package api import ( "context" "encoding/json" "fmt" "io" "net/http" "strings" "time" core "fr.latosa-escrima/api/core" "fr.latosa-escrima/utils" "github.com/golang-jwt/jwt/v5" ) var MySigningKey = []byte("COUCOU") type LoginArgs struct { Email string `json:"email"` Password string `json:"password"` } type Claims struct { UserID string `json:"user_id"` jwt.RegisteredClaims } func HandleLogin(w http.ResponseWriter, r *http.Request) { if r.Body == nil { core.JSONError{ Status: core.Error, Message: "No body has been provided.", }.Respond(w, http.StatusNoContent) return } body, err := io.ReadAll(r.Body) if err != nil { core.JSONError{ Status: core.Error, Message: err.Error(), }.Respond(w, http.StatusNoContent) return } var login LoginArgs err = json.Unmarshal(body, &login) if err != nil { core.JSONError{ Status: core.Error, Message: err.Error(), }.Respond(w, http.StatusNoContent) return } user, err := core.Verify(context.Background(), login.Email, login.Password) if user == nil { core.JSONError{ Status: core.Error, Message: "User not found.", }.Respond(w, http.StatusNotFound) return } if err != nil { core.JSONError{ Status: core.Error, Message: err.Error(), }.Respond(w, http.StatusNoContent) return } claims := Claims{ UserID: user.UserID.String(), RegisteredClaims: jwt.RegisteredClaims{ Issuer: "latosa-escrima.fr", Subject: "authentification", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) signed, err := token.SignedString(MySigningKey) if err != nil { core.JSONError{ Status: core.Error, Message: err.Error(), }.Respond(w, http.StatusNoContent) return } core.JSONSuccess{ Status: core.Success, Message: "JWT Created", Data: signed, }.Respond(w, http.StatusCreated) } func AuthJWT(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Check if the Authorization header is provided authHeader := r.Header.Get("Authorization") if authHeader == "" { core.JSONError{ Status: core.Error, Message: "Missing Authorization header", }.Respond(w, http.StatusUnauthorized) return } // Bearer token is expected, so split the header into "Bearer " tokenString := strings.TrimPrefix(authHeader, "Bearer ") if tokenString == authHeader { core.JSONError{ Status: core.Error, Message: "Invalid Authorization header format", }.Respond(w, http.StatusUnauthorized) return } // Parse the token token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // Ensure that the token's signing method is valid if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return MySigningKey, nil }) if err != nil || !token.Valid { core.JSONError{ Status: core.Error, Message: "Invalid Token", }.Respond(w, http.StatusUnauthorized) return } ctx := context.WithValue(r.Context(), "token", token) // Call the next handler if the JWT is valid next.ServeHTTP(w, r.WithContext(ctx)) }) } // @param methods string -> HttpMethods separated by commas. func Methods(methods string) core.Middleware { _methods := strings.Split(strings.ToUpper(methods), ",") middleware := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if len(methods) > 0 { if !utils.Contains(_methods, r.Method) { core.JSONError{ Status: core.Error, Message: "Method is not allowed.", }.Respond(w, http.StatusMethodNotAllowed) return } } next.ServeHTTP(w, r) }) } return middleware }