package auth import ( "context" "encoding/json" "fmt" "hash" "net/http" "time" "acoolname.co/backend/user" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) type Permission int const ( Start Permission = 1 << iota Stop Browse Create Delete RunCommand Admin ) var hmacSampleSecret []byte type Connection struct { connection *mongo.Client } type TokenInfo struct { Username string `json:"username"` Permissions Permission `json:"permissions"` } type AuthClaims struct { *jwt.StandardClaims TokenInfo } func signToken(token TokenInfo) (string, error) { t := jwt.New(jwt.GetSigningMethod("HS512")) t.Claims = &AuthClaims{ &jwt.StandardClaims{ ExpiresAt: time.Now().Add(time.Hour * 24 * 30).Unix(), }, token, } return t.SignedString(hmacSampleSecret) } func AuthorizedTo(requiredPermissions Permission) gin.HandlerFunc { return func(ctx *gin.Context) { fmt.Println("Auth logic starts") authCookie, err := ctx.Request.Cookie("auth") if err != nil { ctx.AbortWithError(403, err) } token, err := jwt.ParseWithClaims(authCookie.Value, &AuthClaims{}, func(token *jwt.Token) (interface{}, error) { // Don't forget to validate the alg is what you expect: if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } // hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key") return hmacSampleSecret, nil }) fmt.Println(token.Claims) if claims, ok := token.Claims.(*AuthClaims); ok && token.Valid { ctx.Set("claims", claims) if requiredPermissions&claims.Permissions != requiredPermissions { ctx.AbortWithStatus(403) } } else { ctx.AbortWithStatus(500) } } } func (con Connection) signUp(c *gin.Context) { var token TokenInfo type SignUpRequest struct { token string username string password string } err := json.NewDecoder(c.Request.Body).Decode(&token) if err != nil { c.AbortWithError(500, err) } signedToken, err := signToken(token) if err != nil { c.AbortWithError(500, err) } c.SetCookie("auth", signedToken, -1, "", "", false, false) c.IndentedJSON(http.StatusOK, signedToken) } type SignInRequest struct { username string password string } func (con Connection) signIn(c *gin.Context) { type signInRequest struct { username string password string } var request signInRequest err := json.NewDecoder(c.Request.Body).Decode(&request) if err != nil { c.AbortWithError(500, err) } var userItem user.User err = con.connection.Database("Backend").Collection("Users").FindOne(context.TODO(), bson.D{{Key: "username", Value: request.username}}).Decode(&userItem) if err != nil { c.AbortWithError(403, err) } if userItem.hashedPass == hash.Hash64() { } signedToken, err := signToken(token) if err != nil { c.AbortWithError(500, err) } c.SetCookie("auth", signedToken, -1, "", "", false, false) c.IndentedJSON(http.StatusOK, signedToken) } func (con Connection) test(c *gin.Context) { claims, exists := c.Get("claims") if !exists { fmt.Println("No Claims") c.AbortWithStatus(403) } c.IndentedJSON(http.StatusOK, claims) } func LoadGroup(group *gin.RouterGroup, client *mongo.Client) { connection := Connection{connection: client} group.POST("/signup", connection.signUp) group.Use(AuthorizedTo(Admin)) { group.GET("/test", connection.test) } }