From 517168dc297acc3c9fa87f84b6f5f6056fbbdf57 Mon Sep 17 00:00:00 2001 From: rick Date: Sun, 9 Oct 2022 02:15:25 +0200 Subject: [PATCH] first files --- .gitignore | 70 ++++++++++++++++ README.md | 17 ++++ dao/connect.go | 28 +++++++ dao/users.go | 113 ++++++++++++++++++++++++++ example.env | 9 +++ go.mod | 54 +++++++++++++ main.go | 203 +++++++++++++++++++++++++++++++++++++++++++++++ models/user.go | 34 ++++++++ views/index.html | 37 +++++++++ 9 files changed, 565 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 dao/connect.go create mode 100644 dao/users.go create mode 100644 example.env create mode 100644 go.mod create mode 100644 main.go create mode 100644 models/user.go create mode 100644 views/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d5ea64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +.env + +# Created by https://www.toptal.com/developers/gitignore/api/vim,go,rust +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,go,rust + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### Go Patch ### +/vendor/ +/Godeps/ + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# End of https://www.toptal.com/developers/gitignore/api/vim,go,rust diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2063aa --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Site CDS + +## Structure du projet + + * .env : fichier de configuration + * views : fichiers html dynamiques + * dao : fichiers pour faire des requetes en BDD + * models : structures utilisées pour manipuler le contenu de la base de données + +## Lancement + +Il faut mettre en place une base de données [MongoDB](https://www.mongodb.com/). +Il est nécessaire d'avoir [une application Discord](https://discord.com/developers/) +et [une clé d'API Steam](https://steamcommunity.com/dev). +Configurez ensuite le fichier `example.env` et renommez le en `.env`. + +Lancez le serveur avec `go run main.go`. diff --git a/dao/connect.go b/dao/connect.go new file mode 100644 index 0000000..7275a8b --- /dev/null +++ b/dao/connect.go @@ -0,0 +1,28 @@ +package dao + +import ( + "context" + "os" + "time" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func get() (db *mongo.Database, err error) { + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + uri := "mongodb://" + os.Getenv("MONGO_USER") + ":" + os.Getenv("MONGO_PWD") + "@" + os.Getenv("MONGO_CLUSTER") + client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri)) + if err != nil { + return nil, err + } + + return client.Database(os.Getenv("MONGO_DB")), nil +} + +func disconnect(client *mongo.Client) { + if err := client.Disconnect(context.TODO()); err != nil { + panic(err) + } +} diff --git a/dao/users.go b/dao/users.go new file mode 100644 index 0000000..cbfe33c --- /dev/null +++ b/dao/users.go @@ -0,0 +1,113 @@ +package dao + +import ( + "cds/models" + "context" + "fmt" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +func GetByDiscord(id string) (user *models.User, err error) { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + var result models.User + err = coll.FindOne(context.TODO(), bson.D{{"userId", id}}).Decode(&result) + if err != nil { + return nil, err + } else { + return &result, nil + } +} + +func GetBySteam(id string) (user *models.User, err error) { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + var result models.User + err = coll.FindOne(context.TODO(), bson.D{{"steamId", id}}).Decode(&result) + if err != nil { + return nil, err + } else { + return &result, nil + } +} + +func GetById(id string) (user *models.User, err error) { + db, _ := get() + objectId, err := primitive.ObjectIDFromHex(id) + defer disconnect(db.Client()) + coll := db.Collection("users") + + var result models.User + err = coll.FindOne(context.TODO(), bson.D{{"_id", objectId}}).Decode(&result) + if err != nil { + return nil, err + } else { + return &result, nil + } +} + +func CreateUser(user *models.User) (id string, err error) { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + idDb, err := coll.InsertOne(context.TODO(), user) + id = fmt.Sprint(idDb.InsertedID) + return id, err +} + +func AddSteam(discord string, steam string) error { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + update := bson.D{{"$set", bson.D{{"steamId", steam}}}} + + var result bson.M + err := coll.FindOneAndUpdate(context.TODO(), bson.D{{"userId", discord}}, update).Decode(&result) + return err +} + +func AddDiscord(steam string, discordId string, discordName string) error { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + update := bson.D{{"$set", bson.D{{"userId", discordId}, {"userName", discordName}}}} + + var result bson.M + err := coll.FindOneAndUpdate(context.TODO(), bson.D{{"steamId", steam}}, update).Decode(&result) + return err +} + +func RemoveSteam(steam string) error { + return nil +} + +func RemoveDiscord(discord string) error { + return nil +} + +func DeleteBySteam(steam string) error { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + _, err := coll.DeleteOne(context.TODO(), bson.D{{"steamId", steam}}) + return err +} + +func DeleteByDiscord(discord string) error { + db, _ := get() + defer disconnect(db.Client()) + coll := db.Collection("users") + + _, err := coll.DeleteOne(context.TODO(), bson.D{{"userId", discord}}) + return err +} diff --git a/example.env b/example.env new file mode 100644 index 0000000..d10c35b --- /dev/null +++ b/example.env @@ -0,0 +1,9 @@ +MONGO_USER: "user" +MONGO_PWD: "123" +MONGO_CLUSTER: "localhost:80800" +MONGO_DB: "db" + +DISCORD_ID: "id" +DISCORD_SECRET: "secret" + +STEAM_KEY: "steam" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5bebf92 --- /dev/null +++ b/go.mod @@ -0,0 +1,54 @@ +module cds + +go 1.19 + +require ( + github.com/gofiber/fiber/v2 v2.38.1 + github.com/gofiber/swagger v0.1.2 + github.com/gofiber/template v1.7.1 + github.com/joho/godotenv v1.4.0 + github.com/markbates/goth v1.73.0 + github.com/shareed2k/goth_fiber v0.2.8 + github.com/swaggo/swag v1.8.5 + go.mongodb.org/mongo-driver v1.10.3 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/sessions v1.1.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.15.0 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.40.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..7f34c41 --- /dev/null +++ b/main.go @@ -0,0 +1,203 @@ +package main + +import ( + "cds/dao" + "cds/models" + "fmt" + "os" + "time" + + _ "cds/docs" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/html" + "github.com/joho/godotenv" + "github.com/markbates/goth" + "github.com/markbates/goth/providers/discord" + "github.com/markbates/goth/providers/steam" + "github.com/shareed2k/goth_fiber" + "go.mongodb.org/mongo-driver/mongo" +) + +//const DISCORD_API = "https://discord.com/api/v10/" + +func setupRoutes(app *fiber.App) { + app.Get("/", index) + + //api := app.Group("/api") + //routes.AccountRoute(api.Group("/accounts")) + //routes.GroupeRoute(api.Group("/groups")) + //app.Get("/swagger/*", swagger.HandlerDefault) + + app.Get("/login/:provider", goth_fiber.BeginAuthHandler) + app.Get("/auth/:provider", auth) +} + +func checkDiscord(c *fiber.Ctx) error { + gothuser, err := goth_fiber.CompleteUserAuth(c) + if err != nil { + print("== ERROR ==") + panic(err) + } + + /* + fmt.Println(gothuser.UserID) + fmt.Println(gothuser.Name) + fmt.Println(gothuser.RawData["discriminator"]) + fmt.Println(gothuser.AccessToken) + */ + + token := c.Cookies("token", "") + fmt.Println("Discord cookie:" + token) + id := gothuser.UserID + name := fmt.Sprint(gothuser.Name, "#", gothuser.RawData["discriminator"]) + + // on vérifie s'il existe déjà dans la db sinon on le créé + user, err := dao.GetByDiscord(id) + if user != nil && token == "" { + cookie := new(fiber.Cookie) + cookie.Name = "token" + cookie.Value = user.Id.Hex() + cookie.Expires = time.Now().Add(24 * time.Hour) + c.Cookie(cookie) + } + + if err == mongo.ErrNoDocuments { + user = models.NewUserDiscord(id, name) + id, err = dao.CreateUser(user) + if err != nil { + fmt.Println(err) + } + + if token == "" { + cookie := new(fiber.Cookie) + cookie.Name = "token" + cookie.Value = id + cookie.Expires = time.Now().Add(24 * time.Hour) + c.Cookie(cookie) + } + } else if err != nil { + fmt.Println(err) + } + + c.Redirect("/") + return nil +} + +func auth(c *fiber.Ctx) error { + provider, err := goth_fiber.GetProviderName(c) + if err != nil { + print("== ERROR ==") + panic(err) + } + + if provider == "discord" { + return checkDiscord(c) + } else if provider == "steam" { + return checkSteam(c) + } + + return nil +} + +func checkSteam(c *fiber.Ctx) error { + token := c.Cookies("token", "") + gothuser, err := goth_fiber.CompleteUserAuth(c) + if err != nil { + print("== ERROR ==") + panic(err) + } + + id := gothuser.UserID + + user, err := dao.GetById(fmt.Sprint(token)) + + if user == nil { + user, err = dao.GetBySteam(id) + if user != nil && token == "" { + cookie := new(fiber.Cookie) + cookie.Name = "token" + cookie.Value = user.Id.Hex() + cookie.Expires = time.Now().Add(24 * time.Hour) + c.Cookie(cookie) + } + + if err == mongo.ErrNoDocuments { + user = models.NewUserSteam(id) + id, err = dao.CreateUser(user) + if err != nil { + fmt.Println(err) + } + + if token == "" { + cookie := new(fiber.Cookie) + cookie.Name = "token" + cookie.Value = id + cookie.Expires = time.Now().Add(24 * time.Hour) + c.Cookie(cookie) + } + } else if err != nil { + fmt.Println(err) + } + } else if user.SteamId == "" { + if user.DiscordId != "" { + dao.AddSteam(user.DiscordId, id) + } + } + + c.Redirect("/") + return nil +} + +func index(c *fiber.Ctx) error { + token := c.Cookies("token", "") + var discord string = "" + var steam string = "" + if token != "" { + user, _ := dao.GetById(fmt.Sprint(token)) + if user != nil { + steam = user.SteamId + discord = user.DiscordName + } + } + + return c.Render("index", fiber.Map{ + "connected": token != "", + "urlDiscord": "/login/discord", + "urlSteam": "/login/steam", + "discordName": discord, + "steamName": steam, + }) +} + +// @title CDS API +// @version 1.0 (alpha) +// @description API du site web de CDS +// @contact.name La super équipe de dev +// @license.name AGPL 3.0 +// @license.url https://www.gnu.org/licenses/agpl-3.0.html +// @host localhost:8080 +// @BasePath /api +func main() { + err := godotenv.Load() + if err != nil { + panic(err) + } + + app := fiber.New(fiber.Config{Views: html.New("./views", ".html")}) + goth.UseProviders( + discord.New( + os.Getenv("DISCORD_ID"), + os.Getenv("DISCORD_SECRET"), + "http://localhost:8080/auth/discord", + discord.ScopeIdentify, discord.ScopeGuilds), + steam.New(os.Getenv("STEAM_KEY"), "http://localhost:8080/auth/steam"), + ) + + setupRoutes(app) + + err = app.Listen(":8080") + if err != nil { + panic(err) + } +} diff --git a/models/user.go b/models/user.go new file mode 100644 index 0000000..6dffe04 --- /dev/null +++ b/models/user.go @@ -0,0 +1,34 @@ +package models + +import "go.mongodb.org/mongo-driver/bson/primitive" + +type User struct { + Id primitive.ObjectID `bson:"_id", omitempty` + Banned bool `bson:banned` + BlackLister bool `bson:"blacklisted"` + Experience uint `bson:"experience"` + //LastBuy string `bson:"lastBuy,omitempty"` + Level uint `bson:"level"` + Money uint `bson:"money"` + MoneyLimit uint `bson:"moneyLimit"` + DiscordId string `bson:"userId,omitempty"` + SteamId string `bson:"steamId,omitempty"` + DiscordName string `bson:"username,omitempty"` +} + +func NewUser() *User { + return &User{primitive.NewObjectID(), false, false, 0, 0, 0, 0, "", "", ""} +} + +func NewUserDiscord(id string, name string) *User { + ret := NewUser() + ret.DiscordId = id + ret.DiscordName = name + return ret +} + +func NewUserSteam(id string) *User { + ret := NewUser() + ret.SteamId = id + return ret +} diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..bbb596f --- /dev/null +++ b/views/index.html @@ -0,0 +1,37 @@ + + + + + +

Chasseurs De Succès

+

Site pour mieux réunir les chasseurs de succès sur les jeux multijoueurs

+
+ + {{ if .error }} +
+

Erreur rencontrée: {{.error}}

+
+ {{ end }} + + {{if .connected}} +
+

Bienvenue !!

+

Connexions actives :

+ {{ if .discordName }} +

Discord : {{ .discordName }}

+ {{ else }} + SE CONNECTER VIA DISCORD ICI + {{ end }} + + {{ if .steamName }} +

Steam : {{ .steamName }}

+ {{ else }} + SE CONNECTER VIA STEAM ICI + {{ end }} +
+ {{else}} + SE CONNECTER VIA DISCORD ICI + SE CONNECTER VIA STEAM ICI + {{end}} + +