Updated config samplle, moved around user methods.

This commit is contained in:
Ada Werefox 2025-04-29 22:45:40 -07:00
parent dcbe844c41
commit be9702d716
5 changed files with 257 additions and 227 deletions

View file

@ -3,6 +3,11 @@ domain = "localhost"
port = "31337" port = "31337"
https = false https = false
[frontend]
domain = "localhost"
port = "15995"
https = false
[oauth] [oauth]
# You can get all of this from https://discord.com/developers/applications # You can get all of this from https://discord.com/developers/applications
clientid = "[CHANGE ME]" clientid = "[CHANGE ME]"

View file

@ -18,7 +18,6 @@ func main() {
router.GET("/auth/login", api.AuthLoginRedirect) router.GET("/auth/login", api.AuthLoginRedirect)
router.GET("/auth/logout", api.AuthLogoutRedirect) router.GET("/auth/logout", api.AuthLogoutRedirect)
// Create // Create
router.POST("/user/update", api.CreateOrUpdateUser)
router.POST("/group", api.CreateGroup) router.POST("/group", api.CreateGroup)
router.POST("/function", api.CreateFunction) router.POST("/function", api.CreateFunction)
router.POST("/function-tag", api.CreateFunctionTag) router.POST("/function-tag", api.CreateFunctionTag)

View file

@ -36,6 +36,97 @@ var GlobalOAuth *oauth2.Config
// Private Functions // Private Functions
func createOrUpdateUser(context *gin.Context) {
oauthTokenJSON := context.GetString("discord-oauthtoken")
err := error(nil)
if oauthTokenJSON == "" {
oauthTokenJSON, err = context.Cookie("discord-oauthtoken")
if err != nil {
log.Printf("This really shouldn't happen. %s", err)
context.AbortWithStatus(http.StatusInternalServerError)
}
}
var oauthToken *oauth2.Token
err = json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
var currentDiscordUser authdiscord.DiscordUser
result := currentDiscordUser.Get(context, oauthToken, GlobalOAuth)
if result == "" {
if user.Exists(GlobalDatabase, currentDiscordUser.Id) {
currentUser := (*user.Get(GlobalDatabase, []string{currentDiscordUser.Id}))[0]
err := error(nil)
if currentUser.LoggedIn {
context.SetCookie("discord-oauthtoken", currentUser.LoginToken, 0, "", GlobalConfig.API.Domain, false, false)
err = user.Update(
GlobalDatabase,
currentDiscordUser.Id,
currentDiscordUser.Global_Name,
currentDiscordUser.Username,
currentDiscordUser.Avatar,
currentDiscordUser.Avatar_Decoration_Data.Asset,
currentUser.LoginToken,
true,
)
} else {
// context.SetCookie("discord-oauthtoken", oauthTokenJSON, 0, "", GlobalConfig.API.Domain, false, false)
err = user.Update(
GlobalDatabase,
currentDiscordUser.Id,
currentDiscordUser.Global_Name,
currentDiscordUser.Username,
currentDiscordUser.Avatar,
currentDiscordUser.Avatar_Decoration_Data.Asset,
oauthTokenJSON,
true,
)
}
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusInternalServerError)
}
} else {
// context.SetCookie("discord-oauthtoken", oauthTokenJSON, 0, "", GlobalConfig.API.Domain, false, false)
err := user.Create(
GlobalDatabase,
currentDiscordUser.Id,
currentDiscordUser.Global_Name,
currentDiscordUser.Username,
currentDiscordUser.Avatar,
currentDiscordUser.Avatar_Decoration_Data.Asset,
oauthTokenJSON,
true,
)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusInternalServerError)
}
}
} else {
log.Printf("This also really shouldn't happen. %s", result)
context.AbortWithStatus(http.StatusInternalServerError)
}
}
func checkAuthentication(context *gin.Context) *oauth2.Token {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
var oauthToken *oauth2.Token
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err == nil {
if oauthToken.Valid() {
if (*user.Get(GlobalDatabase, []string{oauthTokenJSON}))[0].LoggedIn {
return oauthToken
}
}
}
}
context.Redirect(http.StatusTemporaryRedirect, GlobalConfig.GetFrontendRootDomain())
return nil
}
func objectIDStringsToInts(context *gin.Context, objectIDs []string) *[]int { func objectIDStringsToInts(context *gin.Context, objectIDs []string) *[]int {
var objectIDInts []int var objectIDInts []int
for _, objectID := range objectIDs { for _, objectID := range objectIDs {
@ -62,12 +153,13 @@ func AuthCallback(context *gin.Context) {
oauthTokenJSON, _ := json.Marshal(oauthToken) oauthTokenJSON, _ := json.Marshal(oauthToken)
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false) context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
context.Set("discord-oauthtoken", string(oauthTokenJSON)) context.Set("discord-oauthtoken", string(oauthTokenJSON))
CreateOrUpdateUser(context) createOrUpdateUser(context)
log.Println(GlobalConfig.GetFrontendRootDomain())
context.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%sdashboard", GlobalConfig.GetFrontendRootDomain())) context.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%sdashboard", GlobalConfig.GetFrontendRootDomain()))
} }
func AuthLoginRedirect(context *gin.Context) { func AuthLoginRedirect(context *gin.Context) {
context.Redirect(302, GlobalOAuth.AuthCodeURL(context.GetString("state"))) context.Redirect(http.StatusTemporaryRedirect, GlobalOAuth.AuthCodeURL(context.GetString("state")))
} }
func AuthLogoutRedirect(context *gin.Context) { func AuthLogoutRedirect(context *gin.Context) {
@ -78,65 +170,14 @@ func AuthLogoutRedirect(context *gin.Context) {
} else { } else {
log.Println(err) log.Println(err)
} }
log.Println(GlobalConfig.GetFrontendRootDomain())
context.Redirect(http.StatusTemporaryRedirect, GlobalConfig.GetFrontendRootDomain()) context.Redirect(http.StatusTemporaryRedirect, GlobalConfig.GetFrontendRootDomain())
} }
func CreateOrUpdateUser(context *gin.Context) { // Create Endpoints (POST)
oauthTokenJSON := context.GetString("discord-oauthtoken")
err := error(nil)
if oauthTokenJSON == "" {
oauthTokenJSON, err = context.Cookie("discord-oauthtoken")
if err != nil {
log.Printf("This really shouldn't happen. %s", err)
context.AbortWithStatus(http.StatusInternalServerError)
}
}
var oauthToken *oauth2.Token
err = json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
var currentDiscordUser authdiscord.DiscordUser
currentDiscordUser.GetDiscordUser(context, oauthToken, GlobalConfig, GlobalOAuth)
updatedDatabaseUser := user.User{
DisplayName: currentDiscordUser.Global_Name,
Username: currentDiscordUser.Username,
Id: currentDiscordUser.Id,
Avatar: currentDiscordUser.Avatar,
AvatarDecoration: currentDiscordUser.Avatar_Decoration_Data.Asset,
LoginToken: string(oauthTokenJSON),
LoggedIn: true,
ApiKey: nil,
}
if user.Exists(GlobalDatabase, currentDiscordUser.Id) {
dbOAuthToken := user.GetTokenFromUserId(GlobalDatabase, currentDiscordUser.Id)
if user.GetLoggedInFromDiscordId(GlobalDatabase, currentDiscordUser.Id) {
context.SetCookie("discord-oauthtoken", dbOAuthToken, 0, "", GlobalConfig.API.Domain, false, false)
updatedDatabaseUser.LoginToken = string(dbOAuthToken)
} else {
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
}
err := updatedDatabaseUser.Update(GlobalDatabase)
if err != nil {
log.Println(err)
context.AbortWithStatus(http.StatusInternalServerError)
}
} else {
err := updatedDatabaseUser.Create(GlobalDatabase)
if err != nil {
log.Println(err)
context.Copy().AbortWithStatus(http.StatusInternalServerError)
}
}
}
// Create Endpoints (post/)
func CreateGroup(context *gin.Context) { func CreateGroup(context *gin.Context) {
GetUserLoggedIn(context) checkAuthentication(context)
isAuthorized := context.GetBool("is-authorized")
if isAuthorized {
name, nameOk := context.GetQuery("name") name, nameOk := context.GetQuery("name")
if nameOk { if nameOk {
group.Create(GlobalDatabase, name) group.Create(GlobalDatabase, name)
@ -144,15 +185,10 @@ func CreateGroup(context *gin.Context) {
} else { } else {
context.AbortWithStatus(http.StatusBadRequest) context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
context.AbortWithStatus(http.StatusUnauthorized)
}
} }
func CreateFunction(context *gin.Context) { func CreateFunction(context *gin.Context) {
GetUserLoggedIn(context) checkAuthentication(context)
isAuthorized := context.GetBool("is-authorized")
if isAuthorized {
name, nameOk := context.GetQuery("name") name, nameOk := context.GetQuery("name")
tags := context.QueryArray("tags") tags := context.QueryArray("tags")
requirements := context.QueryArray("requirements") requirements := context.QueryArray("requirements")
@ -162,15 +198,10 @@ func CreateFunction(context *gin.Context) {
} else { } else {
context.AbortWithStatus(http.StatusBadRequest) context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
context.AbortWithStatus(http.StatusUnauthorized)
}
} }
func CreateFunctionTag(context *gin.Context) { func CreateFunctionTag(context *gin.Context) {
GetUserLoggedIn(context) checkAuthentication(context)
isAuthorized := context.GetBool("is-authorized")
if isAuthorized {
name := context.Query("name") name := context.Query("name")
if name != "" { if name != "" {
functiontag.Create(GlobalDatabase, name) functiontag.Create(GlobalDatabase, name)
@ -178,17 +209,12 @@ func CreateFunctionTag(context *gin.Context) {
} else { } else {
context.AbortWithStatus(http.StatusBadRequest) context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
context.AbortWithStatus(http.StatusUnauthorized)
}
} }
// Update Endpoints (put/) // Update Endpoints (PUT)
func UpdateFunction(context *gin.Context) { func UpdateFunction(context *gin.Context) {
GetUserLoggedIn(context) checkAuthentication(context)
isAuthorized := context.GetBool("is-authorized")
if isAuthorized {
name, nameOk := context.GetQuery("name") name, nameOk := context.GetQuery("name")
tags := context.QueryArray("tags") tags := context.QueryArray("tags")
requirements := context.QueryArray("requirements") requirements := context.QueryArray("requirements")
@ -198,70 +224,42 @@ func UpdateFunction(context *gin.Context) {
} else { } else {
context.AbortWithStatus(http.StatusBadRequest) context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
context.AbortWithStatus(http.StatusUnauthorized)
}
} }
// Read Endpoints (get/) // Read Endpoints (GET)
func GetDiscordUser(context *gin.Context) { func GetDiscordUser(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken") oauthToken := checkAuthentication(context)
if err == nil { if oauthToken != nil {
var oauthToken *oauth2.Token
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err == nil {
if oauthToken.Valid() {
var discordUser authdiscord.DiscordUser var discordUser authdiscord.DiscordUser
discordUser.GetDiscordUser(context, oauthToken, GlobalConfig, GlobalOAuth) result := discordUser.Get(context, oauthToken, GlobalOAuth)
if user.GetLoggedInFromDiscordId(GlobalDatabase, discordUser.Id) { if result != "" {
log.Println(result)
log.Println("Assuming the Discord OAuth Key has expired.")
context.Redirect(http.StatusUnauthorized, fmt.Sprintf("%slogout", GlobalConfig.GetFrontendRootDomain()))
} else {
if (*user.Get(GlobalDatabase, []string{discordUser.Id}))[0].LoggedIn {
context.JSON(http.StatusOK, discordUser) context.JSON(http.StatusOK, discordUser)
} else { } else {
context.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%slogout", GlobalConfig.GetAPIRootDomain())) context.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%slogout", GlobalConfig.GetFrontendRootDomain()))
} }
return
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
log.Println(err)
context.AbortWithStatus(http.StatusBadRequest)
}
context.Redirect(http.StatusTemporaryRedirect, GlobalConfig.GetFrontendRootDomain())
} }
func GetUserLoggedIn(context *gin.Context) { func GetUserLoggedIn(context *gin.Context) {
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
if err == nil {
var oauthToken *oauth2.Token
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
if err == nil {
if oauthToken.Valid() {
if user.GetLoggedInFromOAuthToken(GlobalDatabase, oauthTokenJSON) {
context.JSON(http.StatusOK, gin.H{ context.JSON(http.StatusOK, gin.H{
"message": true, "message": (checkAuthentication(context) != nil),
}) })
context.Set("is-authorized", true)
return
}
}
}
}
context.JSON(http.StatusUnauthorized, gin.H{
"message": false,
})
context.Set("is-authorized", false)
} }
func GetObjects(context *gin.Context) { func GetObjects(context *gin.Context) {
objectIDs, idOk := context.GetQueryArray("id") objectIDs, idOk := context.GetQueryArray("id")
if idOk { if idOk {
switch objectType := context.Param("object"); objectType { switch objectType := context.Param("object"); objectType {
case "user":
context.JSON(http.StatusOK, gin.H{
"user": user.Get(GlobalDatabase, objectIDs)})
case "persons": case "persons":
context.JSON(http.StatusOK, gin.H{ context.JSON(http.StatusOK, gin.H{
"persons": person.Get(GlobalDatabase, objectIDs), "persons": person.Get(GlobalDatabase, objectIDs),
@ -381,12 +379,10 @@ func GetAllObjects(context *gin.Context) {
} }
} }
// Delete Endpoints (delete/) // Delete Endpoints (DELETE)
func DeleteFunction(context *gin.Context) { func DeleteFunction(context *gin.Context) {
GetUserLoggedIn(context) checkAuthentication(context)
isAuthorized := context.GetBool("is-authorized")
if isAuthorized {
functionNames, ok := context.GetQueryArray("name") functionNames, ok := context.GetQueryArray("name")
if ok { if ok {
function.Delete(GlobalDatabase, functionNames) function.Delete(GlobalDatabase, functionNames)
@ -394,7 +390,4 @@ func DeleteFunction(context *gin.Context) {
} else { } else {
context.AbortWithStatus(http.StatusBadRequest) context.AbortWithStatus(http.StatusBadRequest)
} }
} else {
context.AbortWithStatus(http.StatusUnauthorized)
}
} }

View file

@ -4,8 +4,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"net/http"
configserver "example.com/config/server" configserver "example.com/config/server"
@ -38,25 +36,22 @@ type DiscordUser struct {
Premium_Type float64 `json:"premium_type"` Premium_Type float64 `json:"premium_type"`
} }
func (discordUser *DiscordUser) GetDiscordUser(context *gin.Context, oauthToken *oauth2.Token, appConfig configserver.AppConfig, oauthConfig *oauth2.Config) { func (discordUser *DiscordUser) Get(context *gin.Context, oauthToken *oauth2.Token, oauthConfig *oauth2.Config) string {
response, err := oauthConfig.Client(context, oauthToken).Get("https://discord.com/api/users/@me") response, err := oauthConfig.Client(context, oauthToken).Get("https://discord.com/api/users/@me")
if err != nil || response.StatusCode != 200 { if err != nil || response.StatusCode != 200 {
responseMessage := ""
if err != nil { if err != nil {
responseMessage = err.Error() return err.Error()
} else { } else {
responseMessage = response.Status return response.Status
} }
log.Println(responseMessage)
log.Println("Assuming the Discord OAuth Key has expired.")
context.Redirect(http.StatusUnauthorized, fmt.Sprintf("%slogout", appConfig.GetFrontendRootDomain()))
} }
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) body, err := io.ReadAll(response.Body)
if err != nil { if err != nil {
log.Println(err) return err.Error()
} }
json.Unmarshal(body, &discordUser) json.Unmarshal(body, &discordUser)
return ""
} }
func CreateDiscordOAuthConfig(config configserver.AppConfig) *oauth2.Config { func CreateDiscordOAuthConfig(config configserver.AppConfig) *oauth2.Config {

View file

@ -1,38 +1,26 @@
package user package user
import ( import (
"errors" "log"
"gorm.io/gorm" "gorm.io/gorm"
) )
type User struct { type User struct {
gorm.Model gorm.Model
Id string `json:"id"` Id string `gorm:"primaryKey uniqueIndex" json:"id"`
DisplayName string `json:"display_name"` DisplayName string `json:"display_name"`
Username string `json:"user_name"` Username string `json:"user_name"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
AvatarDecoration string `json:"avatar_decoration"` AvatarDecoration string `json:"avatar_decoration"`
LoginToken string `json:"login_token"` LoginToken string `json:"login_token"`
LoggedIn bool `json:"logged_in"` LoggedIn bool `json:"logged_in"`
ApiKey []struct { ApiKeys []struct {
Name string `gorm:"primaryKey uniqueIndex" json:"name"` Name string `json:"name"`
Key string `json:"key"` Key string `json:"key"`
} `gorm:"foreignKey:Name" json:"api_key"` } `gorm:"foreignKey:Name" json:"api_key"`
} }
func (user *User) Get(db *gorm.DB, id string) {
db.Where("id = ?", id).Take(&user)
}
func (user User) Update(db *gorm.DB) error {
result := db.Save(&user)
if result.Error != nil {
return result.Error
}
return nil
}
func (user User) Create(db *gorm.DB) error { func (user User) Create(db *gorm.DB) error {
result := db.Create(&user) result := db.Create(&user)
if result.Error != nil { if result.Error != nil {
@ -41,46 +29,96 @@ func (user User) Create(db *gorm.DB) error {
return nil return nil
} }
func Logout(db *gorm.DB, oauthToken string) { func (user *User) Get(db *gorm.DB, id string) error {
db.Model(&User{}).Where("login_token = ?", oauthToken).Update("logged_in", false) result := db.Where("id = ?", id).Take(&user)
if result.Error == gorm.ErrRecordNotFound {
result := db.Where("login_token = ?", id).Take(&user)
if result.Error != nil {
return result.Error
}
}
return nil
}
func (user User) Update(db *gorm.DB) error {
var originalUser User
originalUser.Get(db, user.Id)
result := db.Model(&originalUser).Updates(&user)
if result.Error != nil {
return result.Error
}
return nil
}
func (user User) Delete(db *gorm.DB) error {
result := db.Delete(&user)
if result.Error != nil {
return result.Error
}
return nil
}
func (user User) Logout(db *gorm.DB) error {
result := db.Model(&user).Update("logged_in", false)
if result.Error != nil {
return result.Error
}
return nil
}
func Logout(db *gorm.DB, oauthToken string) error {
var user User
user.Get(db, oauthToken)
return user.Logout(db)
} }
func Exists(db *gorm.DB, id string) bool { func Exists(db *gorm.DB, id string) bool {
var queryUser User var queryUser User
result := db.Where("id = ?", id).Take(&queryUser) err := queryUser.Get(db, id)
if errors.Is(result.Error, gorm.ErrRecordNotFound) { return (err == nil)
return false
} else {
return true
}
} }
func GetTokenFromUserId(db *gorm.DB, id string) string { func Create(db *gorm.DB, id string, displayName string, username string, avatar string, avatarDecoration string, loginToken string, loggedIn bool) error {
var dbUser User return User{
result := db.Where("id = ?", id).Select("login_token").Take(&dbUser) Id: id,
if errors.Is(result.Error, gorm.ErrRecordNotFound) { DisplayName: displayName,
return "" Username: username,
} else { Avatar: avatar,
return dbUser.LoginToken AvatarDecoration: avatarDecoration,
} LoginToken: loginToken,
LoggedIn: loggedIn,
ApiKeys: nil,
}.Create(db)
} }
func GetLoggedInFromOAuthToken(db *gorm.DB, oauthTokenJSON string) bool { func Get(db *gorm.DB, inputUsers []string) *[]User {
var queryUser User var outputUsers []User
result := db.Where("login_token = ?", oauthTokenJSON).Take(&queryUser) for _, inputUser := range inputUsers {
if errors.Is(result.Error, gorm.ErrRecordNotFound) { var outputUser User
return false outputUser.Get(db, inputUser)
} else { outputUsers = append(outputUsers, outputUser)
return queryUser.LoggedIn
} }
return &outputUsers
} }
func GetLoggedInFromDiscordId(db *gorm.DB, discordId string) bool { func GetAll(db *gorm.DB) *[]User {
var queryUser User var outputUserIDs []string
result := db.Where("id = ?", discordId).Take(&queryUser) result := db.Model(&User{}).Select("id").Find(&outputUserIDs)
if errors.Is(result.Error, gorm.ErrRecordNotFound) { if result.Error != nil {
return false log.Println(result.Error)
} else {
return queryUser.LoggedIn
} }
return Get(db, outputUserIDs)
}
func Update(db *gorm.DB, id string, displayName string, username string, avatar string, avatarDecoration string, loginToken string, loggedIn bool) error {
return User{
Id: id,
DisplayName: displayName,
Username: username,
Avatar: avatar,
AvatarDecoration: avatarDecoration,
LoginToken: loginToken,
LoggedIn: loggedIn,
ApiKeys: nil,
}.Update(db)
} }