From 64e007631f6535cc088429a5751265acdd8b31c6 Mon Sep 17 00:00:00 2001 From: ppeb Date: Mon, 16 Sep 2024 00:32:34 -0500 Subject: [PATCH] Add /api/clear to drop user from database --- api/clear.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ database/user.go | 14 +++++++++ nas/main.go | 5 ++++ 3 files changed, 94 insertions(+) create mode 100644 api/clear.go diff --git a/api/clear.go b/api/clear.go new file mode 100644 index 0000000..1d4b97a --- /dev/null +++ b/api/clear.go @@ -0,0 +1,75 @@ +package api + +import ( + "encoding/json" + "io" + "net/http" + "strconv" + "wwfc/database" +) + +func HandleClear(w http.ResponseWriter, r *http.Request) { + var user *database.User + var success bool + var err string + var statusCode int + + switch r.Method { + case http.MethodHead: + statusCode = http.StatusOK + case http.MethodPost: + user, success, err, statusCode = handleClearImpl(w, r) + default: + err = "Incorrect request. POST or HEAD only." + statusCode = http.StatusBadRequest + } + + if user == nil { + user = &database.User{} + } + + w.Header().Set("Content-Type", "application/json") + w.Header().Set("Access-Control-Allow-Origin", "*") + + if r.Method == http.MethodHead { + w.WriteHeader(statusCode) + } else { + json, _ := json.Marshal(UserActionResponse{*user, success, err}) + w.Header().Set("Content-Length", strconv.Itoa(len(json))) + w.WriteHeader(statusCode) + w.Write(json) + } +} + +type ClearRequestSpec struct { + Secret string + Pid uint32 +} + +func handleClearImpl(w http.ResponseWriter, r *http.Request) (*database.User, bool, string, int) { + // TODO: Actual authentication rather than a fixed secret + + body, err := io.ReadAll(r.Body) + if err != nil { + return nil, false, "Unable to read request body", http.StatusBadRequest + } + + var req ClearRequestSpec + err = json.Unmarshal(body, &req) + if err != nil { + return nil, false, err.Error(), http.StatusBadRequest + } + + if apiSecret == "" || req.Secret != apiSecret { + return nil, false, "Invalid API secret in request", http.StatusUnauthorized + } + + user, success := database.ClearProfile(pool, ctx, req.Pid) + + if !success { + return nil, false, "Unable to query user data from the database", http.StatusInternalServerError + } + + // Don't return empty JSON, this is placeholder for now. + return &user, true, "", http.StatusOK +} diff --git a/database/user.go b/database/user.go index aba2086..4072a60 100644 --- a/database/user.go +++ b/database/user.go @@ -16,6 +16,7 @@ const ( UpdateUserProfileID = `UPDATE users SET profile_id = $3 WHERE user_id = $1 AND gsbrcd = $2` UpdateUserNGDeviceID = `UPDATE users SET ng_device_id = $2 WHERE profile_id = $1` GetUser = `SELECT user_id, gsbrcd, email, unique_nick, firstname, lastname, open_host, last_ip_address, last_ingamesn FROM users WHERE profile_id = $1` + DeleteUser = `DELETE FROM users WHERE profile_id = $1 RETURNING user_id, gsbrcd, email, unique_nick, firstname, lastname, open_host, last_ip_address, last_ingamesn` DoesUserExist = `SELECT EXISTS(SELECT 1 FROM users WHERE user_id = $1 AND gsbrcd = $2)` IsProfileIDInUse = `SELECT EXISTS(SELECT 1 FROM users WHERE profile_id = $1)` DeleteUserSession = `DELETE FROM sessions WHERE profile_id = $1` @@ -139,6 +140,19 @@ func GetProfile(pool *pgxpool.Pool, ctx context.Context, profileId uint32) (User return user, true } +func ClearProfile(pool *pgxpool.Pool, ctx context.Context, profileId uint32) (User, bool) { + user := User{} + row := pool.QueryRow(ctx, DeleteUser, profileId) + err := row.Scan(&user.UserId, &user.GsbrCode, &user.Email, &user.UniqueNick, &user.FirstName, &user.LastName, &user.OpenHost, &user.LastIPAddress, &user.LastInGameSn) + + if err != nil { + return User{}, false + } + + user.ProfileId = profileId + return user, true +} + func BanUser(pool *pgxpool.Pool, ctx context.Context, profileId uint32, tos bool, length time.Duration, reason string, reasonHidden string, moderator string) bool { _, err := pool.Exec(ctx, UpdateUserBan, profileId, time.Now(), time.Now().Add(length), reason, reasonHidden, moderator, tos) return err == nil diff --git a/nas/main.go b/nas/main.go index 2916c84..8e9c95c 100644 --- a/nas/main.go +++ b/nas/main.go @@ -173,6 +173,11 @@ func handleRequest(w http.ResponseWriter, r *http.Request) { return } + if r.URL.Path == "/api/clear" { + api.HandleClear(w, r) + return + } + logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr)) replyHTTPError(w, 404, "404 Not Found") }