255 lines
6.7 KiB
Go
255 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"example.com/lib/dbcommands"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/pelletier/go-toml/v2"
|
|
"github.com/ravener/discord-oauth2"
|
|
"github.com/xyproto/randomstring"
|
|
"golang.org/x/oauth2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type appConfig struct {
|
|
API struct {
|
|
Domain string
|
|
Port string
|
|
Https bool
|
|
}
|
|
OAuth struct {
|
|
ClientID string
|
|
ClientSecret string
|
|
}
|
|
}
|
|
|
|
type discordUser struct {
|
|
Id string
|
|
Username string
|
|
Avatar string
|
|
Discriminator string
|
|
Public_Flags float64
|
|
Flags float64
|
|
Banner string
|
|
Accent_Color float64
|
|
Global_Name string
|
|
Avatar_Decoration_Data struct {
|
|
Asset string
|
|
Sku_Id string
|
|
Expires_At string
|
|
}
|
|
Collectibles string
|
|
Banner_Color string
|
|
Clan string
|
|
Primary_Guild string
|
|
Mfa_Eneabled bool
|
|
Locale string
|
|
Premium_Type float64
|
|
}
|
|
|
|
var db *gorm.DB
|
|
var config appConfig
|
|
var oauthConfig *oauth2.Config
|
|
|
|
func parseConfig(configPath string) appConfig {
|
|
configFile, err := os.Open(configPath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
configFileContent, err := io.ReadAll(configFile)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
var configObject appConfig
|
|
err = toml.Unmarshal(configFileContent, &configObject)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
return configObject
|
|
}
|
|
|
|
func createDiscordOAuthConfig() *oauth2.Config {
|
|
protocolString := ""
|
|
if config.API.Https {
|
|
protocolString = "https://"
|
|
config.API.Port = ""
|
|
} else {
|
|
protocolString = "http://"
|
|
config.API.Port = fmt.Sprintf(":%s", config.API.Port)
|
|
}
|
|
redirectUrlString := fmt.Sprintf("%s%s%s/auth/callback", protocolString, config.API.Domain, config.API.Port)
|
|
config := &oauth2.Config{
|
|
ClientID: config.OAuth.ClientID,
|
|
ClientSecret: config.OAuth.ClientSecret,
|
|
RedirectURL: redirectUrlString,
|
|
Scopes: []string{discord.ScopeIdentify},
|
|
Endpoint: discord.Endpoint,
|
|
}
|
|
return config
|
|
}
|
|
|
|
func loginRedirect(context *gin.Context) {
|
|
context.Redirect(302, oauthConfig.AuthCodeURL(context.GetString("state")))
|
|
}
|
|
|
|
func logoutRedirect(context *gin.Context) {
|
|
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
|
|
if err == nil {
|
|
dbcommands.LogoutDatabaseUser(db, oauthTokenJSON)
|
|
context.SetCookie("discord-oauthtoken", "", -1, "", config.API.Domain, false, true)
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/")
|
|
}
|
|
|
|
func authCallback(context *gin.Context) {
|
|
oauthState := randomstring.CookieFriendlyString(32)
|
|
context.Set("state", oauthState)
|
|
var err error
|
|
oauthToken, err := oauthConfig.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, "", config.API.Domain, false, false)
|
|
user := getDiscordUser(context, oauthToken)
|
|
createOrUpdateUser(context, oauthToken, user)
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:15995/dashboard")
|
|
}
|
|
|
|
func getDiscordUser(context *gin.Context, oauthToken *oauth2.Token) discordUser {
|
|
log.Println(*oauthToken)
|
|
response, err := oauthConfig.Client(context.Request.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
|
|
}
|
|
context.JSON(http.StatusInternalServerError, gin.H{
|
|
"message": responseMessage,
|
|
})
|
|
}
|
|
defer response.Body.Close()
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
context.JSON(http.StatusInternalServerError, gin.H{
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
log.Println(string(body))
|
|
var user discordUser
|
|
json.Unmarshal(body, &user)
|
|
return user
|
|
}
|
|
|
|
func createOrUpdateUser(context *gin.Context, oauthToken *oauth2.Token, user discordUser) {
|
|
oauthTokenJSON, err := json.Marshal(oauthToken)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
dbUser := dbcommands.User{
|
|
DisplayName: user.Global_Name,
|
|
Username: user.Username,
|
|
Id: user.Id,
|
|
Avatar: user.Avatar,
|
|
AvatarDecoration: user.Avatar_Decoration_Data.Asset,
|
|
LoginToken: string(oauthTokenJSON),
|
|
LoggedIn: true,
|
|
}
|
|
if dbcommands.DatabaseUserExists(db, user.Id) {
|
|
dbOAuthToken := dbcommands.GetDatabaseUserToken(db, user.Id)
|
|
if dbOAuthToken == "" {
|
|
context.SetCookie("discord-oauthtoken", string(oauthTokenJSON), 0, "", config.API.Domain, false, false)
|
|
err := dbcommands.UpdateDatabaseUser(db, dbUser)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
} else {
|
|
context.SetCookie("discord-oauthtoken", dbOAuthToken, 0, "", config.API.Domain, false, false)
|
|
}
|
|
} else {
|
|
err := dbcommands.CreateDatabaseUser(db, dbUser)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func dashboardDisplay(context *gin.Context) {
|
|
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
|
|
log.Println(oauthTokenJSON)
|
|
if err == nil {
|
|
var oauthToken *oauth2.Token
|
|
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
|
|
if err == nil {
|
|
if oauthToken.Valid() {
|
|
user := getDiscordUser(context, oauthToken)
|
|
if dbcommands.DatabaseUserLoggedIn(db, user.Id) {
|
|
context.JSON(http.StatusOK, user)
|
|
return
|
|
} else {
|
|
context.Redirect(http.StatusTemporaryRedirect, "http://localhost:31337/logout")
|
|
}
|
|
return
|
|
}
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
context.Redirect(http.StatusTemporaryRedirect, "/")
|
|
}
|
|
|
|
func isUserAutorized(context *gin.Context) {
|
|
oauthTokenJSON, err := context.Cookie("discord-oauthtoken")
|
|
log.Printf("Something something: %s", oauthTokenJSON)
|
|
if err == nil {
|
|
var oauthToken *oauth2.Token
|
|
err := json.Unmarshal([]byte(oauthTokenJSON), &oauthToken)
|
|
if err == nil {
|
|
if oauthToken.Valid() {
|
|
user := getDiscordUser(context, oauthToken)
|
|
log.Printf("What the fuck: %v", user)
|
|
is_logged_in := dbcommands.DatabaseUserLoggedIn(db, user.Id)
|
|
log.Printf("Whyyyyyy: %v", is_logged_in)
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"message": is_logged_in,
|
|
})
|
|
return
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
} else {
|
|
log.Println(err)
|
|
}
|
|
context.JSON(http.StatusOK, gin.H{
|
|
"message": false,
|
|
})
|
|
}
|
|
|
|
func main() {
|
|
db = dbcommands.InitializeDatabase()
|
|
config = parseConfig("config.toml")
|
|
oauthConfig = createDiscordOAuthConfig()
|
|
app := gin.Default()
|
|
app.Static("/public", "./public")
|
|
app.GET("/login", loginRedirect)
|
|
app.GET("/auth/callback", authCallback)
|
|
app.GET("/logout", logoutRedirect)
|
|
app.GET("/dashboard", dashboardDisplay)
|
|
app.GET("/authorized", isUserAutorized)
|
|
app.Run(":31337")
|
|
}
|