From 5ec35ec521f4d6f9b6879db4f2100463c1b53f99 Mon Sep 17 00:00:00 2001 From: DeveloperDurp Date: Fri, 26 May 2023 20:06:00 -0500 Subject: [PATCH] update --- .gitignore | 1 + .octopus/deployment_process.ocl | 0 .octopus/deployment_settings.ocl | 7 --- .octopus/schema_version.ocl | 1 - .octopus/variables.ocl | 3 -- controller/controller.go | 24 ++++++--- controller/token.go | 25 +++++++++ docs/docs.go | 25 ++++++++- docs/swagger.json | 25 ++++++++- docs/swagger.yaml | 17 +++++- go.mod | 11 ++-- go.sum | 14 +++++ main.go | 93 ++++++++++++++++++++------------ 13 files changed, 188 insertions(+), 58 deletions(-) delete mode 100644 .octopus/deployment_process.ocl delete mode 100644 .octopus/deployment_settings.ocl delete mode 100644 .octopus/schema_version.ocl delete mode 100644 .octopus/variables.ocl create mode 100644 controller/token.go diff --git a/.gitignore b/.gitignore index 091bd58..04eacc9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __debug_bin .env .idea output +docs \ No newline at end of file diff --git a/.octopus/deployment_process.ocl b/.octopus/deployment_process.ocl deleted file mode 100644 index e69de29..0000000 diff --git a/.octopus/deployment_settings.ocl b/.octopus/deployment_settings.ocl deleted file mode 100644 index 2c0b118..0000000 --- a/.octopus/deployment_settings.ocl +++ /dev/null @@ -1,7 +0,0 @@ -connectivity_policy { - allow_deployments_to_no_targets = true -} - -versioning_strategy { - template = "#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.NextPatch}" -} \ No newline at end of file diff --git a/.octopus/schema_version.ocl b/.octopus/schema_version.ocl deleted file mode 100644 index 4548a61..0000000 --- a/.octopus/schema_version.ocl +++ /dev/null @@ -1 +0,0 @@ -version = 6 \ No newline at end of file diff --git a/.octopus/variables.ocl b/.octopus/variables.ocl deleted file mode 100644 index 4c94db3..0000000 --- a/.octopus/variables.ocl +++ /dev/null @@ -1,3 +0,0 @@ -variable "TestVariable" { - value "1234" {} -} \ No newline at end of file diff --git a/controller/controller.go b/controller/controller.go index cdbdb3d..a5773d1 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -1,10 +1,8 @@ package controller import ( - "fmt" "os" - "github.com/joho/godotenv" openai "github.com/sashabaranov/go-openai" ) @@ -12,23 +10,33 @@ type Controller struct { openaiClient *openai.Client unraidAPIKey string unraidURI string + ClientID string + ClientSecret string + RedirectURL string + AuthURL string + TokenURL string } func NewController() *Controller { - err := godotenv.Load(".env") openaiApiKey := os.Getenv("OPENAI_API_KEY") - openaiClient := openai.NewClient(openaiApiKey) unraidAPIKey := os.Getenv("UNRAID_API_KEY") unraidURI := os.Getenv("UNRAID_URI") + ClientID := os.Getenv("ClientID") + ClientSecret := os.Getenv("ClientSecret") + RedirectURL := os.Getenv("RedirectURL") + AuthURL := os.Getenv("AuthURL") + TokenURL := os.Getenv("TokenURL") - if err != nil { - fmt.Println(".env file not found, using environment variables") - } return &Controller{ - openaiClient: openaiClient, + openaiClient: openai.NewClient(openaiApiKey), unraidAPIKey: unraidAPIKey, unraidURI: unraidURI, + ClientID: ClientID, + ClientSecret: ClientSecret, + RedirectURL: RedirectURL, + AuthURL: AuthURL, + TokenURL: TokenURL, } } diff --git a/controller/token.go b/controller/token.go new file mode 100644 index 0000000..14684c2 --- /dev/null +++ b/controller/token.go @@ -0,0 +1,25 @@ +package controller + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "golang.org/x/oauth2" +) + +// GenerateToken godoc +// +// @Summary Generate Health status +// @Description Get the health of the API +// @Tags token +// @Accept json +// @Produce json +// @Success 200 {string} json "response" +// @Router /token/GenerateToken [get] +func (c *Controller) GenerateToken(conf *oauth2.Config) gin.HandlerFunc { + return func(c *gin.Context) { + // Redirect user to the authorization URL + authURL := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) + c.Redirect(http.StatusTemporaryRedirect, authURL) + } +} diff --git a/docs/docs.go b/docs/docs.go index 6444223..5331cab 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -112,6 +112,29 @@ const docTemplate = `{ } } }, + "/token/GenerateToken": { + "get": { + "description": "Get the health of the API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "token" + ], + "summary": "Generate Health status", + "responses": { + "200": { + "description": "response", + "schema": { + "type": "string" + } + } + } + } + }, "/unraid/powerusage": { "get": { "description": "Gets the PSU Data from unraid", @@ -148,7 +171,7 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", - Host: "durpapi.durp.info", + Host: "localhost:8080", BasePath: "/api/v1", Schemes: []string{}, Title: "DurpAPI", diff --git a/docs/swagger.json b/docs/swagger.json index 130c72f..ab50b14 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -15,7 +15,7 @@ }, "version": "1.0" }, - "host": "durpapi.durp.info", + "host": "localhost:8080", "basePath": "/api/v1", "paths": { "/health/getHealth": { @@ -105,6 +105,29 @@ } } }, + "/token/GenerateToken": { + "get": { + "description": "Get the health of the API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "token" + ], + "summary": "Generate Health status", + "responses": { + "200": { + "description": "response", + "schema": { + "type": "string" + } + } + } + } + }, "/unraid/powerusage": { "get": { "description": "Gets the PSU Data from unraid", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c2815ab..449a61d 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,5 @@ basePath: /api/v1 -host: durpapi.durp.info +host: localhost:8080 info: contact: email: support@swagger.io @@ -70,6 +70,21 @@ paths: summary: Travel Agent ChatGPT tags: - openai + /token/GenerateToken: + get: + consumes: + - application/json + description: Get the health of the API + produces: + - application/json + responses: + "200": + description: response + schema: + type: string + summary: Generate Health status + tags: + - token /unraid/powerusage: get: consumes: diff --git a/go.mod b/go.mod index 276249c..854dda2 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,11 @@ require ( github.com/swaggo/swag v1.8.12 ) -require github.com/google/go-cmp v0.5.8 // indirect +require ( + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.8 // indirect + google.golang.org/appengine v1.6.7 // indirect +) require ( github.com/KyleBanks/depth v1.2.1 // indirect @@ -43,8 +47,9 @@ require ( github.com/ugorji/go/codec v1.2.9 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.5.0 // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.8.0 + golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/tools v0.7.0 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 4139773..5a101db 100644 --- a/go.sum +++ b/go.sum @@ -42,7 +42,10 @@ github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -110,6 +113,7 @@ golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= @@ -117,6 +121,10 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -129,10 +137,13 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -146,7 +157,10 @@ golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index e3be2eb..bf3ab6b 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,16 @@ package main import ( + "context" "fmt" "net/http" - "os" - "strings" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" "gitlab.com/DeveloperDurp/DurpAPI/controller" _ "gitlab.com/DeveloperDurp/DurpAPI/docs" + "golang.org/x/oauth2" ) // @title DurpAPI @@ -37,6 +37,19 @@ func main() { r := gin.Default() c := controller.NewController() var groups []string + conf := &oauth2.Config{ + ClientID: c.ClientID, + ClientSecret: c.ClientSecret, + RedirectURL: c.RedirectURL, + Scopes: []string{ + "email", + "groups", + }, + Endpoint: oauth2.Endpoint{ + AuthURL: c.AuthURL, + TokenURL: c.TokenURL, + }, + } v1 := r.Group("/api/v1") { @@ -44,6 +57,10 @@ func main() { { health.GET("getHealth", c.GetHealth) } + token := v1.Group("/token") + { + token.GET("GenerateToken", c.GenerateToken(conf)) + } openai := v1.Group("/openai") { groups = []string{"openai"} @@ -59,52 +76,62 @@ func main() { } } r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + r.GET("/callback", CallbackHandler(conf)) + err := r.Run(":8080") if err != nil { fmt.Println("Failed to start server") } } -func authMiddleware(allowedGroups []string) gin.HandlerFunc { +func authMiddleware(groups []string) gin.HandlerFunc { return func(c *gin.Context) { - - var groups []string - groupsenv := os.Getenv("groups") - if groupsenv != "" { - groups = strings.Split(groupsenv, ",") - } else { - // Get the user groups from the request headers - groupsHeader := c.GetHeader("X-authentik-groups") - - // Split the groups header value into individual groups - groups = strings.Split(groupsHeader, "|") + // Get the access token from the request header or query parameters + accessToken := c.GetHeader("Authorization") + if accessToken == "" { + accessToken = c.Query("access_token") } - // Check if the user belongs to any of the allowed groups - isAllowed := false - for _, allowedGroup := range allowedGroups { - for _, group := range groups { - if group == allowedGroup { - isAllowed = true - break - } - } - if isAllowed { - break - } - } + // Create an OAuth2 token from the access token + token := &oauth2.Token{AccessToken: accessToken} - // If the user is not in any of the allowed groups, respond with unauthorized access - if !isAllowed { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ - "message": "Unauthorized access", - "groups": groups, - }) + // Validate the token + if !token.Valid() { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) return } + // Add the token to the request context for later use + ctx := context.WithValue(c.Request.Context(), "token", token) + c.Request = c.Request.WithContext(ctx) + // Call the next handler c.Next() } } + +// CallbackHandler receives the authorization code and exchanges it for a token +func CallbackHandler(conf *oauth2.Config) gin.HandlerFunc { + return func(c *gin.Context) { + // Get the authorization code from the query parameters + code := c.Query("code") + + // Exchange the authorization code for a token + token, err := conf.Exchange(context.Background(), code) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to exchange authorization code"}) + return + } + + // Create a response JSON + response := gin.H{ + "access_token": token.AccessToken, + "token_type": token.TokenType, + "refresh_token": token.RefreshToken, + "expiry": token.Expiry, + } + + c.JSON(http.StatusOK, response) + } +}