Admin panel upgrade server updates (#54)

* Changes for testing

* Updating server code to allow unlinking discord IDs as needed

* Fixed some debug issues commented out code

* Updating server to allow updated admin panel functionality

* Updated some commentted out code

* Updated missed /

* Updated to allow for a single query to the db with multiple columns, and a conversion to allow string outputs instead of sql.NullStrings

* Deleted .bak files and .vs folder as per Walker's discord message

* Added logic to check server to make sure usename exists for discord linking and unlinking

* Changes to allow linking and unlinking of google Id from DB

* Removed .vs folder

* Reverted dev code

* PR comments

* Updates from Pancake's comments
pull/50/merge
Opaque02 4 weeks ago committed by GitHub
parent b2aa37b2ef
commit 430496941c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

2
.gitignore vendored

@ -14,3 +14,5 @@ secret.key
*.ipr *.ipr
*.iws *.iws
.vscode/launch.json .vscode/launch.json
/.vs

@ -68,7 +68,11 @@ func Init(mux *http.ServeMux) error {
mux.HandleFunc("/auth/{provider}/logout", handleProviderLogout) mux.HandleFunc("/auth/{provider}/logout", handleProviderLogout)
// admin // admin
mux.HandleFunc("POST /admin/account/discord-link", handleAdminDiscordLink) mux.HandleFunc("POST /admin/account/discordLink", handleAdminDiscordLink)
mux.HandleFunc("POST /admin/account/discordUnlink", handleAdminDiscordUnlink)
mux.HandleFunc("POST /admin/account/googleLink", handleAdminGoogleLink)
mux.HandleFunc("POST /admin/account/googleUnlink", handleAdminGoogleUnlink)
mux.HandleFunc("GET /admin/account/adminSearch", handleAdminSearch)
return nil return nil
} }

