diff --git a/controller/controller.go b/controller/controller.go index a101362..040d1a2 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -12,6 +12,7 @@ type Controller struct { openaiClient *openai.Client unraidAPIKey string unraidURI string + jwtToken string config *configStruct } @@ -29,6 +30,7 @@ func NewController() *Controller { openaiClient := openai.NewClient(openaiApiKey) unraidAPIKey := os.Getenv("UNRAID_API_KEY") unraidURI := os.Getenv("UNRAID_URI") + jwtToken := os.Getenv("jwtToken") if err != nil { fmt.Println(err.Error()) @@ -38,6 +40,7 @@ func NewController() *Controller { openaiClient: openaiClient, unraidAPIKey: unraidAPIKey, unraidURI: unraidURI, + jwtToken: jwtToken, } } diff --git a/controller/token.go b/controller/token.go new file mode 100644 index 0000000..d0d4df8 --- /dev/null +++ b/controller/token.go @@ -0,0 +1,42 @@ +package controller + +import ( + "net/http" + "time" + + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" +) + +// generateTokenHandler godoc +// +// @Summary Generate JWT Token +// @Description Gets the PSU Data from unraid +// @Tags token +// @Accept json +// @Produce plain +// @Param token query string true "Secret Token" +// @Success 200 {string} string "response" +// @Router /token/generateTokenHandler [get] +func (c *Controller) GenerateTokenHandler(ctx *gin.Context) { + // Define the token claims + claims := jwt.MapClaims{ + "exp": time.Now().Add(time.Hour * 24).Unix(), + "iat": time.Now().Unix(), + // Add any additional claims here... + } + + // Generate a new token with the claims + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + // Sign the token with your secret key + // TODO: Replace "my-secret-key" with your own secret key + tokenString, err := token.SignedString([]byte(ctx.Query("token"))) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "Failed to generate token"}) + return + } + + // Return the token in the response body + ctx.JSON(http.StatusOK, gin.H{"token": tokenString}) +} diff --git a/docs/docs.go b/docs/docs.go index 392995c..faab688 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -89,6 +89,38 @@ const docTemplate = `{ } } }, + "/token/generateTokenHandler": { + "get": { + "description": "Gets the PSU Data from unraid", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "token" + ], + "summary": "Generate JWT Token", + "parameters": [ + { + "type": "string", + "description": "Secret Token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "response", + "schema": { + "type": "string" + } + } + } + } + }, "/unraid/powerusage": { "get": { "description": "Gets the PSU Data from unraid", @@ -115,50 +147,9 @@ const docTemplate = `{ }, "securityDefinitions": { "ApiKeyAuth": { - "description": "Description for what is this security definition being used", "type": "apiKey", "name": "Authorization", "in": "header" - }, - "BasicAuth": { - "type": "basic" - }, - "OAuth2AccessCode": { - "type": "oauth2", - "flow": "accessCode", - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information" - } - }, - "OAuth2Application": { - "type": "oauth2", - "flow": "application", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "write": "\t\t\t\t\t\t\tGrants write access" - } - }, - "OAuth2Implicit": { - "type": "oauth2", - "flow": "implicit", - "authorizationUrl": "https://example.com/oauth/authorize", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "write": "\t\t\t\t\t\t\tGrants write access" - } - }, - "OAuth2Password": { - "type": "oauth2", - "flow": "password", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "read": "\t\t\t\t\t\t\t\tGrants read access", - "write": "\t\t\t\t\t\t\tGrants write access" - } } } }` diff --git a/docs/swagger.json b/docs/swagger.json index 92033d9..b142468 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -82,6 +82,38 @@ } } }, + "/token/generateTokenHandler": { + "get": { + "description": "Gets the PSU Data from unraid", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "token" + ], + "summary": "Generate JWT Token", + "parameters": [ + { + "type": "string", + "description": "Secret Token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "response", + "schema": { + "type": "string" + } + } + } + } + }, "/unraid/powerusage": { "get": { "description": "Gets the PSU Data from unraid", @@ -108,50 +140,9 @@ }, "securityDefinitions": { "ApiKeyAuth": { - "description": "Description for what is this security definition being used", "type": "apiKey", "name": "Authorization", "in": "header" - }, - "BasicAuth": { - "type": "basic" - }, - "OAuth2AccessCode": { - "type": "oauth2", - "flow": "accessCode", - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information" - } - }, - "OAuth2Application": { - "type": "oauth2", - "flow": "application", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "write": "\t\t\t\t\t\t\tGrants write access" - } - }, - "OAuth2Implicit": { - "type": "oauth2", - "flow": "implicit", - "authorizationUrl": "https://example.com/oauth/authorize", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "write": "\t\t\t\t\t\t\tGrants write access" - } - }, - "OAuth2Password": { - "type": "oauth2", - "flow": "password", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": "\t\t\t\t\t\t\tGrants read and write access to administrative information", - "read": "\t\t\t\t\t\t\t\tGrants read access", - "write": "\t\t\t\t\t\t\tGrants write access" - } } } } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 7fafe6d..f444074 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -55,6 +55,27 @@ paths: summary: Travel Agent ChatGPT tags: - openai + /token/generateTokenHandler: + get: + consumes: + - application/json + description: Gets the PSU Data from unraid + parameters: + - description: Secret Token + in: query + name: token + required: true + type: string + produces: + - text/plain + responses: + "200": + description: response + schema: + type: string + summary: Generate JWT Token + tags: + - token /unraid/powerusage: get: consumes: @@ -72,39 +93,7 @@ paths: - unraid securityDefinitions: ApiKeyAuth: - description: Description for what is this security definition being used in: header name: Authorization type: apiKey - BasicAuth: - type: basic - OAuth2AccessCode: - authorizationUrl: https://example.com/oauth/authorize - flow: accessCode - scopes: - admin: "\t\t\t\t\t\t\tGrants read and write access to administrative information" - tokenUrl: https://example.com/oauth/token - type: oauth2 - OAuth2Application: - flow: application - scopes: - admin: "\t\t\t\t\t\t\tGrants read and write access to administrative information" - write: "\t\t\t\t\t\t\tGrants write access" - tokenUrl: https://example.com/oauth/token - type: oauth2 - OAuth2Implicit: - authorizationUrl: https://example.com/oauth/authorize - flow: implicit - scopes: - admin: "\t\t\t\t\t\t\tGrants read and write access to administrative information" - write: "\t\t\t\t\t\t\tGrants write access" - type: oauth2 - OAuth2Password: - flow: password - scopes: - admin: "\t\t\t\t\t\t\tGrants read and write access to administrative information" - read: "\t\t\t\t\t\t\t\tGrants read access" - write: "\t\t\t\t\t\t\tGrants write access" - tokenUrl: https://example.com/oauth/token - type: oauth2 swagger: "2.0" diff --git a/main.go b/main.go index 8152722..109d0bc 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,12 @@ package main import ( "net/http" + "os" + "strings" "github.com/DeveloperDurp/DurpAPI/controller" _ "github.com/DeveloperDurp/DurpAPI/docs" + "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" @@ -25,16 +28,21 @@ import ( // @host durpapi.durp.info // @BasePath /api/v1 -// @securityDefinitions.basic BasicAuth +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name Authorization func main() { r := gin.Default() - c := controller.NewController() v1 := r.Group("/api/v1") { + token := v1.Group("/token") + { + token.GET("generateTokenHandler", c.GenerateTokenHandler) + } openai := v1.Group("/openai") { openai.Use(authMiddleware()) @@ -53,26 +61,33 @@ func main() { func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { - // Get the username and password from the request header - username, password, ok := c.Request.BasicAuth() - if !ok { - c.Header("WWW-Authenticate", "Basic realm=Restricted") - c.AbortWithStatus(http.StatusUnauthorized) + // Get the authorization header from the request + authHeader := c.GetHeader("Authorization") + + // Check if the authorization header is missing or doesn't start with "Bearer" + if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Unauthorized access"}) return } - // Check if the username and password are valid - if username != "user" || password != "password" { - c.Header("WWW-Authenticate", "Basic realm=Restricted") - c.AbortWithStatus(http.StatusUnauthorized) + // Extract the token from the authorization header + tokenString := strings.TrimPrefix(authHeader, "Bearer ") + + // Parse the token and validate its signature + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte(os.Getenv("jwtToken")), nil + }) + + // Check if there was an error parsing the token or if it is not valid + if err != nil || !token.Valid { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Unauthorized access"}) return } - // Set the user ID in the context for later use - userID := "user" - c.Set("userID", userID) + // Add the token to the request context + c.Set("token", token) - // Call the next middleware or handler function + // Call the next handler c.Next() } }