338 lines
10 KiB
Go
338 lines
10 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
|
|
authdiscord "example.com/auth/discord"
|
|
configserver "example.com/config/server"
|
|
databasecommands "example.com/database/commands"
|
|
databasemodels "example.com/database/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/xyproto/randomstring"
|
|
"golang.org/x/oauth2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var GlobalDatabase *gorm.DB
|
|
var GlobalConfig configserver.AppConfig
|
|
var GlobalOAuth *oauth2.Config
|
|
|
|
// Private Functions
|
|
|
|
func getDiscordUser(context *gin.Context, oauthToken *oauth2.Token) authdiscord.DiscordUser {
|
|
response, err := GlobalOAuth.Client(context, oauthToken).Get("https://discord.com/api/users/@me")
|
|
if err != nil || response.StatusCode != 200 {
|
|
responseMessage := ""
|
|
if err != nil {
|
|
responseMessage = err.Error()
|
|
} else {
|
|
responseMessage = response.Status
|
|
}
|
|
log.Println(responseMessage)
|
|
log.Println("Assuming the Discord OAuth Key has expired.")
|
|
context.Redirect(http.StatusUnauthorized, "https://localhost:15995/logout")
|
|
}
|
|
defer response.Body.Close()
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
var user authdiscord.DiscordUser
|
|
json.Unmarshal(body, &user)
|
|
return user
|
|
}
|
|
|
|
// Authentication Workflow
|
|
|
|
func AuthCallback(context *gin.Context) {
|
|
oauthState := randomstring.CookieFriendlyString(32)
|
|
context.Set("state", oauthState)
|
|
var err error
|
|
oauthToken, err := GlobalOAuth.Exchange(context.Request.Context(), context.Query("code"))
|
|
if err != nil {
|
|
context.Redirect(http.StatusInternalServerError, "http://localhost:15995/")
|
|
}
|
|
oauthTokenJSON, _ := json.Marshal(oauthToken)
|
|
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", GlobalConfig.API.Domain, false, false)
|
|
context.Set("discord-oauthtoken", string(oauthTokenJSON))
|
|
CreateOrUpdateUser(context)
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/dashboard")
|
|
}
|
|
|
|
func AuthLoginRedirect(context *gin.Context) {
|
|
context.Redirect(302, GlobalOAuth.AuthCodeURL(context.GetString("state")))
|
|
}
|
|
|
|
func AuthLogoutRedirect(context *gin.Context) {
|
|
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
|
|
if err == nil {
|
|
databasecommands.LogoutDatabaseUser(GlobalDatabase, oauthTokenJSON)
|
|
context.SetCookie("discord-oauthtoken", "", -1, "", GlobalConfig.API.Domain, false, true)
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/")
|
|
}
|
|
|
|
// Create & Update Endpoints (post/, put/, patch)
|
|
|
|
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)
|
|
}
|
|
currentDiscordUser := getDiscordUser(context, oauthToken)
|
|
updatedDatabaseUser := databasemodels.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 databasecommands.GetDatabaseUserExists(GlobalDatabase, currentDiscordUser.Id) {
|
|
dbOAuthToken := databasecommands.GetDatabaseUserToken(GlobalDatabase, currentDiscordUser.Id)
|
|
if databasecommands.GetDatabaseUserLoggedInFromDiscordId(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 := databasecommands.UpdateDatabaseUser(GlobalDatabase, updatedDatabaseUser)
|
|
if err != nil {
|
|
log.Println(err)
|
|
context.AbortWithStatus(http.StatusInternalServerError)
|
|
}
|
|
} else {
|
|
err := databasecommands.CreateDatabaseUser(GlobalDatabase, updatedDatabaseUser)
|
|
if err != nil {
|
|
log.Println(err)
|
|
context.Copy().AbortWithStatus(http.StatusInternalServerError)
|
|
}
|
|
}
|
|
}
|
|
|
|
func CreateDatabaseGroup(context *gin.Context) {
|
|
GetIsUserAuthorized(context)
|
|
isAuthorized := context.GetBool("is-authorized")
|
|
if isAuthorized {
|
|
name := context.Query("name")
|
|
if name != "" {
|
|
databasecommands.CreateDatabaseGroup(GlobalDatabase, databasemodels.Group{
|
|
Name: name,
|
|
})
|
|
context.Status(http.StatusOK)
|
|
} else {
|
|
context.AbortWithStatus(http.StatusBadRequest)
|
|
}
|
|
} else {
|
|
context.AbortWithStatus(http.StatusUnauthorized)
|
|
}
|
|
}
|
|
|
|
func CreateDatabaseFunction(context *gin.Context) {
|
|
GetIsUserAuthorized(context)
|
|
isAuthorized := context.GetBool("is-authorized")
|
|
log.Println(isAuthorized)
|
|
if isAuthorized {
|
|
name := context.Query("name")
|
|
tags := context.QueryArray("tags")
|
|
requirements := context.QueryArray("requirements")
|
|
if name != "" {
|
|
newTags := []databasemodels.FunctionTag{}
|
|
log.Println(tags)
|
|
for _, tag := range tags {
|
|
newTags = append(newTags, databasecommands.GetDatabaseFunctionTag(GlobalDatabase, tag))
|
|
}
|
|
log.Println(newTags)
|
|
newRequirements := []databasemodels.Function{}
|
|
for _, requirement := range requirements {
|
|
newRequirement := databasecommands.GetDatabaseFunction(GlobalDatabase, requirement)
|
|
newRequirements = append(newRequirements, newRequirement)
|
|
}
|
|
databasecommands.CreateDatabaseFunction(GlobalDatabase, databasemodels.Function{
|
|
Name: name,
|
|
Tags: newTags,
|
|
Requirements: newRequirements,
|
|
})
|
|
context.Status(http.StatusOK)
|
|
} else {
|
|
context.AbortWithStatus(http.StatusBadRequest)
|
|
}
|
|
} else {
|
|
context.AbortWithStatus(http.StatusUnauthorized)
|
|
}
|
|
}
|
|
|
|
func CreateDatabaseFunctionTag(context *gin.Context) {
|
|
GetIsUserAuthorized(context)
|
|
isAuthorized := context.GetBool("is-authorized")
|
|
log.Println(isAuthorized)
|
|
if isAuthorized {
|
|
name := context.Query("name")
|
|
if name != "" {
|
|
databasecommands.CreateDatabaseFunctionTag(GlobalDatabase, databasemodels.FunctionTag{
|
|
Name: name,
|
|
})
|
|
context.Status(http.StatusOK)
|
|
} else {
|
|
context.AbortWithStatus(http.StatusBadRequest)
|
|
}
|
|
} else {
|
|
context.AbortWithStatus(http.StatusUnauthorized)
|
|
}
|
|
}
|
|
|
|
// Read Endpoints (get/)
|
|
|
|
func GetUserInfo(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() {
|
|
user := getDiscordUser(context, oauthToken)
|
|
if databasecommands.GetDatabaseUserLoggedInFromDiscordId(GlobalDatabase, user.Id) {
|
|
context.JSON(http.StatusOK, user)
|
|
} else {
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:31337/auth/logout")
|
|
}
|
|
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, "http://localhost:15995/")
|
|
}
|
|
|
|
func GetIsUserAuthorized(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 databasecommands.GetDatabaseUserLoggedIn(GlobalDatabase, oauthTokenJSON) {
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"message": true,
|
|
})
|
|
context.Set("is-authorized", true)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
context.JSON(http.StatusUnauthorized, gin.H{
|
|
"message": false,
|
|
})
|
|
context.Set("is-authorized", false)
|
|
}
|
|
|
|
func GetDatabaseGroup(context *gin.Context) {
|
|
groupName := context.Query("group")
|
|
if groupName != "" {
|
|
group := databasecommands.GetDatabaseGroup(GlobalDatabase, groupName)
|
|
context.JSON(http.StatusOK, group)
|
|
} else {
|
|
context.JSON(http.StatusBadRequest, gin.H{
|
|
"name": "",
|
|
})
|
|
}
|
|
}
|
|
|
|
func GetDatabaseGroups(context *gin.Context) {
|
|
groupNames := context.QueryArray("groups")
|
|
groups := databasecommands.GetDatabaseGroups(GlobalDatabase, groupNames)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"groups": groups,
|
|
})
|
|
}
|
|
|
|
func GetAllDatabaseGroups(context *gin.Context) {
|
|
groups := databasecommands.GetAllDatabaseGroups(GlobalDatabase)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"groups": groups,
|
|
})
|
|
}
|
|
|
|
func GetDatabaseFunction(context *gin.Context) {
|
|
functionName := context.Query("function")
|
|
if functionName != "" {
|
|
group := databasecommands.GetDatabaseFunction(GlobalDatabase, functionName)
|
|
context.JSON(http.StatusOK, group)
|
|
} else {
|
|
context.JSON(http.StatusBadRequest, gin.H{
|
|
"name": "",
|
|
})
|
|
}
|
|
}
|
|
|
|
func GetDatabaseFunctions(context *gin.Context) {
|
|
functionNames := context.QueryArray("functions")
|
|
functions := databasecommands.GetDatabaseFunctions(GlobalDatabase, functionNames)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"functions": functions,
|
|
})
|
|
}
|
|
|
|
func GetAllDatabaseFunctions(context *gin.Context) {
|
|
functions := databasecommands.GetAllDatabaseFunctions(GlobalDatabase)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"functions": functions,
|
|
})
|
|
}
|
|
|
|
func GetDatabaseFunctionTag(context *gin.Context) {
|
|
functionTagName := context.Query("name")
|
|
if functionTagName != "" {
|
|
functionTag := databasecommands.GetDatabaseFunctionTag(GlobalDatabase, functionTagName)
|
|
context.JSON(http.StatusOK, functionTag)
|
|
} else {
|
|
context.JSON(http.StatusBadRequest, gin.H{
|
|
"name": "",
|
|
})
|
|
}
|
|
}
|
|
|
|
func GetDatabaseFunctionTags(context *gin.Context) {
|
|
functionTagNames := context.QueryArray("functiontags")
|
|
functionTags := databasecommands.GetDatabaseFunctionTags(GlobalDatabase, functionTagNames)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"function_tags": functionTags,
|
|
})
|
|
}
|
|
|
|
func GetAllDatabaseFunctionTags(context *gin.Context) {
|
|
functionTags := databasecommands.GetAllDatabaseFunctionTags(GlobalDatabase)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"function_tags": functionTags,
|
|
})
|
|
}
|
|
|
|
// Delete Endpoints (delete/)
|