Made the nucleus apps not have any special loading process over others except from loading first, fixed clientKeyShare interpreting the token wrongly

Signed-off-by: Arzumify <jliwin98@danwin1210.de>
This commit is contained in:
Tracker-Friendly 2024-10-04 18:30:17 +01:00
parent 7c47df8587
commit 018cb6e74b
2 changed files with 134 additions and 206 deletions

146
main.go
View File

@ -10,6 +10,7 @@ import (
"os" "os"
"plugin" "plugin"
"sort" "sort"
"strings"
"sync" "sync"
"time" "time"
@ -201,16 +202,17 @@ func processInterServiceMessage(channel chan library.InterServiceMessage, config
// Logger service // Logger service
service, ok := services[message.ServiceID] service, ok := services[message.ServiceID]
if ok { if ok {
if message.MessageType == 0 { switch message.MessageType {
case 0:
// Log message // Log message
slog.Info(service.Name + " says: " + message.Message.(string)) slog.Info(service.Name + " says: " + message.Message.(string))
} else if message.MessageType == 1 { case 1:
// Warn message // Warn message
slog.Warn(service.Name + " warns: " + message.Message.(string)) slog.Warn(service.Name + " warns: " + message.Message.(string))
} else if message.MessageType == 2 { case 2:
// Error message // Error message
slog.Error(service.Name + " complains: " + message.Message.(string)) slog.Error(service.Name + " complains: " + message.Message.(string))
} else { case 3:
// Fatal message // Fatal message
slog.Error(service.Name + "'s dying wish: " + message.Message.(string)) slog.Error(service.Name + "'s dying wish: " + message.Message.(string))
os.Exit(1) os.Exit(1)
@ -490,117 +492,26 @@ func main() {
// These are not dynamically loaded, as they are integral to the system functioning // These are not dynamically loaded, as they are integral to the system functioning
go processInterServiceMessage(globalOutbox, config) go processInterServiceMessage(globalOutbox, config)
// Initialize the storage service // Initialize all the services
// The storage service does not need a subdomain
// Since it is a core service, always allocate it the service ID 3
// Load it from the services directory
storagePlugin, err := plugin.Open(config.Global.ServiceDirectory + "/storage.fgs")
if err != nil {
slog.Error("Could not load blob storage service: ", err)
os.Exit(1)
}
// Load up the service information
storageServiceInformation, err := storagePlugin.Lookup("ServiceInformation")
if err != nil {
slog.Error("Blob storage service lacks necessary information: ", err)
os.Exit(1)
}
services[uuid.MustParse("00000000-0000-0000-0000-000000000003")] = *storageServiceInformation.(*library.Service)
// Load up the main function
storageMain, err := storagePlugin.Lookup("Main")
if err != nil {
slog.Error("Blob storage service lacks necessary main function: ", err)
os.Exit(1)
}
// Initialize the storage service
var storageInbox = make(chan library.InterServiceMessage)
activeServices[uuid.MustParse("00000000-0000-0000-0000-000000000003")] = ActiveService{
ServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000003"),
Inbox: storageInbox,
ActivationConfirmed: false,
}
storageMain.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{
Domain: "",
Configuration: config.Services["storage"].(map[string]interface{}),
Outbox: globalOutbox,
Inbox: storageInbox,
})
// Initialize the authentication service
// The authentication service does not need a subdomain
// Since it is a core service, always allocate it the service ID 4
// Load it from the services directory
authPlugin, err := plugin.Open(config.Global.ServiceDirectory + "/auth.fgs")
if err != nil {
slog.Error("Could not load authentication service: ", err)
os.Exit(1)
}
// Load up the service information
authServiceInformation, err := authPlugin.Lookup("ServiceInformation")
if err != nil {
slog.Error("Authentication service lacks necessary information: ", err)
os.Exit(1)
}
services[uuid.MustParse("00000000-0000-0000-0000-000000000004")] = *authServiceInformation.(*library.Service)
// Load up the main function
authMain, err := authPlugin.Lookup("Main")
if err != nil {
slog.Error("Authentication service lacks necessary main function: ", err)
os.Exit(1)
}
// Initialize the authentication service
var authInbox = make(chan library.InterServiceMessage)
lock.Lock()
activeServices[uuid.MustParse("00000000-0000-0000-0000-000000000004")] = ActiveService{
ServiceID: uuid.MustParse("00000000-0000-0000-0000-000000000004"),
Inbox: authInbox,
ActivationConfirmed: false,
}
lock.Unlock()
// Check if they want a subdomain
var authRouter *chi.Mux
if config.Services["auth"].(map[string]interface{})["subdomain"] != nil {
subdomainRouter := chi.NewRouter()
router.Use(middleware.RouteHeaders().
Route("Host", config.Services["auth"].(map[string]interface{})["subdomain"].(string), middleware.New(subdomainRouter)).
Handler)
authRouter = subdomainRouter
} else {
authRouter = router
}
authMain.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{
Domain: "",
Configuration: config.Services["auth"].(map[string]interface{}),
Outbox: globalOutbox,
Inbox: authInbox,
ResourceDir: os.DirFS(filepath.Join(config.Global.ResourceDirectory, "00000000-0000-0000-0000-000000000004")),
Router: authRouter,
})
// Initialize all custom services
plugins := make(map[time.Time]string) plugins := make(map[time.Time]string)
err = filepath.Walk(config.Global.ServiceDirectory, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(config.Global.ServiceDirectory, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if info.IsDir() || filepath.Ext(path) != ".fgs" || filepath.Base(path) == "auth.fgs" || filepath.Base(path) == "storage.fgs" { if info.IsDir() || filepath.Ext(path) != ".fgs" {
return nil return nil
} }
// Add the plugin to the list of plugins // Add the plugin to the list of plugins
if info.Name() == "storage.fgs" {
plugins[time.Unix(0, 0)] = path
return nil
} else if info.Name() == "auth.fgs" {
plugins[time.Unix(0, 1)] = path
return nil
}
plugins[info.ModTime()] = path plugins[info.ModTime()] = path
return nil return nil
@ -645,6 +556,11 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// Add the service to the services map
lock.Lock()
services[serviceInformation.(*library.Service).ServiceID] = *serviceInformation.(*library.Service)
lock.Unlock()
// Initialize the service // Initialize the service
var inbox = make(chan library.InterServiceMessage) var inbox = make(chan library.InterServiceMessage)
lock.Lock() lock.Lock()
@ -657,21 +573,28 @@ func main() {
// Check if they want a subdomain // Check if they want a subdomain
var finalRouter *chi.Mux var finalRouter *chi.Mux
if config.Services[serviceInformation.(*library.Service).Name].(map[string]interface{})["subdomain"] != nil { serviceConfig, ok := config.Services[strings.ToLower(serviceInformation.(*library.Service).Name)]
if !ok {
slog.Error("Service configuration not found for service: ", serviceInformation.(*library.Service).Name)
os.Exit(1)
}
if serviceConfig.(map[string]interface{})["subdomain"] != nil {
subdomainRouter := chi.NewRouter() subdomainRouter := chi.NewRouter()
router.Use(middleware.RouteHeaders(). router.Use(middleware.RouteHeaders().
Route("Host", config.Services["auth"].(map[string]interface{})["subdomain"].(string), middleware.New(subdomainRouter)). Route("Host", config.Services[strings.ToLower(serviceInformation.(*library.Service).Name)].(map[string]interface{})["subdomain"].(string), middleware.New(subdomainRouter)).
Handler) Handler)
finalRouter = subdomainRouter finalRouter = subdomainRouter
} else { } else {
finalRouter = router finalRouter = router
} }
slog.Info("Activating service " + serviceInformation.(*library.Service).Name + " with ID " + serviceInformation.(*library.Service).ServiceID.String())
// Check if they want a resource directory // Check if they want a resource directory
if serviceInformation.(*library.Service).Permissions.Resources { if serviceInformation.(*library.Service).Permissions.Resources {
main.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{ main.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{
Domain: serviceInformation.(*library.Service).Name, Domain: serviceInformation.(*library.Service).Name,
Configuration: config.Services[serviceInformation.(*library.Service).Name].(map[string]interface{}), Configuration: config.Services[strings.ToLower(serviceInformation.(*library.Service).Name)].(map[string]interface{}),
Outbox: globalOutbox, Outbox: globalOutbox,
Inbox: inbox, Inbox: inbox,
ResourceDir: os.DirFS(filepath.Join(config.Global.ResourceDirectory, serviceInformation.(*library.Service).ServiceID.String())), ResourceDir: os.DirFS(filepath.Join(config.Global.ResourceDirectory, serviceInformation.(*library.Service).ServiceID.String())),
@ -680,12 +603,15 @@ func main() {
} else { } else {
main.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{ main.(func(library.ServiceInitializationInformation))(library.ServiceInitializationInformation{
Domain: serviceInformation.(*library.Service).Name, Domain: serviceInformation.(*library.Service).Name,
Configuration: config.Services[serviceInformation.(*library.Service).Name].(map[string]interface{}), Configuration: config.Services[strings.ToLower(serviceInformation.(*library.Service).Name)].(map[string]interface{}),
Outbox: globalOutbox, Outbox: globalOutbox,
Inbox: inbox, Inbox: inbox,
Router: finalRouter, Router: finalRouter,
}) })
} }
// Log the service activation
slog.Info("Service " + serviceInformation.(*library.Service).Name + " activated with ID " + serviceInformation.(*library.Service).ServiceID.String())
} }
// Start the server // Start the server

View File

@ -421,13 +421,13 @@ func Main(information library.ServiceInitializationInformation) {
} }
}(r.Body) }(r.Body)
// Parse the JWT from the query string // Parse the JWT from the query string
if r.URL.Query().Get("token") == "" { if r.URL.Query().Get("accessToken") == "" {
renderString(400, w, "No token provided", information) renderString(400, w, "No token provided", information)
return return
} }
// Verify the JWT // Verify the JWT
_, claims, ok := verifyJwt(strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer "), publicKey, mem) _, claims, ok := verifyJwt(r.URL.Query().Get("accessToken"), publicKey, mem)
if !ok { if !ok {
renderString(401, w, "Invalid token", information) renderString(401, w, "Invalid token", information)
return return
@ -1681,67 +1681,55 @@ func Main(information library.ServiceInitializationInformation) {
// Wait for a message // Wait for a message
message := <-information.Inbox message := <-information.Inbox
// Check the message type if message.ServiceID != uuid.MustParse("00000000-0000-0000-0000-000000000001") {
switch message.MessageType { // Check the message type
case 0: switch message.MessageType {
// A service would like to know our hostname case 0:
// Send it to them // A service would like to know our hostname
information.Outbox <- library.InterServiceMessage{ // Send it to them
MessageType: 0,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: hostName,
SentAt: time.Now(),
}
case 1:
// A service would like to register a new OAuth entry
// Generate a new secret
// It must be able to be sent via JSON, so we can't have pure-binary data
secret, err := randomChars(512)
if err != nil {
information.Outbox <- library.InterServiceMessage{ information.Outbox <- library.InterServiceMessage{
MessageType: 1, MessageType: 0,
ServiceID: ServiceInformation.ServiceID, ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID, ForServiceID: message.ServiceID,
Message: "36", Message: hostName,
SentAt: time.Now(), SentAt: time.Now(),
} }
logFunc(err.Error(), 2, information) case 1:
return // A service would like to register a new OAuth entry
} // Generate a new secret
// It must be able to be sent via JSON, so we can't have pure-binary data
// Generate a new appId secret, err := randomChars(512)
// It must be able to be sent via JSON, so we can't have pure-binary data if err != nil {
appId, err := randomChars(32)
if err != nil {
information.Outbox <- library.InterServiceMessage{
MessageType: 1,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: "37",
SentAt: time.Now(),
}
logFunc(err.Error(), 2, information)
return
}
// Validate the scopes
var clientKeyShare bool
for _, scope := range message.Message.(authLibrary.OAuthInformation).Scopes {
if scope != "openid" && scope != "clientKeyShare" {
information.Outbox <- library.InterServiceMessage{ information.Outbox <- library.InterServiceMessage{
MessageType: 2, MessageType: 1,
ServiceID: ServiceInformation.ServiceID, ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID, ForServiceID: message.ServiceID,
Message: "Invalid scope", Message: "36",
SentAt: time.Now(), SentAt: time.Now(),
} }
logFunc(err.Error(), 2, information)
return return
} else { }
if scope == "clientKeyShare" {
clientKeyShare = true // Generate a new appId
} else if scope != "openid" { // It must be able to be sent via JSON, so we can't have pure-binary data
logFunc("An impossible logic error has occurred, please move away from radiation or use ECC RAM", 1, information) appId, err := randomChars(32)
if err != nil {
information.Outbox <- library.InterServiceMessage{
MessageType: 1,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: "37",
SentAt: time.Now(),
}
logFunc(err.Error(), 2, information)
return
}
// Validate the scopes
var clientKeyShare bool
for _, scope := range message.Message.(authLibrary.OAuthInformation).Scopes {
if scope != "openid" && scope != "clientKeyShare" {
information.Outbox <- library.InterServiceMessage{ information.Outbox <- library.InterServiceMessage{
MessageType: 2, MessageType: 2,
ServiceID: ServiceInformation.ServiceID, ServiceID: ServiceInformation.ServiceID,
@ -1750,62 +1738,76 @@ func Main(information library.ServiceInitializationInformation) {
SentAt: time.Now(), SentAt: time.Now(),
} }
return return
} else {
if scope == "clientKeyShare" {
clientKeyShare = true
} else if scope != "openid" {
logFunc("An impossible logic error has occurred, please move away from radiation or use ECC RAM", 1, information)
information.Outbox <- library.InterServiceMessage{
MessageType: 2,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: "Invalid scope",
SentAt: time.Now(),
}
return
}
} }
} }
}
// Marshal the scopes // Marshal the scopes
scopes, err := json.Marshal(message.Message.(authLibrary.OAuthInformation).Scopes) scopes, err := json.Marshal(message.Message.(authLibrary.OAuthInformation).Scopes)
if err != nil { if err != nil {
information.Outbox <- library.InterServiceMessage{
MessageType: 1,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: "38",
SentAt: time.Now(),
}
logFunc(err.Error(), 2, information)
return
}
// Insert the oauth entry
if clientKeyShare {
_, err = conn.Exec("INSERT INTO oauth (appId, secret, creator, name, redirectUri, scopes, keyShareUri) VALUES (?, ?, ?, ?, ?, ?, ?)", appId, secret, serviceIDBytes, message.Message.(authLibrary.OAuthInformation).Name, message.Message.(authLibrary.OAuthInformation).RedirectUri, scopes, message.Message.(authLibrary.OAuthInformation).KeyShareUri)
} else {
_, err = conn.Exec("INSERT INTO oauth (appId, secret, creator, name, redirectUri, scopes) VALUES (?, ?, ?, ?, ?, ?)", appId, secret, serviceIDBytes, message.Message.(authLibrary.OAuthInformation).Name, message.Message.(authLibrary.OAuthInformation).RedirectUri, scopes)
}
if err != nil {
information.Outbox <- library.InterServiceMessage{
MessageType: 1,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: "39",
SentAt: time.Now(),
}
logFunc(err.Error(), 2, information)
return
}
// Return the appId and secret
information.Outbox <- library.InterServiceMessage{ information.Outbox <- library.InterServiceMessage{
MessageType: 1, MessageType: 0,
ServiceID: ServiceInformation.ServiceID, ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID, ForServiceID: message.ServiceID,
Message: "38", Message: authLibrary.OAuthResponse{
SentAt: time.Now(), AppID: appId,
SecretKey: secret,
},
SentAt: time.Now(),
} }
logFunc(err.Error(), 2, information) case 2:
return // A service would like to have the public key
} // Send it to them
// Insert the oauth entry
if clientKeyShare {
_, err = conn.Exec("INSERT INTO oauth (appId, secret, creator, name, redirectUri, scopes, keyShareUri) VALUES (?, ?, ?, ?, ?, ?, ?)", appId, secret, serviceIDBytes, message.Message.(authLibrary.OAuthInformation).Name, message.Message.(authLibrary.OAuthInformation).RedirectUri, scopes, message.Message.(authLibrary.OAuthInformation).KeyShareUri)
} else {
_, err = conn.Exec("INSERT INTO oauth (appId, secret, creator, name, redirectUri, scopes) VALUES (?, ?, ?, ?, ?, ?)", appId, secret, serviceIDBytes, message.Message.(authLibrary.OAuthInformation).Name, message.Message.(authLibrary.OAuthInformation).RedirectUri, scopes)
}
if err != nil {
information.Outbox <- library.InterServiceMessage{ information.Outbox <- library.InterServiceMessage{
MessageType: 1, MessageType: 2,
ServiceID: ServiceInformation.ServiceID, ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID, ForServiceID: message.ServiceID,
Message: "39", Message: publicKey,
SentAt: time.Now(), SentAt: time.Now(),
} }
logFunc(err.Error(), 2, information)
return
}
// Return the appId and secret
information.Outbox <- library.InterServiceMessage{
MessageType: 0,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: authLibrary.OAuthResponse{
AppID: appId,
SecretKey: secret,
},
SentAt: time.Now(),
}
case 2:
// A service would like to have the public key
// Send it to them
information.Outbox <- library.InterServiceMessage{
MessageType: 2,
ServiceID: ServiceInformation.ServiceID,
ForServiceID: message.ServiceID,
Message: publicKey,
SentAt: time.Now(),
} }
} }
} }