diff --git a/Dockerfiles/Dockerfile_auth b/Dockerfiles/Dockerfile_auth deleted file mode 100644 index 5280e86..0000000 --- a/Dockerfiles/Dockerfile_auth +++ /dev/null @@ -1,6 +0,0 @@ -FROM ubuntu:22.04 - -WORKDIR /app -COPY --chmod=755 modules/auth/auth /app -EXPOSE 8082 -ENTRYPOINT ["/app/auth"] \ No newline at end of file diff --git a/auth/auth.gen.go b/auth/auth.gen.go deleted file mode 100644 index adb2b06..0000000 --- a/auth/auth.gen.go +++ /dev/null @@ -1,249 +0,0 @@ -// Package auth provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. -package auth - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin" -) - -// PostAuthSignInJSONBody defines parameters for PostAuthSignIn. -type PostAuthSignInJSONBody struct { - Nickname string `json:"nickname"` - Pass string `json:"pass"` -} - -// PostAuthSignUpJSONBody defines parameters for PostAuthSignUp. -type PostAuthSignUpJSONBody struct { - Nickname string `json:"nickname"` - Pass string `json:"pass"` -} - -// PostAuthSignInJSONRequestBody defines body for PostAuthSignIn for application/json ContentType. -type PostAuthSignInJSONRequestBody PostAuthSignInJSONBody - -// PostAuthSignUpJSONRequestBody defines body for PostAuthSignUp for application/json ContentType. -type PostAuthSignUpJSONRequestBody PostAuthSignUpJSONBody - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Sign in a user and return JWT - // (POST /auth/sign-in) - PostAuthSignIn(c *gin.Context) - // Sign up a new user - // (POST /auth/sign-up) - PostAuthSignUp(c *gin.Context) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// PostAuthSignIn operation middleware -func (siw *ServerInterfaceWrapper) PostAuthSignIn(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostAuthSignIn(c) -} - -// PostAuthSignUp operation middleware -func (siw *ServerInterfaceWrapper) PostAuthSignUp(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostAuthSignUp(c) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.POST(options.BaseURL+"/auth/sign-in", wrapper.PostAuthSignIn) - router.POST(options.BaseURL+"/auth/sign-up", wrapper.PostAuthSignUp) -} - -type PostAuthSignInRequestObject struct { - Body *PostAuthSignInJSONRequestBody -} - -type PostAuthSignInResponseObject interface { - VisitPostAuthSignInResponse(w http.ResponseWriter) error -} - -type PostAuthSignIn200JSONResponse struct { - Error *string `json:"error"` - Success *bool `json:"success,omitempty"` - UserId *string `json:"user_id"` -} - -func (response PostAuthSignIn200JSONResponse) VisitPostAuthSignInResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -type PostAuthSignIn401JSONResponse struct { - Error *string `json:"error,omitempty"` -} - -func (response PostAuthSignIn401JSONResponse) VisitPostAuthSignInResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(401) - - return json.NewEncoder(w).Encode(response) -} - -type PostAuthSignUpRequestObject struct { - Body *PostAuthSignUpJSONRequestBody -} - -type PostAuthSignUpResponseObject interface { - VisitPostAuthSignUpResponse(w http.ResponseWriter) error -} - -type PostAuthSignUp200JSONResponse struct { - Error *string `json:"error"` - Success *bool `json:"success,omitempty"` - UserId *string `json:"user_id"` -} - -func (response PostAuthSignUp200JSONResponse) VisitPostAuthSignUpResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -// StrictServerInterface represents all server handlers. -type StrictServerInterface interface { - // Sign in a user and return JWT - // (POST /auth/sign-in) - PostAuthSignIn(ctx context.Context, request PostAuthSignInRequestObject) (PostAuthSignInResponseObject, error) - // Sign up a new user - // (POST /auth/sign-up) - PostAuthSignUp(ctx context.Context, request PostAuthSignUpRequestObject) (PostAuthSignUpResponseObject, error) -} - -type StrictHandlerFunc = strictgin.StrictGinHandlerFunc -type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc - -func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { - return &strictHandler{ssi: ssi, middlewares: middlewares} -} - -type strictHandler struct { - ssi StrictServerInterface - middlewares []StrictMiddlewareFunc -} - -// PostAuthSignIn operation middleware -func (sh *strictHandler) PostAuthSignIn(ctx *gin.Context) { - var request PostAuthSignInRequestObject - - var body PostAuthSignInJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostAuthSignIn(ctx, request.(PostAuthSignInRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostAuthSignIn") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostAuthSignInResponseObject); ok { - if err := validResponse.VisitPostAuthSignInResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} - -// PostAuthSignUp operation middleware -func (sh *strictHandler) PostAuthSignUp(ctx *gin.Context) { - var request PostAuthSignUpRequestObject - - var body PostAuthSignUpJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostAuthSignUp(ctx, request.(PostAuthSignUpRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostAuthSignUp") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostAuthSignUpResponseObject); ok { - if err := validResponse.VisitPostAuthSignUpResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} diff --git a/auth/auth/auth.gen.go b/auth/auth/auth.gen.go deleted file mode 100644 index 12b6622..0000000 --- a/auth/auth/auth.gen.go +++ /dev/null @@ -1,329 +0,0 @@ -// Package oapi_auth provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT. -package oapi_auth - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin" -) - -// PostAuthSignInJSONBody defines parameters for PostAuthSignIn. -type PostAuthSignInJSONBody struct { - Nickname string `json:"nickname"` - Pass string `json:"pass"` -} - -// PostAuthSignUpJSONBody defines parameters for PostAuthSignUp. -type PostAuthSignUpJSONBody struct { - Nickname string `json:"nickname"` - Pass string `json:"pass"` -} - -// PostAuthVerifyTokenJSONBody defines parameters for PostAuthVerifyToken. -type PostAuthVerifyTokenJSONBody struct { - // Token JWT token to validate - Token string `json:"token"` -} - -// PostAuthSignInJSONRequestBody defines body for PostAuthSignIn for application/json ContentType. -type PostAuthSignInJSONRequestBody PostAuthSignInJSONBody - -// PostAuthSignUpJSONRequestBody defines body for PostAuthSignUp for application/json ContentType. -type PostAuthSignUpJSONRequestBody PostAuthSignUpJSONBody - -// PostAuthVerifyTokenJSONRequestBody defines body for PostAuthVerifyToken for application/json ContentType. -type PostAuthVerifyTokenJSONRequestBody PostAuthVerifyTokenJSONBody - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Sign in a user and return JWT - // (POST /auth/sign-in) - PostAuthSignIn(c *gin.Context) - // Sign up a new user - // (POST /auth/sign-up) - PostAuthSignUp(c *gin.Context) - // Verify JWT validity - // (POST /auth/verify-token) - PostAuthVerifyToken(c *gin.Context) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// PostAuthSignIn operation middleware -func (siw *ServerInterfaceWrapper) PostAuthSignIn(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostAuthSignIn(c) -} - -// PostAuthSignUp operation middleware -func (siw *ServerInterfaceWrapper) PostAuthSignUp(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostAuthSignUp(c) -} - -// PostAuthVerifyToken operation middleware -func (siw *ServerInterfaceWrapper) PostAuthVerifyToken(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostAuthVerifyToken(c) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.POST(options.BaseURL+"/auth/sign-in", wrapper.PostAuthSignIn) - router.POST(options.BaseURL+"/auth/sign-up", wrapper.PostAuthSignUp) - router.POST(options.BaseURL+"/auth/verify-token", wrapper.PostAuthVerifyToken) -} - -type PostAuthSignInRequestObject struct { - Body *PostAuthSignInJSONRequestBody -} - -type PostAuthSignInResponseObject interface { - VisitPostAuthSignInResponse(w http.ResponseWriter) error -} - -type PostAuthSignIn200JSONResponse struct { - Error *string `json:"error"` - Success *bool `json:"success,omitempty"` - - // Token JWT token to access protected endpoints - Token *string `json:"token"` - UserId *string `json:"user_id"` -} - -func (response PostAuthSignIn200JSONResponse) VisitPostAuthSignInResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -type PostAuthSignUpRequestObject struct { - Body *PostAuthSignUpJSONRequestBody -} - -type PostAuthSignUpResponseObject interface { - VisitPostAuthSignUpResponse(w http.ResponseWriter) error -} - -type PostAuthSignUp200JSONResponse struct { - Error *string `json:"error"` - Success *bool `json:"success,omitempty"` - UserId *string `json:"user_id"` -} - -func (response PostAuthSignUp200JSONResponse) VisitPostAuthSignUpResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -type PostAuthVerifyTokenRequestObject struct { - Body *PostAuthVerifyTokenJSONRequestBody -} - -type PostAuthVerifyTokenResponseObject interface { - VisitPostAuthVerifyTokenResponse(w http.ResponseWriter) error -} - -type PostAuthVerifyToken200JSONResponse struct { - // Error Error message if token is invalid - Error *string `json:"error"` - - // UserId User ID extracted from token if valid - UserId *string `json:"user_id"` - - // Valid True if token is valid - Valid *bool `json:"valid,omitempty"` -} - -func (response PostAuthVerifyToken200JSONResponse) VisitPostAuthVerifyTokenResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -// StrictServerInterface represents all server handlers. -type StrictServerInterface interface { - // Sign in a user and return JWT - // (POST /auth/sign-in) - PostAuthSignIn(ctx context.Context, request PostAuthSignInRequestObject) (PostAuthSignInResponseObject, error) - // Sign up a new user - // (POST /auth/sign-up) - PostAuthSignUp(ctx context.Context, request PostAuthSignUpRequestObject) (PostAuthSignUpResponseObject, error) - // Verify JWT validity - // (POST /auth/verify-token) - PostAuthVerifyToken(ctx context.Context, request PostAuthVerifyTokenRequestObject) (PostAuthVerifyTokenResponseObject, error) -} - -type StrictHandlerFunc = strictgin.StrictGinHandlerFunc -type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc - -func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { - return &strictHandler{ssi: ssi, middlewares: middlewares} -} - -type strictHandler struct { - ssi StrictServerInterface - middlewares []StrictMiddlewareFunc -} - -// PostAuthSignIn operation middleware -func (sh *strictHandler) PostAuthSignIn(ctx *gin.Context) { - var request PostAuthSignInRequestObject - - var body PostAuthSignInJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostAuthSignIn(ctx, request.(PostAuthSignInRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostAuthSignIn") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostAuthSignInResponseObject); ok { - if err := validResponse.VisitPostAuthSignInResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} - -// PostAuthSignUp operation middleware -func (sh *strictHandler) PostAuthSignUp(ctx *gin.Context) { - var request PostAuthSignUpRequestObject - - var body PostAuthSignUpJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostAuthSignUp(ctx, request.(PostAuthSignUpRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostAuthSignUp") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostAuthSignUpResponseObject); ok { - if err := validResponse.VisitPostAuthSignUpResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} - -// PostAuthVerifyToken operation middleware -func (sh *strictHandler) PostAuthVerifyToken(ctx *gin.Context) { - var request PostAuthVerifyTokenRequestObject - - var body PostAuthVerifyTokenJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostAuthVerifyToken(ctx, request.(PostAuthVerifyTokenRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostAuthVerifyToken") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostAuthVerifyTokenResponseObject); ok { - if err := validResponse.VisitPostAuthVerifyTokenResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} diff --git a/auth/oapi-auth-codegen.yaml b/auth/oapi-auth-codegen.yaml deleted file mode 100644 index 6792391..0000000 --- a/auth/oapi-auth-codegen.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: auth -generate: - strict-server: true - gin-server: true - models: true -output: auth/auth.gen.go \ No newline at end of file diff --git a/auth/openapi-auth.yaml b/auth/openapi-auth.yaml deleted file mode 100644 index 913c000..0000000 --- a/auth/openapi-auth.yaml +++ /dev/null @@ -1,170 +0,0 @@ -openapi: 3.1.1 -info: - title: Auth Service - version: 1.0.0 - -servers: - - url: /auth - -paths: - /auth/sign-up: - post: - summary: Sign up a new user - tags: [Auth] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [nickname, pass] - properties: - nickname: - type: string - pass: - type: string - format: password - responses: - "200": - description: Sign-up result - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - error: - type: string - nullable: true - user_id: - type: string - nullable: true - - /auth/sign-in: - post: - summary: Sign in a user and return JWT - tags: [Auth] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [nickname, pass] - properties: - nickname: - type: string - pass: - type: string - format: password - responses: - "200": - description: Sign-in result with JWT - # headers: - # Set-Cookie: - # schema: - # type: array - # items: - # type: string - # explode: true - # style: simple - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - error: - type: string - nullable: true - user_id: - type: string - nullable: true - "401": - description: Access denied due to invalid credentials - content: - application/json: - schema: - type: object - properties: - error: - type: string - example: "Access denied" - # /auth/verify-token: - # post: - # summary: Verify JWT validity - # tags: [Auth] - # requestBody: - # required: true - # content: - # application/json: - # schema: - # type: object - # required: [token] - # properties: - # token: - # type: string - # description: JWT token to validate - # responses: - # "200": - # description: Token validation result - # content: - # application/json: - # schema: - # type: object - # properties: - # valid: - # type: boolean - # description: True if token is valid - # user_id: - # type: string - # nullable: true - # description: User ID extracted from token if valid - # error: - # type: string - # nullable: true - # description: Error message if token is invalid - # /auth/refresh-token: - # post: - # summary: Refresh JWT using a refresh token - # tags: [Auth] - # requestBody: - # required: true - # content: - # application/json: - # schema: - # type: object - # required: [refresh_token] - # properties: - # refresh_token: - # type: string - # description: JWT refresh token obtained from sign-in - # responses: - # "200": - # description: New access (and optionally refresh) token - # content: - # application/json: - # schema: - # type: object - # properties: - # valid: - # type: boolean - # description: True if refresh token was valid - # user_id: - # type: string - # nullable: true - # description: User ID extracted from refresh token - # access_token: - # type: string - # description: New access token - # nullable: true - # refresh_token: - # type: string - # description: New refresh token (optional) - # nullable: true - # error: - # type: string - # nullable: true - # description: Error message if refresh token is invalid diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 7f53da5..1a96253 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -37,18 +37,6 @@ services: - "8080:8080" depends_on: - postgres - - nyanimedb-auth: - image: meowgit.nekoea.red/nihonium/nyanimedb-auth:latest - container_name: nyanimedb-auth - restart: always - environment: - LOG_LEVEL: ${LOG_LEVEL} - DATABASE_URL: ${DATABASE_URL} - ports: - - "8082:8082" - depends_on: - - postgres nyanimedb-frontend: image: meowgit.nekoea.red/nihonium/nyanimedb-frontend:latest diff --git a/deploy/generate.sh b/deploy/generate.sh index 29587cf..d7d94a2 100644 --- a/deploy/generate.sh +++ b/deploy/generate.sh @@ -1,3 +1,3 @@ -npx openapi-typescript-codegen --input ..\..\api\openapi.yaml --output ./src/api --client axios --useUnionTypes +npx openapi-typescript-codegen --input ..\..\api\openapi.yaml --output ./src/api --client axios oapi-codegen --config=api/oapi-codegen.yaml .\api\openapi.yaml sqlc generate -f .\sql\sqlc.yaml \ No newline at end of file diff --git a/go.mod b/go.mod index bf73121..80a9ab1 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.25.0 require ( github.com/gin-contrib/cors v1.7.6 github.com/gin-gonic/gin v1.11.0 - github.com/golang-jwt/jwt/v5 v5.3.0 github.com/jackc/pgx/v5 v5.7.6 github.com/oapi-codegen/runtime v1.1.2 github.com/pelletier/go-toml/v2 v2.2.4 diff --git a/go.sum b/go.sum index 8f46514..121ca40 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,6 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/modules/auth/handlers/handlers.go b/modules/auth/handlers/handlers.go deleted file mode 100644 index 9b9b0d3..0000000 --- a/modules/auth/handlers/handlers.go +++ /dev/null @@ -1,197 +0,0 @@ -package handlers - -import ( - "context" - "fmt" - "log" - "net/http" - auth "nyanimedb/auth" - sqlc "nyanimedb/sql" - "strconv" - "time" - - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v5" -) - -var accessSecret = []byte("my_access_secret_key") -var refreshSecret = []byte("my_refresh_secret_key") - -var UserDb = make(map[string]string) // TEMP: stores passwords - -type Server struct { - db *sqlc.Queries -} - -func NewServer(db *sqlc.Queries) Server { - return Server{db: db} -} - -func parseInt64(s string) (int32, error) { - i, err := strconv.ParseInt(s, 10, 64) - return int32(i), err -} - -func generateTokens(userID string) (accessToken string, refreshToken string, err error) { - accessClaims := jwt.MapClaims{ - "user_id": userID, - "exp": time.Now().Add(15 * time.Minute).Unix(), - } - at := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims) - accessToken, err = at.SignedString(accessSecret) - if err != nil { - return "", "", err - } - - refreshClaims := jwt.MapClaims{ - "user_id": userID, - "exp": time.Now().Add(7 * 24 * time.Hour).Unix(), - } - rt := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims) - refreshToken, err = rt.SignedString(refreshSecret) - if err != nil { - return "", "", err - } - - return accessToken, refreshToken, nil -} - -func (s Server) PostAuthSignUp(ctx context.Context, req auth.PostAuthSignUpRequestObject) (auth.PostAuthSignUpResponseObject, error) { - err := "" - success := true - UserDb[req.Body.Nickname] = req.Body.Pass - - return auth.PostAuthSignUp200JSONResponse{ - Error: &err, - Success: &success, - UserId: &req.Body.Nickname, - }, nil -} - -func (s Server) PostAuthSignIn(ctx context.Context, req auth.PostAuthSignInRequestObject) (auth.PostAuthSignInResponseObject, error) { - // ctx.SetCookie("122") - ginCtx, ok := ctx.Value(gin.ContextKey).(*gin.Context) - if !ok { - log.Print("failed to get gin context") - // TODO: change to 500 - return auth.PostAuthSignIn200JSONResponse{}, fmt.Errorf("failed to get gin.Context from context.Context") - } - - err := "" - success := true - - pass, ok := UserDb[req.Body.Nickname] - if !ok || pass != req.Body.Pass { - e := "invalid credentials" - return auth.PostAuthSignIn401JSONResponse{ - Error: &e, - }, nil - } - - accessToken, refreshToken, _ := generateTokens(req.Body.Nickname) - - ginCtx.SetSameSite(http.SameSiteStrictMode) - ginCtx.SetCookie("access_token", accessToken, 604800, "/auth", "", true, true) - ginCtx.SetCookie("refresh_token", refreshToken, 604800, "/api", "", true, true) - - // Return access token; refresh token can be returned in response or HttpOnly cookie - result := auth.PostAuthSignIn200JSONResponse{ - Error: &err, - Success: &success, - UserId: &req.Body.Nickname, - } - return result, nil -} - -// func (s Server) PostAuthVerifyToken(ctx context.Context, req auth.PostAuthVerifyTokenRequestObject) (auth.PostAuthVerifyTokenResponseObject, error) { -// valid := false -// var userID *string -// var errStr *string - -// token, err := jwt.Parse(req.Body.Token, func(t *jwt.Token) (interface{}, error) { -// if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { -// return nil, fmt.Errorf("unexpected signing method") -// } -// return accessSecret, nil -// }) - -// if err != nil { -// e := err.Error() -// errStr = &e -// return auth.PostAuthVerifyToken200JSONResponse{ -// Valid: &valid, -// UserId: userID, -// Error: errStr, -// }, nil -// } - -// if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { -// if uid, ok := claims["user_id"].(string); ok { -// valid = true -// userID = &uid -// } else { -// e := "user_id not found in token" -// errStr = &e -// } -// } else { -// e := "invalid token claims" -// errStr = &e -// } - -// return auth.PostAuthVerifyToken200JSONResponse{ -// Valid: &valid, -// UserId: userID, -// Error: errStr, -// }, nil -// } - -// func (s Server) PostAuthRefreshToken(ctx context.Context, req auth.PostAuthRefreshTokenRequestObject) (auth.PostAuthRefreshTokenResponseObject, error) { -// valid := false -// var userID *string -// var errStr *string - -// token, err := jwt.Parse(req.Body.Token, func(t *jwt.Token) (interface{}, error) { -// if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { -// return nil, fmt.Errorf("unexpected signing method") -// } -// return refreshSecret, nil -// }) - -// if err != nil { -// e := err.Error() -// errStr = &e -// return auth.PostAuthVerifyToken200JSONResponse{ -// Valid: &valid, -// UserId: userID, -// Error: errStr, -// }, nil -// } - -// if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { -// if uid, ok := claims["user_id"].(string); ok { -// // Refresh token is valid, generate new tokens -// newAccessToken, newRefreshToken, _ := generateTokens(uid) -// valid = true -// userID = &uid -// return auth.PostAuthVerifyToken200JSONResponse{ -// Valid: &valid, -// UserId: userID, -// Error: nil, -// Token: &newAccessToken, // return new access token -// // optionally return newRefreshToken as well -// }, nil -// } else { -// e := "user_id not found in refresh token" -// errStr = &e -// } -// } else { -// e := "invalid refresh token claims" -// errStr = &e -// } - -// return auth.PostAuthVerifyToken200JSONResponse{ -// Valid: &valid, -// UserId: userID, -// Error: errStr, -// }, nil -// } diff --git a/modules/auth/main.go b/modules/auth/main.go deleted file mode 100644 index c001e8b..0000000 --- a/modules/auth/main.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import ( - "time" - - auth "nyanimedb/auth" - handlers "nyanimedb/modules/auth/handlers" - sqlc "nyanimedb/sql" - - "github.com/gin-contrib/cors" - "github.com/gin-gonic/gin" -) - -var AppConfig Config - -func main() { - r := gin.Default() - - var queries *sqlc.Queries = nil - - server := handlers.NewServer(queries) - - r.Use(cors.New(cors.Config{ - AllowOrigins: []string{"*"}, // allow all origins, change to specific domains in production - AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, - AllowHeaders: []string{"Origin", "Content-Type", "Accept"}, - ExposeHeaders: []string{"Content-Length"}, - AllowCredentials: true, - MaxAge: 12 * time.Hour, - })) - - auth.RegisterHandlers(r, auth.NewStrictHandler( - server, - []auth.StrictMiddlewareFunc{}, - )) - - r.Run(":8082") -} diff --git a/modules/auth/types.go b/modules/auth/types.go deleted file mode 100644 index 038b179..0000000 --- a/modules/auth/types.go +++ /dev/null @@ -1,6 +0,0 @@ -package main - -type Config struct { - JwtPrivateKey string - LogLevel string `toml:"LogLevel" env:"LOG_LEVEL"` -} diff --git a/modules/frontend/nginx-default.conf b/modules/frontend/nginx-default.conf index c3a851f..a538968 100644 --- a/modules/frontend/nginx-default.conf +++ b/modules/frontend/nginx-default.conf @@ -19,15 +19,6 @@ server { proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } - location /auth/ { - rewrite ^/auth/(.*)$ /$1 break; - proxy_pass http://nyanimedb-auth:8082/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - } #error_page 404 /404.html; error_page 500 502 503 504 /50x.html; diff --git a/modules/frontend/src/App.tsx b/modules/frontend/src/App.tsx index 5a25313..909ad6c 100644 --- a/modules/frontend/src/App.tsx +++ b/modules/frontend/src/App.tsx @@ -2,7 +2,6 @@ import React from "react"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import UserPage from "./pages/UserPage/UserPage"; import TitlesPage from "./pages/TitlesPage/TitlesPage"; -import { LoginPage } from "./pages/LoginPage/LoginPage"; import { Header } from "./components/Header/Header"; const App: React.FC = () => { @@ -11,8 +10,6 @@ const App: React.FC = () => {
- } /> {/* <-- маршрут для логина */} - } /> {/* <-- можно использовать тот же компонент для регистрации */} } /> } /> diff --git a/modules/frontend/src/api/core/OpenAPI.ts b/modules/frontend/src/api/core/OpenAPI.ts index 6ce873e..185e5c3 100644 --- a/modules/frontend/src/api/core/OpenAPI.ts +++ b/modules/frontend/src/api/core/OpenAPI.ts @@ -20,7 +20,7 @@ export type OpenAPIConfig = { }; export const OpenAPI: OpenAPIConfig = { - BASE: 'http://10.1.0.65:8081/api/v1', + BASE: '/api/v1', VERSION: '1.0.0', WITH_CREDENTIALS: false, CREDENTIALS: 'include', diff --git a/modules/frontend/src/auth/core/ApiError.ts b/modules/frontend/src/auth/core/ApiError.ts deleted file mode 100644 index ec7b16a..0000000 --- a/modules/frontend/src/auth/core/ApiError.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; -import type { ApiResult } from './ApiResult'; - -export class ApiError extends Error { - public readonly url: string; - public readonly status: number; - public readonly statusText: string; - public readonly body: any; - public readonly request: ApiRequestOptions; - - constructor(request: ApiRequestOptions, response: ApiResult, message: string) { - super(message); - - this.name = 'ApiError'; - this.url = response.url; - this.status = response.status; - this.statusText = response.statusText; - this.body = response.body; - this.request = request; - } -} diff --git a/modules/frontend/src/auth/core/ApiRequestOptions.ts b/modules/frontend/src/auth/core/ApiRequestOptions.ts deleted file mode 100644 index 93143c3..0000000 --- a/modules/frontend/src/auth/core/ApiRequestOptions.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type ApiRequestOptions = { - readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'; - readonly url: string; - readonly path?: Record; - readonly cookies?: Record; - readonly headers?: Record; - readonly query?: Record; - readonly formData?: Record; - readonly body?: any; - readonly mediaType?: string; - readonly responseHeader?: string; - readonly errors?: Record; -}; diff --git a/modules/frontend/src/auth/core/ApiResult.ts b/modules/frontend/src/auth/core/ApiResult.ts deleted file mode 100644 index ee1126e..0000000 --- a/modules/frontend/src/auth/core/ApiResult.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type ApiResult = { - readonly url: string; - readonly ok: boolean; - readonly status: number; - readonly statusText: string; - readonly body: any; -}; diff --git a/modules/frontend/src/auth/core/CancelablePromise.ts b/modules/frontend/src/auth/core/CancelablePromise.ts deleted file mode 100644 index d70de92..0000000 --- a/modules/frontend/src/auth/core/CancelablePromise.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export class CancelError extends Error { - - constructor(message: string) { - super(message); - this.name = 'CancelError'; - } - - public get isCancelled(): boolean { - return true; - } -} - -export interface OnCancel { - readonly isResolved: boolean; - readonly isRejected: boolean; - readonly isCancelled: boolean; - - (cancelHandler: () => void): void; -} - -export class CancelablePromise implements Promise { - #isResolved: boolean; - #isRejected: boolean; - #isCancelled: boolean; - readonly #cancelHandlers: (() => void)[]; - readonly #promise: Promise; - #resolve?: (value: T | PromiseLike) => void; - #reject?: (reason?: any) => void; - - constructor( - executor: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: any) => void, - onCancel: OnCancel - ) => void - ) { - this.#isResolved = false; - this.#isRejected = false; - this.#isCancelled = false; - this.#cancelHandlers = []; - this.#promise = new Promise((resolve, reject) => { - this.#resolve = resolve; - this.#reject = reject; - - const onResolve = (value: T | PromiseLike): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isResolved = true; - if (this.#resolve) this.#resolve(value); - }; - - const onReject = (reason?: any): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isRejected = true; - if (this.#reject) this.#reject(reason); - }; - - const onCancel = (cancelHandler: () => void): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#cancelHandlers.push(cancelHandler); - }; - - Object.defineProperty(onCancel, 'isResolved', { - get: (): boolean => this.#isResolved, - }); - - Object.defineProperty(onCancel, 'isRejected', { - get: (): boolean => this.#isRejected, - }); - - Object.defineProperty(onCancel, 'isCancelled', { - get: (): boolean => this.#isCancelled, - }); - - return executor(onResolve, onReject, onCancel as OnCancel); - }); - } - - get [Symbol.toStringTag]() { - return "Cancellable Promise"; - } - - public then( - onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null, - onRejected?: ((reason: any) => TResult2 | PromiseLike) | null - ): Promise { - return this.#promise.then(onFulfilled, onRejected); - } - - public catch( - onRejected?: ((reason: any) => TResult | PromiseLike) | null - ): Promise { - return this.#promise.catch(onRejected); - } - - public finally(onFinally?: (() => void) | null): Promise { - return this.#promise.finally(onFinally); - } - - public cancel(): void { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isCancelled = true; - if (this.#cancelHandlers.length) { - try { - for (const cancelHandler of this.#cancelHandlers) { - cancelHandler(); - } - } catch (error) { - console.warn('Cancellation threw an error', error); - return; - } - } - this.#cancelHandlers.length = 0; - if (this.#reject) this.#reject(new CancelError('Request aborted')); - } - - public get isCancelled(): boolean { - return this.#isCancelled; - } -} diff --git a/modules/frontend/src/auth/core/OpenAPI.ts b/modules/frontend/src/auth/core/OpenAPI.ts deleted file mode 100644 index 2d0edf8..0000000 --- a/modules/frontend/src/auth/core/OpenAPI.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; - -type Resolver = (options: ApiRequestOptions) => Promise; -type Headers = Record; - -export type OpenAPIConfig = { - BASE: string; - VERSION: string; - WITH_CREDENTIALS: boolean; - CREDENTIALS: 'include' | 'omit' | 'same-origin'; - TOKEN?: string | Resolver | undefined; - USERNAME?: string | Resolver | undefined; - PASSWORD?: string | Resolver | undefined; - HEADERS?: Headers | Resolver | undefined; - ENCODE_PATH?: ((path: string) => string) | undefined; -}; - -export const OpenAPI: OpenAPIConfig = { - BASE: '/auth', - VERSION: '1.0.0', - WITH_CREDENTIALS: false, - CREDENTIALS: 'include', - TOKEN: undefined, - USERNAME: undefined, - PASSWORD: undefined, - HEADERS: undefined, - ENCODE_PATH: undefined, -}; diff --git a/modules/frontend/src/auth/core/request.ts b/modules/frontend/src/auth/core/request.ts deleted file mode 100644 index 1dc6fef..0000000 --- a/modules/frontend/src/auth/core/request.ts +++ /dev/null @@ -1,323 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import axios from 'axios'; -import type { AxiosError, AxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios'; -import FormData from 'form-data'; - -import { ApiError } from './ApiError'; -import type { ApiRequestOptions } from './ApiRequestOptions'; -import type { ApiResult } from './ApiResult'; -import { CancelablePromise } from './CancelablePromise'; -import type { OnCancel } from './CancelablePromise'; -import type { OpenAPIConfig } from './OpenAPI'; - -export const isDefined = (value: T | null | undefined): value is Exclude => { - return value !== undefined && value !== null; -}; - -export const isString = (value: any): value is string => { - return typeof value === 'string'; -}; - -export const isStringWithValue = (value: any): value is string => { - return isString(value) && value !== ''; -}; - -export const isBlob = (value: any): value is Blob => { - return ( - typeof value === 'object' && - typeof value.type === 'string' && - typeof value.stream === 'function' && - typeof value.arrayBuffer === 'function' && - typeof value.constructor === 'function' && - typeof value.constructor.name === 'string' && - /^(Blob|File)$/.test(value.constructor.name) && - /^(Blob|File)$/.test(value[Symbol.toStringTag]) - ); -}; - -export const isFormData = (value: any): value is FormData => { - return value instanceof FormData; -}; - -export const isSuccess = (status: number): boolean => { - return status >= 200 && status < 300; -}; - -export const base64 = (str: string): string => { - try { - return btoa(str); - } catch (err) { - // @ts-ignore - return Buffer.from(str).toString('base64'); - } -}; - -export const getQueryString = (params: Record): string => { - const qs: string[] = []; - - const append = (key: string, value: any) => { - qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`); - }; - - const process = (key: string, value: any) => { - if (isDefined(value)) { - if (Array.isArray(value)) { - value.forEach(v => { - process(key, v); - }); - } else if (typeof value === 'object') { - Object.entries(value).forEach(([k, v]) => { - process(`${key}[${k}]`, v); - }); - } else { - append(key, value); - } - } - }; - - Object.entries(params).forEach(([key, value]) => { - process(key, value); - }); - - if (qs.length > 0) { - return `?${qs.join('&')}`; - } - - return ''; -}; - -const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { - const encoder = config.ENCODE_PATH || encodeURI; - - const path = options.url - .replace('{api-version}', config.VERSION) - .replace(/{(.*?)}/g, (substring: string, group: string) => { - if (options.path?.hasOwnProperty(group)) { - return encoder(String(options.path[group])); - } - return substring; - }); - - const url = `${config.BASE}${path}`; - if (options.query) { - return `${url}${getQueryString(options.query)}`; - } - return url; -}; - -export const getFormData = (options: ApiRequestOptions): FormData | undefined => { - if (options.formData) { - const formData = new FormData(); - - const process = (key: string, value: any) => { - if (isString(value) || isBlob(value)) { - formData.append(key, value); - } else { - formData.append(key, JSON.stringify(value)); - } - }; - - Object.entries(options.formData) - .filter(([_, value]) => isDefined(value)) - .forEach(([key, value]) => { - if (Array.isArray(value)) { - value.forEach(v => process(key, v)); - } else { - process(key, value); - } - }); - - return formData; - } - return undefined; -}; - -type Resolver = (options: ApiRequestOptions) => Promise; - -export const resolve = async (options: ApiRequestOptions, resolver?: T | Resolver): Promise => { - if (typeof resolver === 'function') { - return (resolver as Resolver)(options); - } - return resolver; -}; - -export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions, formData?: FormData): Promise> => { - const [token, username, password, additionalHeaders] = await Promise.all([ - resolve(options, config.TOKEN), - resolve(options, config.USERNAME), - resolve(options, config.PASSWORD), - resolve(options, config.HEADERS), - ]); - - const formHeaders = typeof formData?.getHeaders === 'function' && formData?.getHeaders() || {} - - const headers = Object.entries({ - Accept: 'application/json', - ...additionalHeaders, - ...options.headers, - ...formHeaders, - }) - .filter(([_, value]) => isDefined(value)) - .reduce((headers, [key, value]) => ({ - ...headers, - [key]: String(value), - }), {} as Record); - - if (isStringWithValue(token)) { - headers['Authorization'] = `Bearer ${token}`; - } - - if (isStringWithValue(username) && isStringWithValue(password)) { - const credentials = base64(`${username}:${password}`); - headers['Authorization'] = `Basic ${credentials}`; - } - - if (options.body !== undefined) { - if (options.mediaType) { - headers['Content-Type'] = options.mediaType; - } else if (isBlob(options.body)) { - headers['Content-Type'] = options.body.type || 'application/octet-stream'; - } else if (isString(options.body)) { - headers['Content-Type'] = 'text/plain'; - } else if (!isFormData(options.body)) { - headers['Content-Type'] = 'application/json'; - } - } - - return headers; -}; - -export const getRequestBody = (options: ApiRequestOptions): any => { - if (options.body) { - return options.body; - } - return undefined; -}; - -export const sendRequest = async ( - config: OpenAPIConfig, - options: ApiRequestOptions, - url: string, - body: any, - formData: FormData | undefined, - headers: Record, - onCancel: OnCancel, - axiosClient: AxiosInstance -): Promise> => { - const source = axios.CancelToken.source(); - - const requestConfig: AxiosRequestConfig = { - url, - headers, - data: body ?? formData, - method: options.method, - withCredentials: config.WITH_CREDENTIALS, - withXSRFToken: config.CREDENTIALS === 'include' ? config.WITH_CREDENTIALS : false, - cancelToken: source.token, - }; - - onCancel(() => source.cancel('The user aborted a request.')); - - try { - return await axiosClient.request(requestConfig); - } catch (error) { - const axiosError = error as AxiosError; - if (axiosError.response) { - return axiosError.response; - } - throw error; - } -}; - -export const getResponseHeader = (response: AxiosResponse, responseHeader?: string): string | undefined => { - if (responseHeader) { - const content = response.headers[responseHeader]; - if (isString(content)) { - return content; - } - } - return undefined; -}; - -export const getResponseBody = (response: AxiosResponse): any => { - if (response.status !== 204) { - return response.data; - } - return undefined; -}; - -export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => { - const errors: Record = { - 400: 'Bad Request', - 401: 'Unauthorized', - 403: 'Forbidden', - 404: 'Not Found', - 500: 'Internal Server Error', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - ...options.errors, - } - - const error = errors[result.status]; - if (error) { - throw new ApiError(options, result, error); - } - - if (!result.ok) { - const errorStatus = result.status ?? 'unknown'; - const errorStatusText = result.statusText ?? 'unknown'; - const errorBody = (() => { - try { - return JSON.stringify(result.body, null, 2); - } catch (e) { - return undefined; - } - })(); - - throw new ApiError(options, result, - `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}` - ); - } -}; - -/** - * Request method - * @param config The OpenAPI configuration object - * @param options The request options from the service - * @param axiosClient The axios client instance to use - * @returns CancelablePromise - * @throws ApiError - */ -export const request = (config: OpenAPIConfig, options: ApiRequestOptions, axiosClient: AxiosInstance = axios): CancelablePromise => { - return new CancelablePromise(async (resolve, reject, onCancel) => { - try { - const url = getUrl(config, options); - const formData = getFormData(options); - const body = getRequestBody(options); - const headers = await getHeaders(config, options, formData); - - if (!onCancel.isCancelled) { - const response = await sendRequest(config, options, url, body, formData, headers, onCancel, axiosClient); - const responseBody = getResponseBody(response); - const responseHeader = getResponseHeader(response, options.responseHeader); - - const result: ApiResult = { - url, - ok: isSuccess(response.status), - status: response.status, - statusText: response.statusText, - body: responseHeader ?? responseBody, - }; - - catchErrorCodes(options, result); - - resolve(result.body); - } - } catch (error) { - reject(error); - } - }); -}; diff --git a/modules/frontend/src/auth/index.ts b/modules/frontend/src/auth/index.ts deleted file mode 100644 index b0989c4..0000000 --- a/modules/frontend/src/auth/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export { ApiError } from './core/ApiError'; -export { CancelablePromise, CancelError } from './core/CancelablePromise'; -export { OpenAPI } from './core/OpenAPI'; -export type { OpenAPIConfig } from './core/OpenAPI'; - -export { AuthService } from './services/AuthService'; diff --git a/modules/frontend/src/auth/services/AuthService.ts b/modules/frontend/src/auth/services/AuthService.ts deleted file mode 100644 index bab9c77..0000000 --- a/modules/frontend/src/auth/services/AuthService.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { CancelablePromise } from '../core/CancelablePromise'; -import { OpenAPI } from '../core/OpenAPI'; -import { request as __request } from '../core/request'; -export class AuthService { - /** - * Sign up a new user - * @param requestBody - * @returns any Sign-up result - * @throws ApiError - */ - public static postAuthSignUp( - requestBody: { - nickname: string; - pass: string; - }, - ): CancelablePromise<{ - success?: boolean; - error?: string | null; - user_id?: string | null; - }> { - return __request(OpenAPI, { - method: 'POST', - url: '/auth/sign-up', - body: requestBody, - mediaType: 'application/json', - }); - } - /** - * Sign in a user and return JWT - * @param requestBody - * @returns any Sign-in result with JWT - * @throws ApiError - */ - public static postAuthSignIn( - requestBody: { - nickname: string; - pass: string; - }, - ): CancelablePromise<{ - success?: boolean; - error?: string | null; - user_id?: string | null; - }> { - return __request(OpenAPI, { - method: 'POST', - url: '/auth/sign-in', - body: requestBody, - mediaType: 'application/json', - errors: { - 401: `Access denied due to invalid credentials`, - }, - }); - } -} diff --git a/modules/frontend/src/pages/LoginPage/LoginPage.tsx b/modules/frontend/src/pages/LoginPage/LoginPage.tsx deleted file mode 100644 index dcd6965..0000000 --- a/modules/frontend/src/pages/LoginPage/LoginPage.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import React, { useState } from "react"; -import { AuthService } from "../../auth/services/AuthService"; -import { useNavigate } from "react-router-dom"; - -export const LoginPage: React.FC = () => { - const navigate = useNavigate(); - const [isLogin, setIsLogin] = useState(true); // true = login, false = signup - const [nickname, setNickname] = useState(""); - const [password, setPassword] = useState(""); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - setError(null); - - try { - if (isLogin) { - const res = await AuthService.postAuthSignIn({ nickname, pass: password }); - if (res.success) { - // TODO: сохранить JWT в localStorage/cookie - console.log("Logged in user id:", res.user_id); - navigate("/"); // редирект после успешного входа - } else { - setError(res.error || "Login failed"); - } - } else { - const res = await AuthService.postAuthSignUp({ nickname, pass: password }); - if (res.success) { - console.log("User signed up with id:", res.user_id); - setIsLogin(true); // переключаемся на login после регистрации - } else { - setError(res.error || "Sign up failed"); - } - } - } catch (err: any) { - console.error(err); - setError(err?.message || "Something went wrong"); - } finally { - setLoading(false); - } - }; - - return ( -
-
-

- {isLogin ? "Login" : "Sign Up"} -

- - {error &&
{error}
} - -
-
- - setNickname(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required - /> -
- -
- - setPassword(e.target.value)} - className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - required - /> -
- - -
- -
- {isLogin ? ( - <> - Don't have an account?{" "} - - - ) : ( - <> - Already have an account?{" "} - - - )} -
-
-
- ); -};