Compare commits
16 commits
Author | SHA1 | Date | |
---|---|---|---|
5da37f6ee7 | |||
d951d5f036 | |||
26faa6789b | |||
274d001fad | |||
e0de8cee09 | |||
4ad2a6e695 | |||
79a1d24c56 | |||
1b4a0c9994 | |||
1a2c461891 | |||
cfead595ad | |||
1329068738 | |||
e8334dca73 | |||
849b87904a | |||
d057453d1d | |||
05cd559e34 | |||
bcb2aaa26d |
6 changed files with 89 additions and 188 deletions
13
build.sh
13
build.sh
|
@ -5,8 +5,19 @@ resourceDir="$path/../../resources/322dc186-04d2-4f69-89b5-403ab643cc1d"
|
|||
rm -rf "$resourceDir" || exit 1
|
||||
rm -rf "$path/../../services/data-tracker.fgs" || exit 1
|
||||
cd "$path" || exit 1
|
||||
printf "\033[1;35mBuilding data-tracker.fgs...\033[0m\n"
|
||||
go build -o "$path/../../services/data-tracker.fgs" --buildmode=plugin -ldflags "-s -w" || exit 1
|
||||
cd "$path/resources/wasm/oauth" || exit 1
|
||||
GOOS=js GOARCH=wasm go build -o "$resourceDir/static/wasm/oauth.wasm" -ldflags "-s -w" || exit 1
|
||||
find -L "$path/resources/wasm" -type f -name "main.go" | while read -r mainGo; do
|
||||
buildDir=$(dirname "$mainGo")
|
||||
baseName=$(basename "$buildDir")
|
||||
printf "\033[1;34m\033[1;33mBuilding WASM object %s...\033[0m\n" "$baseName"
|
||||
(cd "$buildDir" && GOOS=js GOARCH=wasm go build -o "$resourceDir/static/wasm/$(basename "$buildDir").wasm" -ldflags "-s -w") || {
|
||||
printf "\033[1;31mError: %s failed.\033[0m\n" "$mainGo"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
printf "\033[1;34mCopying static files...\033[0m\n"
|
||||
cp -r "$path/resources/static" "$resourceDir/" || exit 1
|
||||
cp -r "$path/resources/templates" "$resourceDir/" || exit 1
|
||||
printf "\033[1;36mdata-tracker.fgs has been built successfully!\033[0m\n"
|
||||
|
|
8
go.mod
8
go.mod
|
@ -1,12 +1,12 @@
|
|||
module git.ailur.dev/ailur/datatracker
|
||||
|
||||
go 1.23.1
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.0
|
||||
git.ailur.dev/ailur/fg-library/v3 v3.6.2
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.2.2
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
)
|
||||
|
||||
require github.com/go-chi/chi/v5 v5.1.0
|
||||
require github.com/go-chi/chi/v5 v5.2.1 // indirect
|
||||
|
|
14
go.sum
14
go.sum
|
@ -1,11 +1,9 @@
|
|||
git.ailur.dev/ailur/fg-library/v2 v2.0.0 h1:NanDV52W+NBu96v/HPDPGqH8NOxLp6MRrRdXLPEsgYw=
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.0/go.mod h1:1jYbWhabGcIwp7CkhHqvRwC8eP+nHv5BrXPe9NX2HE8=
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1 h1:ltPYXf/Om0hnMD8gr1K5bkYrfHqKPSbb0hxa0wtTnZ0=
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1/go.mod h1:1jYbWhabGcIwp7CkhHqvRwC8eP+nHv5BrXPe9NX2HE8=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.0 h1:TT1V4cfka+uUpvV1zU7bc4KXFkgnsI/sIvaZDDxXk+k=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.0/go.mod h1:m4gNSEypfgrUV8bXaR8NLB8zchUM59y0ellV1wp/C+I=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
git.ailur.dev/ailur/fg-library/v3 v3.6.2 h1:PNJKxpvbel2iDeB9+/rpYRyMoim6JjRHOXPYFYky7Ng=
|
||||
git.ailur.dev/ailur/fg-library/v3 v3.6.2/go.mod h1:ArNsafpqES2JuxQM5aM+bNe0FwHLIsL6pbjpiWvDwGs=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.2.2 h1:JbclmxGSoL+ByGZAl0W6PqWRoyBBGTrKrizWDJ7rdI0=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.2.2/go.mod h1:stxiTyMv3Fa7GzpyLbBUh3ahlb7110p0NnCl8ZTjwBs=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
|
233
main.go
233
main.go
|
@ -2,16 +2,14 @@ package main
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"crypto/ed25519"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
library "git.ailur.dev/ailur/fg-library/v2"
|
||||
library "git.ailur.dev/ailur/fg-library/v3"
|
||||
authLibrary "git.ailur.dev/ailur/fg-nucleus-library"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"html/template"
|
||||
|
@ -24,6 +22,7 @@ var ServiceInformation = library.Service{
|
|||
Permissions: library.Permissions{
|
||||
Authenticate: true, // This service does require authentication
|
||||
Database: true, // This service does require database access
|
||||
Router: true, // This service does require a router
|
||||
BlobStorage: false, // This service does not require blob storage
|
||||
InterServiceCommunication: true, // This service does require inter-service communication
|
||||
Resources: true, // This service does require its HTTP templates and static files
|
||||
|
@ -31,18 +30,16 @@ var ServiceInformation = library.Service{
|
|||
ServiceID: uuid.MustParse("322dc186-04d2-4f69-89b5-403ab643cc1d"),
|
||||
}
|
||||
|
||||
func logFunc(message string, messageType uint64, information library.ServiceInitializationInformation) {
|
||||
var (
|
||||
loggerService = uuid.MustParse("00000000-0000-0000-0000-000000000002")
|
||||
)
|
||||
|
||||
func logFunc(message string, messageType library.MessageCode, information *library.ServiceInitializationInformation) {
|
||||
// Log the message to the logger service
|
||||
information.Outbox <- library.InterServiceMessage{
|
||||
ServiceID: ServiceInformation.ServiceID,
|
||||
ForServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), // Logger service
|
||||
MessageType: messageType,
|
||||
SentAt: time.Now(),
|
||||
Message: message,
|
||||
}
|
||||
information.SendISMessage(loggerService, messageType, message)
|
||||
}
|
||||
|
||||
func renderTemplate(statusCode int, w http.ResponseWriter, data map[string]interface{}, templatePath string, information library.ServiceInitializationInformation) {
|
||||
func renderTemplate(statusCode int, w http.ResponseWriter, data map[string]interface{}, templatePath string, information *library.ServiceInitializationInformation) {
|
||||
var err error
|
||||
var requestedTemplate *template.Template
|
||||
// Output ls of the resource directory
|
||||
|
@ -60,7 +57,7 @@ func renderTemplate(statusCode int, w http.ResponseWriter, data map[string]inter
|
|||
}
|
||||
}
|
||||
|
||||
func renderString(statusCode int, w http.ResponseWriter, data string, information library.ServiceInitializationInformation) {
|
||||
func renderString(statusCode int, w http.ResponseWriter, data string, information *library.ServiceInitializationInformation) {
|
||||
w.WriteHeader(statusCode)
|
||||
_, err := w.Write([]byte(data))
|
||||
if err != nil {
|
||||
|
@ -68,7 +65,7 @@ func renderString(statusCode int, w http.ResponseWriter, data string, informatio
|
|||
}
|
||||
}
|
||||
|
||||
func renderJSON(statusCode int, w http.ResponseWriter, data map[string]interface{}, information library.ServiceInitializationInformation) {
|
||||
func renderJSON(statusCode int, w http.ResponseWriter, data map[string]interface{}, information *library.ServiceInitializationInformation) {
|
||||
w.WriteHeader(statusCode)
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
|
@ -105,6 +102,10 @@ func getUsername(token string, oauthHostName string, publicKey ed25519.PublicKey
|
|||
Sub string `json:"sub"`
|
||||
}
|
||||
request, err := http.NewRequest("GET", oauthHostName+"/api/oauth/userinfo", nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
request.Header.Set("Authorization", "Bearer "+token)
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
|
@ -161,174 +162,66 @@ func verifyJwt(token string, publicKey ed25519.PublicKey, conn library.Database)
|
|||
return claims, true
|
||||
}
|
||||
|
||||
func Main(information library.ServiceInitializationInformation) *chi.Mux {
|
||||
func Main(information *library.ServiceInitializationInformation) {
|
||||
var conn library.Database
|
||||
hostName := information.Configuration["hostName"].(string)
|
||||
|
||||
go information.StartISProcessor()
|
||||
|
||||
// Initiate a connection to the database
|
||||
// Call service ID 1 to get the database connection information
|
||||
information.Outbox <- library.InterServiceMessage{
|
||||
ServiceID: ServiceInformation.ServiceID,
|
||||
ForServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), // Service initialization service
|
||||
MessageType: 1, // Request connection information
|
||||
SentAt: time.Now(),
|
||||
Message: nil,
|
||||
}
|
||||
|
||||
// Wait for the response
|
||||
response := <-information.Inbox
|
||||
if response.MessageType == 2 {
|
||||
// This is the connection information
|
||||
// Set up the database connection
|
||||
conn = response.Message.(library.Database)
|
||||
if conn.DBType == library.Sqlite {
|
||||
// Create the RFCs table
|
||||
_, err := conn.DB.Exec("CREATE TABLE IF NOT EXISTS rfc (id INTEGER NOT NULL, year INTEGER NOT NULL, name TEXT NOT NULL, content TEXT NOT NULL, version TEXT NOT NULL, creator BLOB NOT NULL, UNIQUE(id, year))")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the users table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS users (id BLOB NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the comments table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS comments (id BLOB NOT NULL, rfcId INTEGER NOT NULL, rfcYear INTEGER NOT NULL, content TEXT NOT NULL, creator BLOB NOT NULL, creatorName TEXT NOT NULL, created INTEGER NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
} else {
|
||||
// Create the RFCs table
|
||||
_, err := conn.DB.Exec("CREATE TABLE IF NOT EXISTS rfc (id SERIAL PRIMARY KEY, year INTEGER NOT NULL, name TEXT NOT NULL, content TEXT NOT NULL, version TEXT NOT NULL, creator BYTEA NOT NULL, UNIQUE(id, year))")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the users table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS users (id BYTEA NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the comments table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS comments (id BYTEA NOT NULL, rfcId INTEGER NOT NULL, rfcYear INTEGER NOT NULL, content TEXT NOT NULL, creator BYTEA NOT NULL, creatorName TEXT NOT NULL, created INTEGER NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is an error message
|
||||
// Log the error message to the logger service
|
||||
logFunc(response.Message.(error).Error(), 3, information)
|
||||
}
|
||||
|
||||
// Ask the authentication service for the public key
|
||||
information.Outbox <- library.InterServiceMessage{
|
||||
ServiceID: ServiceInformation.ServiceID,
|
||||
ForServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), // Authentication service
|
||||
MessageType: 2, // Request public key
|
||||
SentAt: time.Now(),
|
||||
Message: nil,
|
||||
}
|
||||
|
||||
var publicKey ed25519.PublicKey = nil
|
||||
|
||||
// 3 second timeout
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
if publicKey == nil {
|
||||
logFunc("Timeout while waiting for the public key from the authentication service", 3, information)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the response
|
||||
response = <-information.Inbox
|
||||
if response.MessageType == 2 {
|
||||
// This is the public key
|
||||
publicKey = response.Message.(ed25519.PublicKey)
|
||||
} else {
|
||||
// This is an error message
|
||||
// Log the error message to the logger service
|
||||
logFunc(response.Message.(error).Error(), 3, information)
|
||||
}
|
||||
|
||||
// Ask the authentication service for the OAuth host name
|
||||
information.Outbox <- library.InterServiceMessage{
|
||||
ServiceID: ServiceInformation.ServiceID,
|
||||
ForServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), // Authentication service
|
||||
MessageType: 0, // Request OAuth host name
|
||||
SentAt: time.Now(),
|
||||
Message: nil,
|
||||
}
|
||||
|
||||
var oauthHostName string
|
||||
|
||||
// 3 second timeout
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
if oauthHostName == "" {
|
||||
logFunc("Timeout while waiting for the OAuth host name from the authentication service", 3, information)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the response
|
||||
response = <-information.Inbox
|
||||
if response.MessageType == 0 {
|
||||
// This is the OAuth host name
|
||||
oauthHostName = response.Message.(string)
|
||||
} else {
|
||||
// This is an error message
|
||||
// Log the error message to the logger service
|
||||
logFunc(response.Message.(error).Error(), 3, information)
|
||||
}
|
||||
|
||||
// Ask the authentication service to create a new OAuth2 client
|
||||
urlPath, err := url.JoinPath(hostName, "/oauth")
|
||||
conn, err := information.GetDatabase()
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
return
|
||||
}
|
||||
|
||||
information.Outbox <- library.InterServiceMessage{
|
||||
ServiceID: ServiceInformation.ServiceID,
|
||||
ForServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000004"), // Authentication service
|
||||
MessageType: 1, // Create OAuth2 client
|
||||
SentAt: time.Now(),
|
||||
Message: authLibrary.OAuthInformation{
|
||||
Name: "Data Tracker",
|
||||
RedirectUri: urlPath,
|
||||
KeyShareUri: "",
|
||||
Scopes: []string{"openid"},
|
||||
},
|
||||
}
|
||||
|
||||
oauthResponse := authLibrary.OAuthResponse{}
|
||||
|
||||
// 3 second timeout
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
if oauthResponse == (authLibrary.OAuthResponse{}) {
|
||||
logFunc("Timeout while waiting for the OAuth response from the authentication service", 3, information)
|
||||
if conn.DBType == library.Sqlite {
|
||||
// Create the RFCs table
|
||||
_, err := conn.DB.Exec("CREATE TABLE IF NOT EXISTS rfc (id INTEGER NOT NULL, year INTEGER NOT NULL, name TEXT NOT NULL, content TEXT NOT NULL, version TEXT NOT NULL, creator BLOB NOT NULL, UNIQUE(id, year))")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
}()
|
||||
// Create the users table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS users (id BLOB NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the comments table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS comments (id BLOB NOT NULL, rfcId INTEGER NOT NULL, rfcYear INTEGER NOT NULL, content TEXT NOT NULL, creator BLOB NOT NULL, creatorName TEXT NOT NULL, created INTEGER NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
} else {
|
||||
// Create the RFCs table
|
||||
_, err := conn.DB.Exec("CREATE TABLE IF NOT EXISTS rfc (id SERIAL PRIMARY KEY, year INTEGER NOT NULL, name TEXT NOT NULL, content TEXT NOT NULL, version TEXT NOT NULL, creator BYTEA NOT NULL, UNIQUE(id, year))")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the users table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS users (id BYTEA NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
// Create the comments table
|
||||
_, err = conn.DB.Exec("CREATE TABLE IF NOT EXISTS comments (id BYTEA NOT NULL, rfcId INTEGER NOT NULL, rfcYear INTEGER NOT NULL, content TEXT NOT NULL, creator BYTEA NOT NULL, creatorName TEXT NOT NULL, created INTEGER NOT NULL)")
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the response
|
||||
response = <-information.Inbox
|
||||
switch response.MessageType {
|
||||
case 0:
|
||||
// Success, set the OAuth response
|
||||
oauthResponse = response.Message.(authLibrary.OAuthResponse)
|
||||
logFunc("Initialized with App ID: "+oauthResponse.AppID, 0, information)
|
||||
case 1:
|
||||
// An error which is their fault
|
||||
logFunc(response.Message.(error).Error(), 3, information)
|
||||
case 2:
|
||||
// An error which is our fault
|
||||
logFunc(response.Message.(error).Error(), 3, information)
|
||||
default:
|
||||
// An unknown error
|
||||
logFunc("Unknown error", 3, information)
|
||||
// Initialize the OAuth
|
||||
oauthResponse, publicKey, oauthHostName, err := authLibrary.InitializeOAuth(authLibrary.OAuthInformation{
|
||||
Name: "datatracker",
|
||||
RedirectUri: hostName + "/oauth",
|
||||
Scopes: []string{"openid"},
|
||||
}, information)
|
||||
if err != nil {
|
||||
logFunc(err.Error(), 3, information)
|
||||
return
|
||||
}
|
||||
|
||||
// Set up the router
|
||||
router := chi.NewRouter()
|
||||
router := information.Router
|
||||
|
||||
// Set up the static routes
|
||||
staticDir, err := fs.Sub(information.ResourceDir, "static")
|
||||
|
@ -642,6 +535,4 @@ func Main(information library.ServiceInitializationInformation) *chi.Mux {
|
|||
"AuthorizationUri": oauthHostName,
|
||||
}, "oauth.html", information)
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
year: year,
|
||||
id: id,
|
||||
year: parseInt(year),
|
||||
id: parseInt(id),
|
||||
token: localStorage.getItem("SECRET-token")
|
||||
})
|
||||
}).then(function(response) {
|
||||
|
|
|
@ -41,9 +41,7 @@ func randomChars(length int) (string, error) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
// Clear local storage
|
||||
localStorage := js.Global().Get("localStorage")
|
||||
localStorage.Call("clear")
|
||||
|
||||
statusBox := js.Global().Get("document").Call("getElementById", "statusBox")
|
||||
tryAgain := js.Global().Get("document").Call("getElementById", "tryAgain")
|
||||
|
@ -175,6 +173,9 @@ func main() {
|
|||
tryAgain.Set("style", "")
|
||||
}
|
||||
} else {
|
||||
// Clear local storage
|
||||
localStorage.Call("clear")
|
||||
|
||||
// Start the authorization process
|
||||
verifier, err := randomChars(128)
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Reference in a new issue