@ -693,13 +693,257 @@ func handleAdminDiscordLink(w http.ResponseWriter, r *http.Request) {
return return
} }
err = db.AddDiscordIdByUsername(r.Form.Get("discordId"), r.Form.Get("username")) username := r.Form.Get("username")
discordId := r.Form.Get("discordId")
// this does a quick call to make sure the username exists on the server before allowing the rest of the code to run
// this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server
_, err = db.CheckUsernameExists(username)
if err != nil {
httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound)
return
}
userUuid, err := db.FetchUUIDFromUsername(username)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
err = db.AddDiscordIdByUUID(discordId, userUuid)
if err != nil { if err != nil {
httpError(w, r, err, http.StatusInternalServerError) httpError(w, r, err, http.StatusInternalServerError)
return return
} }
log.Printf("%s: %s added discord id %s to username %s", r.URL.Path, userDiscordId, r.Form.Get("discordId"), r.Form.Get("username")) log.Printf("%s: %s added discord id %s to username %s", r.URL.Path, userDiscordId, discordId, username)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func handleAdminDiscordUnlink(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest)
return
}
uuid, err := uuidFromRequest(r)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
userDiscordId, err := db.FetchDiscordIdByUUID(uuid)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID)
if !hasRole || err != nil {
httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden)
return
}
username := r.Form.Get("username")
discordId := r.Form.Get("discordId")
switch {
case username != "":
log.Printf("Username given, removing discordId")
// this does a quick call to make sure the username exists on the server before allowing the rest of the code to run
// this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server
_, err = db.CheckUsernameExists(username)
if err != nil {
httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound)
return
}
userUuid, err := db.FetchUUIDFromUsername(username)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
err = db.RemoveDiscordIdByUUID(userUuid)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
case discordId != "":
log.Printf("DiscordID given, removing discordId")
err = db.RemoveDiscordIdByDiscordId(discordId)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
}
log.Printf("%s: %s removed discord id %s from username %s", userDiscordId, r.URL.Path, r.Form.Get("discordId"), r.Form.Get("username"))
w.WriteHeader(http.StatusOK)
}
func handleAdminGoogleLink(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest)
return
}
uuid, err := uuidFromRequest(r)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
userDiscordId, err := db.FetchDiscordIdByUUID(uuid)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID)
if !hasRole || err != nil {
httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden)
return
}
username := r.Form.Get("username")
googleId := r.Form.Get("googleId")
// this does a quick call to make sure the username exists on the server before allowing the rest of the code to run
// this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server
_, err = db.CheckUsernameExists(username)
if err != nil {
httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound)
return
}
userUuid, err := db.FetchUUIDFromUsername(username)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
err = db.AddGoogleIdByUUID(googleId, userUuid)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
log.Printf("%s: %s added google id %s to username %s", r.URL.Path, userDiscordId, googleId, username)
w.WriteHeader(http.StatusOK)
}
func handleAdminGoogleUnlink(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest)
return
}
uuid, err := uuidFromRequest(r)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
userDiscordId, err := db.FetchDiscordIdByUUID(uuid)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID)
if !hasRole || err != nil {
httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden)
return
}
username := r.Form.Get("username")
googleId := r.Form.Get("googleId")
switch {
case username != "":
log.Printf("Username given, removing googleId")
// this does a quick call to make sure the username exists on the server before allowing the rest of the code to run
// this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server
_, err = db.CheckUsernameExists(username)
if err != nil {
httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound)
return
}
userUuid, err := db.FetchUUIDFromUsername(username)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
err = db.RemoveGoogleIdByUUID(userUuid)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
case googleId != "":
log.Printf("DiscordID given, removing googleId")
err = db.RemoveGoogleIdByDiscordId(googleId)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
}
log.Printf("%s: %s removed google id %s from username %s", userDiscordId, r.URL.Path, r.Form.Get("googleId"), r.Form.Get("username"))
w.WriteHeader(http.StatusOK)
}
func handleAdminSearch(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
httpError(w, r, fmt.Errorf("failed to parse request form: %s", err), http.StatusBadRequest)
return
}
uuid, err := uuidFromRequest(r)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
userDiscordId, err := db.FetchDiscordIdByUUID(uuid)
if err != nil {
httpError(w, r, err, http.StatusUnauthorized)
return
}
hasRole, err := account.IsUserDiscordAdmin(userDiscordId, account.DiscordGuildID)
if !hasRole || err != nil {
httpError(w, r, fmt.Errorf("user does not have the required role"), http.StatusForbidden)
return
}
username := r.Form.Get("username")
// this does a quick call to make sure the username exists on the server before allowing the rest of the code to run
// this calls error value 404 (StatusNotFound) if there's no data; this means the username does not exist in the server
_, err = db.CheckUsernameExists(username)
if err != nil {
httpError(w, r, fmt.Errorf("username does not exist on the server"), http.StatusNotFound)
return
}
// this does a single call that does a query for multiple columns from our database and makes an object out of it, which is returned to us
adminSearchResult, err := db.FetchAdminDetailsByUsername(username)
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
return
}
writeJSON(w, r, adminSearchResult)
log.Printf("%s: %s searched for username %s", userDiscordId, r.URL.Path, username)
}

@ -0,0 +1,13 @@
VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=http://{serverIP}:8001
VITE_DISCORD_CLIENT_ID=1248062921129459756
VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com
VITE_I18N_DEBUG=1
debug=true
dbaddr=db
dbuser=pokerogue
dbpass=pokerogue
dbname=pokeroguedb
gameurl=http://{devMachineIP}:8000
callbackurl=http://{serverIP}:8001

