From 539019eefa8a97233366eaa05aefc573fdfe0780 Mon Sep 17 00:00:00 2001 From: BuckarooBanzay Date: Thu, 14 Sep 2023 14:09:18 +0200 Subject: [PATCH] ui audit log --- app/geoip.go | 30 +++++++++++++ events/events.go | 2 +- events/log.go | 12 +---- public/js/components/pages/Log.js | 18 +++++++- web/api.go | 13 ++++++ web/chat_command.go | 9 ++++ web/config.go | 9 ++++ web/features.go | 12 +++++ web/filebrowser.go | 74 +++++++++++++++++++++++++------ web/login.go | 35 +++++++++++++++ web/lua.go | 8 ++++ web/maintenance.go | 17 +++++++ web/modmanager.go | 22 +++++++++ web/mtconfig.go | 36 ++++++++++----- web/oauth_app.go | 15 +++++++ web/onboard.go | 8 ++++ web/service_engine.go | 29 ++++++++++++ web/signup.go | 8 ++++ web/skinsdb.go | 14 ++++++ 19 files changed, 334 insertions(+), 37 deletions(-) diff --git a/app/geoip.go b/app/geoip.go index 846e8e29..8919ac30 100644 --- a/app/geoip.go +++ b/app/geoip.go @@ -1,8 +1,11 @@ package app import ( + "mtui/types" "net" + "net/http" "path" + "strings" "github.com/oschwald/geoip2-golang" "github.com/sirupsen/logrus" @@ -66,3 +69,30 @@ func (r *GeoipResolver) Resolve(ipstr string) *GeoipResult { return result } + +func (a *App) ResolveLogGeoIP(l *types.Log, r *http.Request) { + if r == nil { + // nothing to work with + return + } + + fwdfor := r.Header.Get("X-Forwarded-For") + if fwdfor != "" { + // behind reverse proxy + parts := strings.Split(fwdfor, ",") + l.IPAddress = &parts[0] + } else { + // direct access + parts := strings.Split(r.RemoteAddr, ":") + l.IPAddress = &parts[0] + } + + if a.GeoipResolver != nil && l.IPAddress != nil { + geoip := a.GeoipResolver.Resolve(*l.IPAddress) + if geoip != nil { + l.GeoCity = &geoip.City + l.GeoCountry = &geoip.ISOCountry + l.GeoASN = &geoip.ASN + } + } +} diff --git a/events/events.go b/events/events.go index 3ce5720a..b9360fdd 100644 --- a/events/events.go +++ b/events/events.go @@ -8,7 +8,7 @@ import ( func Setup(app *app.App) error { go metricLoop(app, app.Bridge.AddHandler(command.COMMAND_METRICS)) go statsLoop(app.WSEvents, app.Bridge.AddHandler(command.COMMAND_STATS)) - go logLoop(app, app.GeoipResolver, app.Bridge.AddHandler(command.COMMAND_LOG)) + go logLoop(app, app.Bridge.AddHandler(command.COMMAND_LOG)) return nil } diff --git a/events/log.go b/events/log.go index e3a43893..cde00a10 100644 --- a/events/log.go +++ b/events/log.go @@ -8,7 +8,7 @@ import ( "mtui/types" ) -func logLoop(a *app.App, geoipresolver *app.GeoipResolver, ch chan *bridge.CommandResponse) { +func logLoop(a *app.App, ch chan *bridge.CommandResponse) { for cmd := range ch { log := &types.Log{} err := json.Unmarshal(cmd.Data, log) @@ -17,15 +17,7 @@ func logLoop(a *app.App, geoipresolver *app.GeoipResolver, ch chan *bridge.Comma return } - if log.IPAddress != nil { - geoip := geoipresolver.Resolve(*log.IPAddress) - if geoip != nil { - log.GeoCity = &geoip.City - log.GeoCountry = &geoip.ISOCountry - log.GeoASN = &geoip.ASN - } - } - + a.ResolveLogGeoIP(log, nil) err = a.Repos.LogRepository.Insert(log) if err != nil { fmt.Printf("DB error: %s\n", err.Error()) diff --git a/public/js/components/pages/Log.js b/public/js/components/pages/Log.js index 0e9fe883..9fdcc6a7 100644 --- a/public/js/components/pages/Log.js +++ b/public/js/components/pages/Log.js @@ -56,7 +56,21 @@ export default { "logfile-verbose" ]; } else { - return []; + return [ + "login", + "signup", + "skin", + "settings", + "filebrowser", + "maintenance", + "lua", + "chatcommand", + "feature", + "system", + "engine", + "mods", + "oauth" + ]; } } }, @@ -113,6 +127,7 @@ export default { format_time: format_time }, watch: { + "category": "update_count", "event": "update_count", "from": "update_count", "to": "update_count", @@ -134,6 +149,7 @@ export default {
diff --git a/web/api.go b/web/api.go index bb25c3ec..a1954b8b 100644 --- a/web/api.go +++ b/web/api.go @@ -2,7 +2,9 @@ package web import ( "mtui/app" + "mtui/types" "mtui/types/command" + "net/http" ) type Api struct { @@ -22,5 +24,16 @@ func (api *Api) Setup() error { go api.TanSetListener(api.app.Bridge.AddHandler(command.COMMAND_TAN_REMOVE)) go api.StatsEventListener(api.app.Bridge.AddHandler(command.COMMAND_STATS)) + api.CreateUILogEntry(&types.Log{ + Event: "system", + Message: "mtui started", + }, nil) + return nil } + +func (api *Api) CreateUILogEntry(l *types.Log, r *http.Request) { + l.Category = types.CategoryUI + api.app.ResolveLogGeoIP(l, r) + api.app.Repos.LogRepository.Insert(l) +} diff --git a/web/chat_command.go b/web/chat_command.go index 8396d036..994b82b6 100644 --- a/web/chat_command.go +++ b/web/chat_command.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "fmt" "mtui/types" "mtui/types/command" "net/http" @@ -26,4 +27,12 @@ func (a *Api) ExecuteChatcommand(w http.ResponseWriter, r *http.Request, claims resp := &command.ExecuteChatCommandResponse{} err = a.app.Bridge.ExecuteCommand(command.COMMAND_CHATCMD, req, resp, time.Second*5) Send(w, resp, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "chatcommand", + Message: fmt.Sprintf("User '%s' executes the chatcommand: '%s'", claims.Username, req.Command), + }, r) + } diff --git a/web/config.go b/web/config.go index f6c7f0ce..fab3584c 100644 --- a/web/config.go +++ b/web/config.go @@ -2,6 +2,7 @@ package web import ( "bytes" + "fmt" "io" "mtui/types" "net/http" @@ -53,4 +54,12 @@ func (a *Api) SetConfig(w http.ResponseWriter, r *http.Request, c *types.Claims) SendError(w, 500, err.Error()) return } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: c.Username, + Event: "lua", + Message: fmt.Sprintf("User '%s' sets the config '%s' to '%s'", c.Username, key, e.Value), + }, r) + } diff --git a/web/features.go b/web/features.go index 8e72c77f..51b8c2a4 100644 --- a/web/features.go +++ b/web/features.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "fmt" "mtui/app" "mtui/types" "net/http" @@ -44,4 +45,15 @@ func (a *Api) SetFeature(w http.ResponseWriter, r *http.Request, claims *types.C err = a.app.Repos.FeatureRepository.Set(feature) Send(w, feature, err) + + // create log entry + action := "disables" + if feature.Enabled { + action = "enables" + } + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "feature", + Message: fmt.Sprintf("User '%s' %s the feature '%s'", claims.Username, action, feature.Name), + }, r) } diff --git a/web/filebrowser.go b/web/filebrowser.go index d4c52b41..e69076fb 100644 --- a/web/filebrowser.go +++ b/web/filebrowser.go @@ -34,13 +34,13 @@ func (a *Api) get_sanitized_dir(r *http.Request) (string, string, error) { return dir, path.Join(a.app.WorldDir, dir), nil } -func (a *Api) get_sanitized_filename(r *http.Request, query_param string) (string, error) { +func (a *Api) get_sanitized_filename(r *http.Request, query_param string) (string, string, error) { filename := r.URL.Query().Get(query_param) if strings.Contains(filename, "..") { - return "", fmt.Errorf("invalid filename: '%s'", filename) + return "", "", fmt.Errorf("invalid filename: '%s'", filename) } - return path.Join(a.app.WorldDir, filename), nil + return filename, path.Join(a.app.WorldDir, filename), nil } func (a *Api) BrowseFolder(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -92,7 +92,7 @@ func (a *Api) BrowseFolder(w http.ResponseWriter, r *http.Request, claims *types } func (a *Api) DownloadFile(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - filename, err := a.get_sanitized_filename(r, "filename") + rel_filename, filename, err := a.get_sanitized_filename(r, "filename") if err != nil { SendError(w, 500, err.Error()) return @@ -124,11 +124,17 @@ func (a *Api) DownloadFile(w http.ResponseWriter, r *http.Request, claims *types return } - _, err = io.Copy(w, f) + count, err := io.Copy(w, f) if err != nil { SendError(w, 500, err.Error()) return } + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' downloaded the file '%s' with %d bytes", claims.Username, rel_filename, count), + }, r) } func (a *Api) DownloadZip(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -148,6 +154,7 @@ func (a *Api) DownloadZip(w http.ResponseWriter, r *http.Request, claims *types. zw := zip.NewWriter(w) defer zw.Close() + count := int64(0) err = filepath.Walk(absdir, func(filePath string, info os.FileInfo, err error) error { if info.IsDir() { return nil @@ -164,10 +171,11 @@ func (a *Api) DownloadZip(w http.ResponseWriter, r *http.Request, claims *types. if err != nil { return err } - _, err = io.Copy(zipFile, fsFile) + fc, err := io.Copy(zipFile, fsFile) if err != nil { return err } + count += fc return nil }) @@ -175,10 +183,16 @@ func (a *Api) DownloadZip(w http.ResponseWriter, r *http.Request, claims *types. SendError(w, 500, err.Error()) return } + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' downloaded the directory '%s' with %d bytes (uncompressed)", claims.Username, reldir, count), + }, r) } func (a *Api) UploadZip(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - _, absdir, err := a.get_sanitized_dir(r) + reldir, absdir, err := a.get_sanitized_dir(r) if err != nil { SendError(w, 500, err.Error()) return @@ -204,6 +218,7 @@ func (a *Api) UploadZip(w http.ResponseWriter, r *http.Request, claims *types.Cl } defer zr.Close() + count := int64(0) for _, f := range zr.File { targetfile := path.Join(absdir, f.Name) dirname := path.Dir(targetfile) @@ -226,7 +241,8 @@ func (a *Api) UploadZip(w http.ResponseWriter, r *http.Request, claims *types.Cl return } - _, err = io.Copy(targetf, zipfile) + fc, err := io.Copy(targetf, zipfile) + count += fc targetf.Close() zipfile.Close() @@ -235,10 +251,16 @@ func (a *Api) UploadZip(w http.ResponseWriter, r *http.Request, claims *types.Cl return } } + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' uploaded a zip to the directory '%s' with %d bytes (uncompressed)", claims.Username, reldir, count), + }, r) } func (a *Api) Mkdir(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - _, absdir, err := a.get_sanitized_dir(r) + reldir, absdir, err := a.get_sanitized_dir(r) if err != nil { SendError(w, 500, err.Error()) return @@ -246,10 +268,16 @@ func (a *Api) Mkdir(w http.ResponseWriter, r *http.Request, claims *types.Claims err = os.MkdirAll(absdir, 0644) Send(w, true, err) + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' created the directory '%s'", claims.Username, reldir), + }, r) } func (a *Api) UploadFile(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - filename, err := a.get_sanitized_filename(r, "filename") + rel_filename, filename, err := a.get_sanitized_filename(r, "filename") if err != nil { SendError(w, 500, err.Error()) return @@ -262,15 +290,21 @@ func (a *Api) UploadFile(w http.ResponseWriter, r *http.Request, claims *types.C } defer f.Close() - _, err = io.Copy(f, r.Body) + count, err := io.Copy(f, r.Body) if err != nil { SendError(w, 500, err.Error()) return } + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' uploaded the file '%s' with %d bytes (uncompressed)", claims.Username, rel_filename, count), + }, r) } func (a *Api) DeleteFile(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - filename, err := a.get_sanitized_filename(r, "filename") + rel_filename, filename, err := a.get_sanitized_filename(r, "filename") if err != nil { SendError(w, 500, err.Error()) return @@ -278,16 +312,22 @@ func (a *Api) DeleteFile(w http.ResponseWriter, r *http.Request, claims *types.C err = os.RemoveAll(filename) Send(w, true, err) + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' deleted the file '%s'", claims.Username, rel_filename), + }, r) } func (a *Api) RenameFile(w http.ResponseWriter, r *http.Request, claims *types.Claims) { - src, err := a.get_sanitized_filename(r, "src") + rel_src, src, err := a.get_sanitized_filename(r, "src") if err != nil { SendError(w, 500, err.Error()) return } - dst, err := a.get_sanitized_filename(r, "dst") + rel_dst, dst, err := a.get_sanitized_filename(r, "dst") if err != nil { SendError(w, 500, err.Error()) return @@ -295,4 +335,10 @@ func (a *Api) RenameFile(w http.ResponseWriter, r *http.Request, claims *types.C err = os.Rename(src, dst) Send(w, true, err) + + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "filebrowser", + Message: fmt.Sprintf("User '%s' moved the file '%s' to '%s'", claims.Username, rel_src, rel_dst), + }, r) } diff --git a/web/login.go b/web/login.go index 6786537e..d4608baa 100644 --- a/web/login.go +++ b/web/login.go @@ -67,6 +67,12 @@ func (a *Api) GetLogin(w http.ResponseWriter, r *http.Request) { claims, err = a.updateToken(w, *auth_entry.ID, claims.Username) Send(w, claims, err) + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "login", + Message: fmt.Sprintf("User '%s' refreshed session", claims.Username), + }, r) + } else { // maintenance mode, send back existing claims Send(w, claims, nil) @@ -110,6 +116,12 @@ func (a *Api) DoLogin(w http.ResponseWriter, r *http.Request) { } if auth_entry == nil { SendError(w, 404, "user not found") + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: req.Username, + Event: "login", + Message: fmt.Sprintf("User '%s' tried to login and was not found", req.Username), + }, r) return } @@ -135,6 +147,12 @@ func (a *Api) DoLogin(w http.ResponseWriter, r *http.Request) { } if !ok { SendError(w, 401, "unauthorized") + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: req.Username, + Event: "login", + Message: fmt.Sprintf("User '%s' provided wrong password", req.Username), + }, r) return } } @@ -184,11 +202,28 @@ func (a *Api) DoLogin(w http.ResponseWriter, r *http.Request) { if !otp_ok { SendError(w, 403, "otp code wrong") + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: req.Username, + Event: "login", + Message: fmt.Sprintf("User '%s' provided wrong otp code", req.Username), + }, r) return } } } claims, err := a.updateToken(w, *auth_entry.ID, auth_entry.Name) + if err != nil { + SendError(w, 500, fmt.Sprintf("token-update failed: %v", err)) + return + } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "login", + Message: fmt.Sprintf("User '%s' logged in successfully", claims.Username), + }, r) Send(w, claims, err) } diff --git a/web/lua.go b/web/lua.go index f84ed3ef..b8d6eacf 100644 --- a/web/lua.go +++ b/web/lua.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "fmt" "mtui/types" "mtui/types/command" "net/http" @@ -20,4 +21,11 @@ func (a *Api) ExecuteLua(w http.ResponseWriter, r *http.Request, claims *types.C resp := &command.LuaResponse{} err = a.app.Bridge.ExecuteCommand(command.COMMAND_LUA, req, resp, time.Second*5) Send(w, resp, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "lua", + Message: fmt.Sprintf("User '%s' executes the lua-code: '%s'", claims.Username, req.Code), + }, r) } diff --git a/web/maintenance.go b/web/maintenance.go index 4e87ada3..c2515ca5 100644 --- a/web/maintenance.go +++ b/web/maintenance.go @@ -1,6 +1,7 @@ package web import ( + "fmt" "mtui/types" "net/http" @@ -18,6 +19,14 @@ func (a *Api) EnableMaintenanceMode(w http.ResponseWriter, r *http.Request, c *t SendError(w, 500, "already in maintenance mode") } a.app.MaintenanceMode.Store(true) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: c.Username, + Event: "maintenance", + Message: fmt.Sprintf("User '%s' enables the maintenance mode", c.Username), + }, r) + // clear current stats current_stats.Store(nil) // detach database @@ -42,5 +51,13 @@ func (a *Api) DisableMaintenanceMode(w http.ResponseWriter, r *http.Request, c * "err": err, }).Error("Attach database failed") } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: c.Username, + Event: "maintenance", + Message: fmt.Sprintf("User '%s' disabled the maintenance mode", c.Username), + }, r) + Send(w, false, err) } diff --git a/web/modmanager.go b/web/modmanager.go index 40c06aa6..05ee5e4a 100644 --- a/web/modmanager.go +++ b/web/modmanager.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "fmt" "mtui/minetestconfig/depanalyzer" "mtui/types" "net/http" @@ -40,6 +41,13 @@ func (a *Api) UpdateModVersion(w http.ResponseWriter, r *http.Request, claims *t m.Version = version SendJson(w, m) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "mods", + Message: fmt.Sprintf("User '%s' updated the %s '%s' (%s) to version '%s'", claims.Username, m.ModType, m.Name, m.SourceType, m.Version), + }, r) } func (a *Api) CreateMod(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -51,6 +59,13 @@ func (a *Api) CreateMod(w http.ResponseWriter, r *http.Request, claims *types.Cl } Send(w, m, a.app.ModManager.Create(m)) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "mods", + Message: fmt.Sprintf("User '%s' creates the %s '%s' (%s) in version '%s'", claims.Username, m.ModType, m.Name, m.SourceType, m.Version), + }, r) } func (a *Api) DeleteMod(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -71,6 +86,13 @@ func (a *Api) DeleteMod(w http.ResponseWriter, r *http.Request, claims *types.Cl if err != nil { SendError(w, 500, err.Error()) } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "mods", + Message: fmt.Sprintf("User '%s' deletes the %s '%s' (%s)", claims.Username, m.ModType, m.Name, m.SourceType), + }, r) } func (a *Api) ModsCheckUpdates(w http.ResponseWriter, r *http.Request, claims *types.Claims) { diff --git a/web/mtconfig.go b/web/mtconfig.go index 12bf4396..ce782938 100644 --- a/web/mtconfig.go +++ b/web/mtconfig.go @@ -137,18 +137,25 @@ func (a *Api) SetMTConfig(w http.ResponseWriter, r *http.Request, claims *types. return } - if strings.HasPrefix(key, "secure.") { - // skip runtime change for secure settings - Send(w, true, nil) - return - } - st := sts[key] if st == nil { // default to string type st = &minetestconfig.SettingType{Type: "string"} } + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "settings", + Message: fmt.Sprintf("User '%s' changed the setting '%s' of type '%s' to '%s'", claims.Username, key, st.Type, s.Value), + }, r) + + if strings.HasPrefix(key, "secure.") { + // skip runtime change for secure settings + Send(w, true, nil) + return + } + if runtime_set_allowed_types[st.Type] { go func() { // set in engine @@ -191,17 +198,24 @@ func (a *Api) DeleteMTConfig(w http.ResponseWriter, r *http.Request, claims *typ return } + st := sts[key] + if st == nil { + st = &minetestconfig.SettingType{Type: "string"} + } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "settings", + Message: fmt.Sprintf("User '%s' removed the setting '%s' of type '%s'", claims.Username, key, st.Type), + }, r) + if strings.HasPrefix(key, "secure.") { // skip runtime change for secure settings Send(w, true, nil) return } - st := sts[key] - if st == nil { - st = &minetestconfig.SettingType{Type: "string"} - } - if runtime_set_allowed_types[st.Type] { go func() { // remove in engine diff --git a/web/oauth_app.go b/web/oauth_app.go index 201910d5..033bc3c4 100644 --- a/web/oauth_app.go +++ b/web/oauth_app.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "fmt" "mtui/types" "net/http" @@ -29,10 +30,24 @@ func (a *Api) SetOauthApp(w http.ResponseWriter, r *http.Request, claims *types. err = a.app.Repos.OauthAppRepo.Set(app) Send(w, app, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "oauth", + Message: fmt.Sprintf("User '%s' updates the oauth app '%s'", claims.Username, app.ID), + }, r) } func (a *Api) DeleteOauthApp(w http.ResponseWriter, r *http.Request, claims *types.Claims) { vars := mux.Vars(r) err := a.app.Repos.OauthAppRepo.Delete(vars["id"]) Send(w, true, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "oauth", + Message: fmt.Sprintf("User '%s' deletes the oauth app '%s'", claims.Username, vars["id"]), + }, r) } diff --git a/web/onboard.go b/web/onboard.go index 1ddc7e1a..1ab5400e 100644 --- a/web/onboard.go +++ b/web/onboard.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "mtui/auth" + "mtui/types" "net/http" "sync/atomic" @@ -113,4 +114,11 @@ func (a *Api) CreateOnboardUser(w http.ResponseWriter, r *http.Request) { return } } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: obr.Username, + Event: "signup", + Message: fmt.Sprintf("User '%s' signed up successfully as admin", obr.Username), + }, r) } diff --git a/web/service_engine.go b/web/service_engine.go index 7fc65166..9d4ed1c6 100644 --- a/web/service_engine.go +++ b/web/service_engine.go @@ -237,6 +237,14 @@ func (a *Api) CreateEngine(w http.ResponseWriter, r *http.Request, claims *types Running: false, Version: cer.Version, }) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "engine", + Message: fmt.Sprintf("User '%s' created the minetest engine with version '%s'", claims.Username, cer.Version), + }, r) + } func (a *Api) StartEngine(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -259,6 +267,13 @@ func (a *Api) StartEngine(w http.ResponseWriter, r *http.Request, claims *types. ctx := context.Background() err = cli.ContainerStart(ctx, c.ID, dockertypes.ContainerStartOptions{}) Send(w, true, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "engine", + Message: fmt.Sprintf("User '%s' started the minetest engine", claims.Username), + }, r) } func (a *Api) StopEngine(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -285,6 +300,13 @@ func (a *Api) StopEngine(w http.ResponseWriter, r *http.Request, claims *types.C current_stats.Store(nil) Send(w, true, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "engine", + Message: fmt.Sprintf("User '%s' stopped the minetest engine", claims.Username), + }, r) } func (a *Api) RemoveEngine(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -307,6 +329,13 @@ func (a *Api) RemoveEngine(w http.ResponseWriter, r *http.Request, claims *types ctx := context.Background() err = cli.ContainerRemove(ctx, c.ID, dockertypes.ContainerRemoveOptions{}) Send(w, true, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "engine", + Message: fmt.Sprintf("User '%s' removed the minetest engine", claims.Username), + }, r) } type ServiceLogResponse struct { diff --git a/web/signup.go b/web/signup.go index a320d28b..342debdb 100644 --- a/web/signup.go +++ b/web/signup.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "mtui/auth" + "mtui/types" "net/http" "github.com/dchest/captcha" @@ -85,4 +86,11 @@ func (a *Api) Signup(w http.ResponseWriter, r *http.Request) { return } } + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: sr.Username, + Event: "signup", + Message: fmt.Sprintf("User '%s' signed up successfully", sr.Username), + }, r) } diff --git a/web/skinsdb.go b/web/skinsdb.go index 1aed0308..7cf94cbe 100644 --- a/web/skinsdb.go +++ b/web/skinsdb.go @@ -74,6 +74,13 @@ func (a *Api) SetSkin(w http.ResponseWriter, r *http.Request, claims *types.Clai resp := &command.LuaResponse{} err = a.app.Bridge.ExecuteCommand(command.COMMAND_LUA, req, resp, time.Second*5) SendLuaResponse(w, err, resp) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "skin", + Message: fmt.Sprintf("User '%s' uploaded a new skin in slot %d with %d bytes", claims.Username, skin_id, len(b)), + }, r) } func (a *Api) RemoveSkin(w http.ResponseWriter, r *http.Request, claims *types.Claims) { @@ -82,4 +89,11 @@ func (a *Api) RemoveSkin(w http.ResponseWriter, r *http.Request, claims *types.C err := os.Remove(getPlayerSkinFile(a.app.WorldDir, claims.Username, skin_id)) Send(w, true, err) + + // create log entry + a.CreateUILogEntry(&types.Log{ + Username: claims.Username, + Event: "skin", + Message: fmt.Sprintf("User '%s' removed the skin in slot %d", claims.Username, skin_id), + }, r) }