@ -68,6 +68,25 @@ func AddGoogleIdByUsername(googleId string, username string) error {
return nil return nil
} }
func AddGoogleIdByUUID(googleId string, uuid []byte) error {
_, err := handle.Exec("UPDATE accounts SET googleId = ? WHERE uuid = ?", googleId, uuid)
if err != nil {
return err
}
return nil
}
func AddDiscordIdByUUID(discordId string, uuid []byte) error {
_, err := handle.Exec("UPDATE accounts SET discordId = ? WHERE uuid = ?", discordId, uuid)
if err != nil {
return err
}
return nil
}
func FetchUsernameByDiscordId(discordId string) (string, error) { func FetchUsernameByDiscordId(discordId string) (string, error) {
var username string var username string
err := handle.QueryRow("SELECT username FROM accounts WHERE discordId = ?", discordId).Scan(&username) err := handle.QueryRow("SELECT username FROM accounts WHERE discordId = ?", discordId).Scan(&username)
@ -154,6 +173,60 @@ func FetchUsernameBySessionToken(token []byte) (string, error) {
return username, nil return username, nil
} }
func CheckUsernameExists(username string) (string, error) {
var dbUsername sql.NullString
err := handle.QueryRow("SELECT username FROM accounts WHERE username = ?", username).Scan(&dbUsername)
if err != nil {
return "", err
}
if !dbUsername.Valid {
return "", nil
}
return dbUsername.String, nil
}
func FetchLastLoggedInDateByUsername(username string) (string, error) {
var lastLoggedIn sql.NullString
err := handle.QueryRow("SELECT lastLoggedIn FROM accounts WHERE username = ?", username).Scan(&lastLoggedIn)
if err != nil {
return "", err
}
if !lastLoggedIn.Valid {
return "", nil
}
return lastLoggedIn.String, nil
}
type AdminSearchResponse struct {
Username string `json:"username"`
DiscordId string `json:"discordId"`
GoogleId string `json:"googleId"`
LastLoggedIn string `json:"lastLoggedIn"`
Registered string `json:"registered"`
}
func FetchAdminDetailsByUsername(dbUsername string) (AdminSearchResponse, error) {
var resultUsername, resultDiscordId, resultGoogleId, resultLastLoggedIn, resultRegistered sql.NullString
var adminResponse AdminSearchResponse
err := handle.QueryRow("SELECT username, discordId, googleId, lastLoggedIn, registered from accounts WHERE username = ?", dbUsername).Scan(&resultUsername, &resultDiscordId, &resultGoogleId, &resultLastLoggedIn, &resultRegistered)
if err != nil {
return adminResponse, err
}
adminResponse = AdminSearchResponse{
Username: resultUsername.String,
DiscordId: resultDiscordId.String,
GoogleId: resultGoogleId.String,
LastLoggedIn: resultLastLoggedIn.String,
Registered: resultRegistered.String,
}
return adminResponse, nil
}
func UpdateAccountPassword(uuid, key, salt []byte) error { func UpdateAccountPassword(uuid, key, salt []byte) error {
_, err := handle.Exec("UPDATE accounts SET (hash, salt) VALUES (?, ?) WHERE uuid = ?", key, salt, uuid) _, err := handle.Exec("UPDATE accounts SET (hash, salt) VALUES (?, ?) WHERE uuid = ?", key, salt, uuid)
if err != nil { if err != nil {
@ -343,6 +416,16 @@ func FetchUsernameFromUUID(uuid []byte) (string, error) {
return username, nil return username, nil
} }
func FetchUUIDFromUsername(username string) ([]byte, error) {
var uuid []byte
err := handle.QueryRow("SELECT uuid FROM accounts WHERE username = ?", username).Scan(&uuid)
if err != nil {
return nil, err
}
return uuid, nil
}
func RemoveDiscordIdByUUID(uuid []byte) error { func RemoveDiscordIdByUUID(uuid []byte) error {
_, err := handle.Exec("UPDATE accounts SET discordId = NULL WHERE uuid = ?", uuid) _, err := handle.Exec("UPDATE accounts SET discordId = NULL WHERE uuid = ?", uuid)
if err != nil { if err != nil {
@ -360,3 +443,39 @@ func RemoveGoogleIdByUUID(uuid []byte) error {
return nil return nil
} }
func RemoveGoogleIdByUsername(username string) error {
_, err := handle.Exec("UPDATE accounts SET googleId = NULL WHERE username = ?", username)
if err != nil {
return err
}
return nil
}
func RemoveDiscordIdByUsername(username string) error {
_, err := handle.Exec("UPDATE accounts SET discordId = NULL WHERE username = ?", username)
if err != nil {
return err
}
return nil
}
func RemoveDiscordIdByDiscordId(discordId string) error {
_, err := handle.Exec("UPDATE accounts SET discordId = NULL WHERE discordId = ?", discordId)
if err != nil {
return err
}
return nil
}
func RemoveGoogleIdByDiscordId(discordId string) error {
_, err := handle.Exec("UPDATE accounts SET googleId = NULL WHERE discordId = ?", discordId)
if err != nil {
return err
}
return nil
}

@ -37,6 +37,8 @@ services:
- database:/var/lib/mysql - database:/var/lib/mysql
networks: networks:
- internal - internal
ports:
- "3306:3306"
# Watchtower is a service that will automatically update your running containers # Watchtower is a service that will automatically update your running containers
# when a new image is available. This is useful for keeping your server up-to-date. # when a new image is available. This is useful for keeping your server up-to-date.

Loading…
Cancel
Save