diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index d64be95..c05f223 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,19 +1,12 @@ import * as React from 'react'; import { Text, ChakraProvider } from '@chakra-ui/react'; import { MdStar } from 'react-icons/md'; +import { BrowserRouter } from 'react-router-dom'; export default function Example() { return ( - - Authorizer Dashboard - + ); } diff --git a/dashboard/src/Router.tsx b/dashboard/src/Router.tsx new file mode 100644 index 0000000..e69de29 diff --git a/dashboard/src/components/layouts/AuthLayout.tsx b/dashboard/src/components/layouts/AuthLayout.tsx new file mode 100644 index 0000000..0ba7800 --- /dev/null +++ b/dashboard/src/components/layouts/AuthLayout.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function AuthLayout() { + return

Auth Layout

; +} diff --git a/dashboard/src/components/layouts/DefaultLayout.tsx b/dashboard/src/components/layouts/DefaultLayout.tsx new file mode 100644 index 0000000..505b6c5 --- /dev/null +++ b/dashboard/src/components/layouts/DefaultLayout.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function DefaultLayout() { + return

Default Layout

; +} diff --git a/dashboard/src/contexts/AuthContext.tsx b/dashboard/src/contexts/AuthContext.tsx new file mode 100644 index 0000000..e69de29 diff --git a/server/__test__/admin_login_test.go b/server/__test__/admin_login_test.go new file mode 100644 index 0000000..827d8cf --- /dev/null +++ b/server/__test__/admin_login_test.go @@ -0,0 +1,28 @@ +package test + +import ( + "testing" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/resolvers" + "github.com/stretchr/testify/assert" +) + +func adminLoginTests(s TestSetup, t *testing.T) { + t.Run(`should complete admin login`, func(t *testing.T) { + _, ctx := createContext(s) + _, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ + AdminSecret: "admin_test", + }) + + assert.NotNil(t, err) + + res, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ + AdminSecret: constants.EnvData.ADMIN_SECRET, + }) + + assert.Nil(t, err) + assert.Greater(t, len(res.AccessToken), 0) + }) +} diff --git a/server/__test__/admin_session_test.go b/server/__test__/admin_session_test.go new file mode 100644 index 0000000..bcf248b --- /dev/null +++ b/server/__test__/admin_session_test.go @@ -0,0 +1,28 @@ +package test + +import ( + "log" + "testing" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/resolvers" + "github.com/authorizerdev/authorizer/server/utils" + "github.com/stretchr/testify/assert" +) + +func adminSessionTests(s TestSetup, t *testing.T) { + t.Run(`should get admin session`, func(t *testing.T) { + req, ctx := createContext(s) + _, err := resolvers.AdminSession(ctx) + log.Println("error:", err) + assert.NotNil(t, err) + + h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + assert.Nil(t, err) + req.Header.Add("Authorization", "Bearer "+h) + res, err := resolvers.AdminSession(ctx) + + assert.Nil(t, err) + assert.Greater(t, len(res.AccessToken), 0) + }) +} diff --git a/server/__test__/config_test.go b/server/__test__/config_test.go new file mode 100644 index 0000000..09df58a --- /dev/null +++ b/server/__test__/config_test.go @@ -0,0 +1,28 @@ +package test + +import ( + "log" + "testing" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/resolvers" + "github.com/authorizerdev/authorizer/server/utils" + "github.com/stretchr/testify/assert" +) + +func configTests(s TestSetup, t *testing.T) { + t.Run(`should get config`, func(t *testing.T) { + req, ctx := createContext(s) + _, err := resolvers.ConfigResolver(ctx) + log.Println("error:", err) + assert.NotNil(t, err) + + h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + assert.Nil(t, err) + req.Header.Add("Authorization", "Bearer "+h) + res, err := resolvers.ConfigResolver(ctx) + + assert.Nil(t, err) + assert.Equal(t, *res.AdminSecret, constants.EnvData.ADMIN_SECRET) + }) +} diff --git a/server/__test__/delete_user_test.go b/server/__test__/delete_user_test.go index 4f306dc..14084f2 100644 --- a/server/__test__/delete_user_test.go +++ b/server/__test__/delete_user_test.go @@ -24,7 +24,7 @@ func deleteUserTest(s TestSetup, t *testing.T) { }) assert.NotNil(t, err, "unauthorized") - req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET) + req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET) _, err = resolvers.DeleteUser(ctx, model.DeleteUserInput{ Email: email, }) diff --git a/server/__test__/env_test.go b/server/__test__/env_test.go index 690ad51..328d5f6 100644 --- a/server/__test__/env_test.go +++ b/server/__test__/env_test.go @@ -8,18 +8,18 @@ import ( ) func TestEnvs(t *testing.T) { - constants.ENV_PATH = "../../.env.sample" + constants.EnvData.ENV_PATH = "../../.env.sample" - assert.Equal(t, constants.ADMIN_SECRET, "admin") - assert.Equal(t, constants.ENV, "production") - assert.False(t, constants.DISABLE_EMAIL_VERIFICATION) - assert.False(t, constants.DISABLE_MAGIC_LINK_LOGIN) - assert.False(t, constants.DISABLE_BASIC_AUTHENTICATION) - assert.Equal(t, constants.JWT_TYPE, "HS256") - assert.Equal(t, constants.JWT_SECRET, "random_string") - assert.Equal(t, constants.JWT_ROLE_CLAIM, "role") - assert.EqualValues(t, constants.ROLES, []string{"user"}) - assert.EqualValues(t, constants.DEFAULT_ROLES, []string{"user"}) - assert.EqualValues(t, constants.PROTECTED_ROLES, []string{"admin"}) - assert.EqualValues(t, constants.ALLOWED_ORIGINS, []string{"*"}) + assert.Equal(t, constants.EnvData.ADMIN_SECRET, "admin") + assert.Equal(t, constants.EnvData.ENV, "production") + assert.False(t, constants.EnvData.DISABLE_EMAIL_VERIFICATION) + assert.False(t, constants.EnvData.DISABLE_MAGIC_LINK_LOGIN) + assert.False(t, constants.EnvData.DISABLE_BASIC_AUTHENTICATION) + assert.Equal(t, constants.EnvData.JWT_TYPE, "HS256") + assert.Equal(t, constants.EnvData.JWT_SECRET, "random_string") + assert.Equal(t, constants.EnvData.JWT_ROLE_CLAIM, "role") + assert.EqualValues(t, constants.EnvData.ROLES, []string{"user"}) + assert.EqualValues(t, constants.EnvData.DEFAULT_ROLES, []string{"user"}) + assert.EqualValues(t, constants.EnvData.PROTECTED_ROLES, []string{"admin"}) + assert.EqualValues(t, constants.EnvData.ALLOWED_ORIGINS, []string{"*"}) } diff --git a/server/__test__/meta_test.go b/server/__test__/meta_test.go index f4167c1..9989141 100644 --- a/server/__test__/meta_test.go +++ b/server/__test__/meta_test.go @@ -2,6 +2,7 @@ package test import ( "context" + "log" "testing" "github.com/authorizerdev/authorizer/server/resolvers" @@ -12,6 +13,7 @@ func metaTests(s TestSetup, t *testing.T) { t.Run(`should get meta information`, func(t *testing.T) { ctx := context.Background() meta, err := resolvers.Meta(ctx) + log.Println("=> meta:", meta) assert.Nil(t, err) assert.False(t, meta.IsFacebookLoginEnabled) assert.False(t, meta.IsGoogleLoginEnabled) diff --git a/server/__test__/resolvers_test.go b/server/__test__/resolvers_test.go index 160265c..59224e7 100644 --- a/server/__test__/resolvers_test.go +++ b/server/__test__/resolvers_test.go @@ -6,19 +6,21 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/enum" + "github.com/authorizerdev/authorizer/server/env" ) func TestResolvers(t *testing.T) { databases := map[string]string{ - enum.Sqlite.String(): "../../data.db", - enum.Arangodb.String(): "http://root:root@localhost:8529", - enum.Mongodb.String(): "mongodb://localhost:27017", + enum.Sqlite.String(): "../../data.db", + // enum.Arangodb.String(): "http://root:root@localhost:8529", + // enum.Mongodb.String(): "mongodb://localhost:27017", } for dbType, dbURL := range databases { - constants.DATABASE_URL = dbURL - constants.DATABASE_TYPE = dbType + constants.EnvData.DATABASE_URL = dbURL + constants.EnvData.DATABASE_TYPE = dbType db.InitDB() + env.PersistEnv() s := testSetup() defer s.Server.Close() @@ -42,6 +44,10 @@ func TestResolvers(t *testing.T) { usersTest(s, t) deleteUserTest(s, t) updateUserTest(s, t) + adminLoginTests(s, t) + adminSessionTests(s, t) + updateConfigTests(s, t) + configTests(s, t) }) } } diff --git a/server/__test__/test.go b/server/__test__/test.go index 1abd9f5..82ae77b 100644 --- a/server/__test__/test.go +++ b/server/__test__/test.go @@ -70,7 +70,8 @@ func testSetup() TestSetup { Password: "test", } - constants.ENV_PATH = "../../.env.sample" + constants.EnvData.ENV_PATH = "../../.env.sample" + env.InitEnv() session.InitSession() diff --git a/server/__test__/update_config_test.go b/server/__test__/update_config_test.go new file mode 100644 index 0000000..a104f38 --- /dev/null +++ b/server/__test__/update_config_test.go @@ -0,0 +1,42 @@ +package test + +import ( + "log" + "testing" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/resolvers" + "github.com/authorizerdev/authorizer/server/utils" + "github.com/stretchr/testify/assert" +) + +func updateConfigTests(s TestSetup, t *testing.T) { + t.Run(`should update configs`, func(t *testing.T) { + req, ctx := createContext(s) + originalAppURL := constants.EnvData.APP_URL + log.Println("=> originalAppURL:", constants.EnvData.APP_URL) + + data := model.UpdateConfigInput{} + _, err := resolvers.UpdateConfigResolver(ctx, data) + log.Println("error:", err) + assert.NotNil(t, err) + + h, _ := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + req.Header.Add("Authorization", "Bearer "+h) + newURL := "https://test.com" + data = model.UpdateConfigInput{ + AppURL: &newURL, + } + _, err = resolvers.UpdateConfigResolver(ctx, data) + log.Println("error:", err) + assert.Nil(t, err) + assert.Equal(t, constants.EnvData.APP_URL, newURL) + assert.NotEqual(t, constants.EnvData.APP_URL, originalAppURL) + data = model.UpdateConfigInput{ + AppURL: &originalAppURL, + } + _, err = resolvers.UpdateConfigResolver(ctx, data) + assert.Nil(t, err) + }) +} diff --git a/server/__test__/update_user_test.go b/server/__test__/update_user_test.go index 45d614a..fd832e9 100644 --- a/server/__test__/update_user_test.go +++ b/server/__test__/update_user_test.go @@ -29,7 +29,7 @@ func updateUserTest(s TestSetup, t *testing.T) { }) assert.NotNil(t, err, "unauthorized") - req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET) + req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET) _, err = resolvers.UpdateUser(ctx, model.UpdateUserInput{ ID: user.ID, Roles: newRoles, diff --git a/server/__test__/users_test.go b/server/__test__/users_test.go index 6386a8e..8251325 100644 --- a/server/__test__/users_test.go +++ b/server/__test__/users_test.go @@ -22,7 +22,7 @@ func usersTest(s TestSetup, t *testing.T) { users, err := resolvers.Users(ctx) assert.NotNil(t, err, "unauthorized") - req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET) + req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET) users, err = resolvers.Users(ctx) assert.Nil(t, err) rLen := len(users) diff --git a/server/__test__/validator_test.go b/server/__test__/validator_test.go index 4999716..7145d74 100644 --- a/server/__test__/validator_test.go +++ b/server/__test__/validator_test.go @@ -22,7 +22,7 @@ func TestIsValidEmail(t *testing.T) { func TestIsValidOrigin(t *testing.T) { // don't use portocal(http/https) for ALLOWED_ORIGINS while testing, // as we trim them off while running the main function - constants.ALLOWED_ORIGINS = []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"} + constants.EnvData.ALLOWED_ORIGINS = []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"} assert.False(t, utils.IsValidOrigin("http://myapp.com"), "it should be invalid origin") assert.False(t, utils.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin") diff --git a/server/__test__/verification_requests_test.go b/server/__test__/verification_requests_test.go index 22fc26e..a4c6f0b 100644 --- a/server/__test__/verification_requests_test.go +++ b/server/__test__/verification_requests_test.go @@ -23,7 +23,7 @@ func verificationRequestsTest(s TestSetup, t *testing.T) { requests, err := resolvers.VerificationRequests(ctx) assert.NotNil(t, err, "unauthorizer") - req.Header.Add("x-authorizer-admin-secret", constants.ADMIN_SECRET) + req.Header.Add("x-authorizer-admin-secret", constants.EnvData.ADMIN_SECRET) requests, err = resolvers.VerificationRequests(ctx) assert.Nil(t, err) diff --git a/server/constants/constants.go b/server/constants/constants.go index 23b66f9..b2ae221 100644 --- a/server/constants/constants.go +++ b/server/constants/constants.go @@ -1,50 +1,61 @@ package constants -// this constants are configured via env -var ( - ADMIN_SECRET = "" - ENV = "" - ENV_PATH = "" - VERSION = "" - DATABASE_TYPE = "" - DATABASE_URL = "" - DATABASE_NAME = "" - SMTP_HOST = "" - SMTP_PORT = "" - SENDER_EMAIL = "" - SENDER_PASSWORD = "" - JWT_TYPE = "" - JWT_SECRET = "" - ALLOWED_ORIGINS = []string{} - AUTHORIZER_URL = "" - APP_URL = "" - PORT = "" - REDIS_URL = "" - IS_PROD = false - COOKIE_NAME = "" - RESET_PASSWORD_URL = "" - DISABLE_EMAIL_VERIFICATION = false - DISABLE_BASIC_AUTHENTICATION = false - DISABLE_MAGIC_LINK_LOGIN = false - DISABLE_LOGIN_PAGE = false +type EnvConst struct { + ADMIN_SECRET string + ENV string + ENV_PATH string + VERSION string + DATABASE_TYPE string + DATABASE_URL string + DATABASE_NAME string + SMTP_HOST string + SMTP_PORT string + SENDER_EMAIL string + SENDER_PASSWORD string + JWT_TYPE string + JWT_SECRET string + ALLOWED_ORIGINS []string + AUTHORIZER_URL string + APP_URL string + PORT string + REDIS_URL string + COOKIE_NAME string + ADMIN_COOKIE_NAME string + RESET_PASSWORD_URL string + ENCRYPTION_KEY string `json:"-"` + IS_PROD bool + DISABLE_EMAIL_VERIFICATION bool + DISABLE_BASIC_AUTHENTICATION bool + DISABLE_MAGIC_LINK_LOGIN bool + DISABLE_LOGIN_PAGE bool // ROLES - ROLES = []string{} - PROTECTED_ROLES = []string{} - DEFAULT_ROLES = []string{} - JWT_ROLE_CLAIM = "role" + ROLES []string + PROTECTED_ROLES []string + DEFAULT_ROLES []string + JWT_ROLE_CLAIM string // OAuth login - GOOGLE_CLIENT_ID = "" - GOOGLE_CLIENT_SECRET = "" - GITHUB_CLIENT_ID = "" - GITHUB_CLIENT_SECRET = "" - FACEBOOK_CLIENT_ID = "" - FACEBOOK_CLIENT_SECRET = "" - TWITTER_CLIENT_ID = "" - TWITTER_CLIENT_SECRET = "" + GOOGLE_CLIENT_ID string + GOOGLE_CLIENT_SECRET string + GITHUB_CLIENT_ID string + GITHUB_CLIENT_SECRET string + FACEBOOK_CLIENT_ID string + FACEBOOK_CLIENT_SECRET string // Org envs - ORGANIZATION_NAME = "Authorizer" - ORGANIZATION_LOGO = "https://authorizer.dev/images/logo.png" -) + ORGANIZATION_NAME string + ORGANIZATION_LOGO string +} + +var EnvData = EnvConst{ + ADMIN_COOKIE_NAME: "authorizer-admin", + JWT_ROLE_CLAIM: "role", + ORGANIZATION_NAME: "Authorizer", + ORGANIZATION_LOGO: "https://authorizer.dev/images/logo.png", + DISABLE_EMAIL_VERIFICATION: false, + DISABLE_BASIC_AUTHENTICATION: false, + DISABLE_MAGIC_LINK_LOGIN: false, + DISABLE_LOGIN_PAGE: false, + IS_PROD: false, +} diff --git a/server/db/arangodb.go b/server/db/arangodb.go index 1d624ed..f6cdb06 100644 --- a/server/db/arangodb.go +++ b/server/db/arangodb.go @@ -17,7 +17,7 @@ import ( func initArangodb() (arangoDriver.Database, error) { ctx := context.Background() conn, err := http.NewConnection(http.ConnectionConfig{ - Endpoints: []string{constants.DATABASE_URL}, + Endpoints: []string{constants.EnvData.DATABASE_URL}, }) if err != nil { return nil, err @@ -32,16 +32,16 @@ func initArangodb() (arangoDriver.Database, error) { var arangodb driver.Database - arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.DATABASE_NAME) + arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.EnvData.DATABASE_NAME) if arangodb_exists { - log.Println(constants.DATABASE_NAME + " db exists already") - arangodb, err = arangoClient.Database(nil, constants.DATABASE_NAME) + log.Println(constants.EnvData.DATABASE_NAME + " db exists already") + arangodb, err = arangoClient.Database(nil, constants.EnvData.DATABASE_NAME) if err != nil { return nil, err } } else { - arangodb, err = arangoClient.CreateDatabase(nil, constants.DATABASE_NAME, nil) + arangodb, err = arangoClient.CreateDatabase(nil, constants.EnvData.DATABASE_NAME, nil) if err != nil { return nil, err } @@ -100,5 +100,15 @@ func initArangodb() (arangoDriver.Database, error) { Sparse: true, }) + configCollectionExists, err := arangodb.CollectionExists(ctx, Collections.Config) + if configCollectionExists { + log.Println(Collections.Config + " collection exists already") + } else { + _, err = arangodb.CreateCollection(ctx, Collections.Config, nil) + if err != nil { + log.Println("error creating collection("+Collections.Config+"):", err) + } + } + return arangodb, err } diff --git a/server/db/config.go b/server/db/config.go new file mode 100644 index 0000000..d4f724a --- /dev/null +++ b/server/db/config.go @@ -0,0 +1,161 @@ +package db + +import ( + "fmt" + "log" + "time" + + arangoDriver "github.com/arangodb/go-driver" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type Config struct { + Key string `json:"_key,omitempty" bson:"_key"` // for arangodb + ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` + Config []byte `gorm:"type:text" json:"config" bson:"config"` + Hash string `gorm:"type:hash" json:"hash" bson:"hash"` + UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` +} + +// AddConfig function to add config +func (mgr *manager) AddConfig(config Config) (Config, error) { + if config.ID == "" { + config.ID = uuid.New().String() + } + + if IsORMSupported { + // copy id as value for fields required for mongodb & arangodb + config.Key = config.ID + result := mgr.sqlDB.Create(&config) + + if result.Error != nil { + log.Println("error adding config:", result.Error) + return config, result.Error + } + } + + if IsArangoDB { + config.CreatedAt = time.Now().Unix() + config.UpdatedAt = time.Now().Unix() + configCollection, _ := mgr.arangodb.Collection(nil, Collections.Config) + meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), config) + if err != nil { + log.Println("error adding config:", err) + return config, err + } + config.Key = meta.Key + config.ID = meta.ID.String() + } + + if IsMongoDB { + config.CreatedAt = time.Now().Unix() + config.UpdatedAt = time.Now().Unix() + config.Key = config.ID + configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection()) + _, err := configCollection.InsertOne(nil, config) + if err != nil { + log.Println("error adding config:", err) + return config, err + } + } + + return config, nil +} + +// UpdateConfig function to update config +func (mgr *manager) UpdateConfig(config Config) (Config, error) { + config.UpdatedAt = time.Now().Unix() + + if IsORMSupported { + result := mgr.sqlDB.Save(&config) + + if result.Error != nil { + log.Println("error updating config:", result.Error) + return config, result.Error + } + } + + if IsArangoDB { + collection, _ := mgr.arangodb.Collection(nil, Collections.Config) + meta, err := collection.UpdateDocument(nil, config.Key, config) + if err != nil { + log.Println("error updating config:", err) + return config, err + } + + config.Key = meta.Key + config.ID = meta.ID.String() + } + + if IsMongoDB { + configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection()) + _, err := configCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": config.ID}}, bson.M{"$set": config}, options.MergeUpdateOptions()) + if err != nil { + log.Println("error updating config:", err) + return config, err + } + } + + return config, nil +} + +// GetConfig function to get config +func (mgr *manager) GetConfig() (Config, error) { + var config Config + + if IsORMSupported { + result := mgr.sqlDB.First(&config) + + if result.Error != nil { + return config, result.Error + } + } + + if IsArangoDB { + query := fmt.Sprintf("FOR d in %s RETURN d", Collections.Config) + + cursor, err := mgr.arangodb.Query(nil, query, nil) + if err != nil { + return config, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if config.Key == "" { + return config, fmt.Errorf("config not found") + } + break + } + _, err := cursor.ReadDocument(nil, &config) + if err != nil { + return config, err + } + } + } + + if IsMongoDB { + configCollection := mgr.mongodb.Collection(Collections.Config, options.Collection()) + cursor, err := configCollection.Find(nil, bson.M{}, options.Find()) + if err != nil { + return config, err + } + defer cursor.Close(nil) + + for cursor.Next(nil) { + err := cursor.Decode(&config) + if err != nil { + return config, err + } + } + + if config.ID == "" { + return config, fmt.Errorf("config not found") + } + } + + return config, nil +} diff --git a/server/db/db.go b/server/db/db.go index f8e7256..8727da5 100644 --- a/server/db/db.go +++ b/server/db/db.go @@ -29,6 +29,9 @@ type Manager interface { GetVerificationByEmail(email string, identifier string) (VerificationRequest, error) AddSession(session Session) error DeleteUserSession(userId string) error + AddConfig(config Config) (Config, error) + UpdateConfig(config Config) (Config, error) + GetConfig() (Config, error) } type manager struct { @@ -42,6 +45,7 @@ type CollectionList struct { User string VerificationRequest string Session string + Config string } var ( @@ -54,6 +58,7 @@ var ( User: Prefix + "users", VerificationRequest: Prefix + "verification_requests", Session: Prefix + "sessions", + Config: Prefix + "config", } ) @@ -61,9 +66,9 @@ func InitDB() { var sqlDB *gorm.DB var err error - IsORMSupported = constants.DATABASE_TYPE != enum.Arangodb.String() && constants.DATABASE_TYPE != enum.Mongodb.String() - IsArangoDB = constants.DATABASE_TYPE == enum.Arangodb.String() - IsMongoDB = constants.DATABASE_TYPE == enum.Mongodb.String() + IsORMSupported = constants.EnvData.DATABASE_TYPE != enum.Arangodb.String() && constants.EnvData.DATABASE_TYPE != enum.Mongodb.String() + IsArangoDB = constants.EnvData.DATABASE_TYPE == enum.Arangodb.String() + IsMongoDB = constants.EnvData.DATABASE_TYPE == enum.Mongodb.String() // sql db orm config ormConfig := &gorm.Config{ @@ -72,20 +77,20 @@ func InitDB() { }, } - log.Println("db type:", constants.DATABASE_TYPE) + log.Println("db type:", constants.EnvData.DATABASE_TYPE) - switch constants.DATABASE_TYPE { + switch constants.EnvData.DATABASE_TYPE { case enum.Postgres.String(): - sqlDB, err = gorm.Open(postgres.Open(constants.DATABASE_URL), ormConfig) + sqlDB, err = gorm.Open(postgres.Open(constants.EnvData.DATABASE_URL), ormConfig) break case enum.Sqlite.String(): - sqlDB, err = gorm.Open(sqlite.Open(constants.DATABASE_URL), ormConfig) + sqlDB, err = gorm.Open(sqlite.Open(constants.EnvData.DATABASE_URL), ormConfig) break case enum.Mysql.String(): - sqlDB, err = gorm.Open(mysql.Open(constants.DATABASE_URL), ormConfig) + sqlDB, err = gorm.Open(mysql.Open(constants.EnvData.DATABASE_URL), ormConfig) break case enum.SQLServer.String(): - sqlDB, err = gorm.Open(sqlserver.Open(constants.DATABASE_URL), ormConfig) + sqlDB, err = gorm.Open(sqlserver.Open(constants.EnvData.DATABASE_URL), ormConfig) break case enum.Arangodb.String(): arangodb, err := initArangodb() @@ -118,7 +123,7 @@ func InitDB() { if err != nil { log.Fatal("Failed to init sqlDB:", err) } else { - sqlDB.AutoMigrate(&User{}, &VerificationRequest{}, &Session{}) + sqlDB.AutoMigrate(&User{}, &VerificationRequest{}, &Session{}, &Config{}) } Mgr = &manager{ sqlDB: sqlDB, diff --git a/server/db/mongodb.go b/server/db/mongodb.go index c69f5bc..21d9320 100644 --- a/server/db/mongodb.go +++ b/server/db/mongodb.go @@ -12,7 +12,7 @@ import ( ) func initMongodb() (*mongo.Database, error) { - mongodbOptions := options.Client().ApplyURI(constants.DATABASE_URL) + mongodbOptions := options.Client().ApplyURI(constants.EnvData.DATABASE_URL) maxWait := time.Duration(5 * time.Second) mongodbOptions.ConnectTimeout = &maxWait mongoClient, err := mongo.NewClient(mongodbOptions) @@ -30,7 +30,7 @@ func initMongodb() (*mongo.Database, error) { return nil, err } - mongodb := mongoClient.Database(constants.DATABASE_NAME, options.Database()) + mongodb := mongoClient.Database(constants.EnvData.DATABASE_NAME, options.Database()) mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection()) userCollection := mongodb.Collection(Collections.User, options.Collection()) @@ -73,5 +73,7 @@ func initMongodb() (*mongo.Database, error) { }, }, options.CreateIndexes()) + mongodb.CreateCollection(ctx, Collections.Config, options.CreateCollection()) + return mongodb, nil } diff --git a/server/db/user.go b/server/db/user.go index 60254fa..f020dcf 100644 --- a/server/db/user.go +++ b/server/db/user.go @@ -43,7 +43,7 @@ func (mgr *manager) AddUser(user User) (User, error) { } if user.Roles == "" { - user.Roles = constants.DEFAULT_ROLES[0] + user.Roles = constants.EnvData.DEFAULT_ROLES[0] } if IsORMSupported { diff --git a/server/email/email.go b/server/email/email.go index 3b2bf60..0136e1b 100644 --- a/server/email/email.go +++ b/server/email/email.go @@ -27,7 +27,7 @@ type Sender struct { } func NewSender() Sender { - return Sender{User: constants.SENDER_EMAIL, Password: constants.SENDER_PASSWORD} + return Sender{User: constants.EnvData.SENDER_EMAIL, Password: constants.EnvData.SENDER_PASSWORD} } func (sender Sender) SendMail(Dest []string, Subject, bodyMessage string) error { @@ -35,8 +35,8 @@ func (sender Sender) SendMail(Dest []string, Subject, bodyMessage string) error "To: " + strings.Join(Dest, ",") + "\n" + "Subject: " + Subject + "\n" + bodyMessage - err := smtp.SendMail(constants.SMTP_HOST+":"+constants.SMTP_PORT, - smtp.PlainAuth("", sender.User, sender.Password, constants.SMTP_HOST), + err := smtp.SendMail(constants.EnvData.SMTP_HOST+":"+constants.EnvData.SMTP_PORT, + smtp.PlainAuth("", sender.User, sender.Password, constants.EnvData.SMTP_HOST), sender.User, Dest, []byte(msg)) if err != nil { diff --git a/server/env/env.go b/server/env/env.go index 0ee0294..fa0f135 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -7,6 +7,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/utils" + "github.com/google/uuid" "github.com/joho/godotenv" ) @@ -20,163 +21,169 @@ var ( // InitEnv -> to initialize env and through error if required env are not present func InitEnv() { - if constants.ENV_PATH == "" { - constants.ENV_PATH = `.env` + if constants.EnvData.ENV_PATH == "" { + constants.EnvData.ENV_PATH = `.env` } if ARG_ENV_FILE != nil && *ARG_ENV_FILE != "" { - constants.ENV_PATH = *ARG_ENV_FILE + constants.EnvData.ENV_PATH = *ARG_ENV_FILE } - err := godotenv.Load(constants.ENV_PATH) + err := godotenv.Load(constants.EnvData.ENV_PATH) if err != nil { - log.Printf("error loading %s file", constants.ENV_PATH) + log.Printf("error loading %s file", constants.EnvData.ENV_PATH) } - if constants.ADMIN_SECRET == "" { - constants.ADMIN_SECRET = os.Getenv("ADMIN_SECRET") - if constants.ADMIN_SECRET == "" { - panic("root admin secret is required") - } + if constants.EnvData.ADMIN_SECRET == "" { + constants.EnvData.ADMIN_SECRET = os.Getenv("ADMIN_SECRET") } - if constants.ENV == "" { - constants.ENV = os.Getenv("ENV") - if constants.ENV == "" { - constants.ENV = "production" - } - - if constants.ENV == "production" { - constants.IS_PROD = true - os.Setenv("GIN_MODE", "release") - } else { - constants.IS_PROD = false - } - } - - if constants.DATABASE_TYPE == "" { - constants.DATABASE_TYPE = os.Getenv("DATABASE_TYPE") - log.Println(constants.DATABASE_TYPE) + if constants.EnvData.DATABASE_TYPE == "" { + constants.EnvData.DATABASE_TYPE = os.Getenv("DATABASE_TYPE") + log.Println(constants.EnvData.DATABASE_TYPE) if ARG_DB_TYPE != nil && *ARG_DB_TYPE != "" { - constants.DATABASE_TYPE = *ARG_DB_TYPE + constants.EnvData.DATABASE_TYPE = *ARG_DB_TYPE } - if constants.DATABASE_TYPE == "" { + if constants.EnvData.DATABASE_TYPE == "" { panic("DATABASE_TYPE is required") } } - if constants.DATABASE_URL == "" { - constants.DATABASE_URL = os.Getenv("DATABASE_URL") + if constants.EnvData.DATABASE_URL == "" { + constants.EnvData.DATABASE_URL = os.Getenv("DATABASE_URL") if ARG_DB_URL != nil && *ARG_DB_URL != "" { - constants.DATABASE_URL = *ARG_DB_URL + constants.EnvData.DATABASE_URL = *ARG_DB_URL } - if constants.DATABASE_URL == "" { + if constants.EnvData.DATABASE_URL == "" { panic("DATABASE_URL is required") } } - if constants.DATABASE_NAME == "" { - constants.DATABASE_NAME = os.Getenv("DATABASE_NAME") - if constants.DATABASE_NAME == "" { - constants.DATABASE_NAME = "authorizer" + if constants.EnvData.DATABASE_NAME == "" { + constants.EnvData.DATABASE_NAME = os.Getenv("DATABASE_NAME") + if constants.EnvData.DATABASE_NAME == "" { + constants.EnvData.DATABASE_NAME = "authorizer" } } - if constants.SMTP_HOST == "" { - constants.SMTP_HOST = os.Getenv("SMTP_HOST") - } + if constants.EnvData.ENV == "" { + constants.EnvData.ENV = os.Getenv("ENV") + if constants.EnvData.ENV == "" { + constants.EnvData.ENV = "production" + } - if constants.SMTP_PORT == "" { - constants.SMTP_PORT = os.Getenv("SMTP_PORT") - } - - if constants.SENDER_EMAIL == "" { - constants.SENDER_EMAIL = os.Getenv("SENDER_EMAIL") - } - - if constants.SENDER_PASSWORD == "" { - constants.SENDER_PASSWORD = os.Getenv("SENDER_PASSWORD") - } - - if constants.JWT_SECRET == "" { - constants.JWT_SECRET = os.Getenv("JWT_SECRET") - } - - if constants.JWT_TYPE == "" { - constants.JWT_TYPE = os.Getenv("JWT_TYPE") - } - - if constants.JWT_ROLE_CLAIM == "" { - constants.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM") - - if constants.JWT_ROLE_CLAIM == "" { - constants.JWT_ROLE_CLAIM = "role" + if constants.EnvData.ENV == "production" { + constants.EnvData.IS_PROD = true + os.Setenv("GIN_MODE", "release") + } else { + constants.EnvData.IS_PROD = false } } - if constants.AUTHORIZER_URL == "" { - constants.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/") + if constants.EnvData.SMTP_HOST == "" { + constants.EnvData.SMTP_HOST = os.Getenv("SMTP_HOST") + } + + if constants.EnvData.SMTP_PORT == "" { + constants.EnvData.SMTP_PORT = os.Getenv("SMTP_PORT") + } + + if constants.EnvData.SENDER_EMAIL == "" { + constants.EnvData.SENDER_EMAIL = os.Getenv("SENDER_EMAIL") + } + + if constants.EnvData.SENDER_PASSWORD == "" { + constants.EnvData.SENDER_PASSWORD = os.Getenv("SENDER_PASSWORD") + } + + if constants.EnvData.JWT_SECRET == "" { + constants.EnvData.JWT_SECRET = os.Getenv("JWT_SECRET") + if constants.EnvData.JWT_SECRET == "" { + constants.EnvData.JWT_SECRET = uuid.New().String() + } + } + + if constants.EnvData.JWT_TYPE == "" { + constants.EnvData.JWT_TYPE = os.Getenv("JWT_TYPE") + if constants.EnvData.JWT_TYPE == "" { + constants.EnvData.JWT_TYPE = "HS256" + } + } + + if constants.EnvData.JWT_ROLE_CLAIM == "" { + constants.EnvData.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM") + + if constants.EnvData.JWT_ROLE_CLAIM == "" { + constants.EnvData.JWT_ROLE_CLAIM = "role" + } + } + + if constants.EnvData.AUTHORIZER_URL == "" { + constants.EnvData.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/") if ARG_AUTHORIZER_URL != nil && *ARG_AUTHORIZER_URL != "" { - constants.AUTHORIZER_URL = *ARG_AUTHORIZER_URL + constants.EnvData.AUTHORIZER_URL = *ARG_AUTHORIZER_URL } } - if constants.PORT == "" { - constants.PORT = os.Getenv("PORT") - if constants.PORT == "" { - constants.PORT = "8080" + if constants.EnvData.PORT == "" { + constants.EnvData.PORT = os.Getenv("PORT") + if constants.EnvData.PORT == "" { + constants.EnvData.PORT = "8080" } } - if constants.REDIS_URL == "" { - constants.REDIS_URL = os.Getenv("REDIS_URL") + if constants.EnvData.REDIS_URL == "" { + constants.EnvData.REDIS_URL = os.Getenv("REDIS_URL") } - if constants.COOKIE_NAME == "" { - constants.COOKIE_NAME = os.Getenv("COOKIE_NAME") + if constants.EnvData.COOKIE_NAME == "" { + constants.EnvData.COOKIE_NAME = os.Getenv("COOKIE_NAME") + if constants.EnvData.COOKIE_NAME == "" { + constants.EnvData.COOKIE_NAME = "authorizer" + } } - if constants.GOOGLE_CLIENT_ID == "" { - constants.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID") + if constants.EnvData.GOOGLE_CLIENT_ID == "" { + constants.EnvData.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID") } - if constants.GOOGLE_CLIENT_SECRET == "" { - constants.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET") + if constants.EnvData.GOOGLE_CLIENT_SECRET == "" { + constants.EnvData.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET") } - if constants.GITHUB_CLIENT_ID == "" { - constants.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID") + if constants.EnvData.GITHUB_CLIENT_ID == "" { + constants.EnvData.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID") } - if constants.GITHUB_CLIENT_SECRET == "" { - constants.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET") + if constants.EnvData.GITHUB_CLIENT_SECRET == "" { + constants.EnvData.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET") } - if constants.FACEBOOK_CLIENT_ID == "" { - constants.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID") + if constants.EnvData.FACEBOOK_CLIENT_ID == "" { + constants.EnvData.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID") } - if constants.FACEBOOK_CLIENT_SECRET == "" { - constants.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET") + if constants.EnvData.FACEBOOK_CLIENT_SECRET == "" { + constants.EnvData.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET") } - if constants.RESET_PASSWORD_URL == "" { - constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/") + if constants.EnvData.RESET_PASSWORD_URL == "" { + constants.EnvData.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/") } - constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true" - constants.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true" - constants.DISABLE_MAGIC_LINK_LOGIN = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true" - constants.DISABLE_LOGIN_PAGE = os.Getenv("DISABLE_LOGIN_PAGE") == "true" + constants.EnvData.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true" + constants.EnvData.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true" + constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true" + constants.EnvData.DISABLE_LOGIN_PAGE = os.Getenv("DISABLE_LOGIN_PAGE") == "true" - if constants.SMTP_HOST == "" || constants.SENDER_EMAIL == "" || constants.SENDER_PASSWORD == "" { - constants.DISABLE_EMAIL_VERIFICATION = true - constants.DISABLE_MAGIC_LINK_LOGIN = true + if constants.EnvData.SMTP_HOST == "" || constants.EnvData.SENDER_EMAIL == "" || constants.EnvData.SENDER_PASSWORD == "" { + constants.EnvData.DISABLE_EMAIL_VERIFICATION = true + constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true } allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",") @@ -205,18 +212,10 @@ func InitEnv() { allowedOrigins = []string{"*"} } - constants.ALLOWED_ORIGINS = allowedOrigins + constants.EnvData.ALLOWED_ORIGINS = allowedOrigins - if constants.JWT_TYPE == "" { - constants.JWT_TYPE = "HS256" - } - - if constants.COOKIE_NAME == "" { - constants.COOKIE_NAME = "authorizer" - } - - if constants.DISABLE_EMAIL_VERIFICATION { - constants.DISABLE_MAGIC_LINK_LOGIN = true + if constants.EnvData.DISABLE_EMAIL_VERIFICATION { + constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true } rolesEnv := strings.TrimSpace(os.Getenv("ROLES")) @@ -256,19 +255,19 @@ func InitEnv() { } } - if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRoleSplit) > 0 { + if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRolesEnv) > 0 { panic(`Invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`) } - constants.ROLES = roles - constants.DEFAULT_ROLES = defaultRoles - constants.PROTECTED_ROLES = protectedRoles + constants.EnvData.ROLES = roles + constants.EnvData.DEFAULT_ROLES = defaultRoles + constants.EnvData.PROTECTED_ROLES = protectedRoles if os.Getenv("ORGANIZATION_NAME") != "" { - constants.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME") + constants.EnvData.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME") } if os.Getenv("ORGANIZATION_LOGO") != "" { - constants.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO") + constants.EnvData.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO") } } diff --git a/server/env/persist_env.go b/server/env/persist_env.go new file mode 100644 index 0000000..7ce535c --- /dev/null +++ b/server/env/persist_env.go @@ -0,0 +1,152 @@ +package env + +import ( + "encoding/json" + "log" + "os" + "reflect" + "strings" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/utils" + "github.com/google/uuid" +) + +func PersistEnv() error { + config, err := db.Mgr.GetConfig() + // config not found in db + if err != nil { + // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid + hash := uuid.New().String()[:36-4] + constants.EnvData.ENCRYPTION_KEY = hash + encodedHash := utils.EncryptB64(hash) + + configData, err := json.Marshal(constants.EnvData) + if err != nil { + return err + } + encryptedConfig, err := utils.EncryptAES(configData) + if err != nil { + return err + } + + config = db.Config{ + Hash: encodedHash, + Config: encryptedConfig, + } + + db.Mgr.AddConfig(config) + } else { + // decrypt the config data from db + // decryption can be done using the hash stored in db + encryptionKey := config.Hash + decryptedEncryptionKey, err := utils.DecryptB64(encryptionKey) + if err != nil { + return err + } + constants.EnvData.ENCRYPTION_KEY = decryptedEncryptionKey + decryptedConfigs, err := utils.DecryptAES(config.Config) + if err != nil { + return err + } + + // temp json to validate with env + var jsonData map[string]interface{} + + err = json.Unmarshal(decryptedConfigs, &jsonData) + if err != nil { + return err + } + + // if env is changed via env file or OS env + // give that higher preference and update db, but we don't recommend it + + hasChanged := false + + for key, value := range jsonData { + fieldType := reflect.TypeOf(value).String() + + // check only for derivative keys + // No need to check for ENCRYPTION_KEY which special key we use for encrypting config data + // as we have removed it from json + envValue := strings.TrimSpace(os.Getenv(key)) + + // env is not empty + if envValue != "" { + // check the type + // currently we have 3 types of env vars: string, bool, []string{} + if fieldType == "string" { + if value != envValue { + jsonData[key] = envValue + hasChanged = true + } + } + + if fieldType == "bool" { + newValue := envValue == "true" + if value != newValue { + jsonData[key] = newValue + hasChanged = true + } + } + + if fieldType == "[]interface {}" { + stringArr := []string{} + envStringArr := strings.Split(envValue, ",") + for _, v := range value.([]interface{}) { + stringArr = append(stringArr, v.(string)) + } + if !utils.IsStringArrayEqual(stringArr, envStringArr) { + jsonData[key] = envStringArr + } + } + } + } + + // handle derivative cases like disabling email verification & magic login + // in case SMTP is off but env is set to true + if jsonData["SMTP_HOST"] == "" || jsonData["SENDER_EMAIL"] == "" || jsonData["SENDER_PASSWORD"] == "" { + if !jsonData["DISABLE_EMAIL_VERIFICATION"].(bool) { + jsonData["DISABLE_EMAIL_VERIFICATION"] = true + hasChanged = true + } + + if !jsonData["DISABLE_MAGIC_LINK_LOGIN"].(bool) { + jsonData["DISABLE_MAGIC_LINK_LOGIN"] = true + hasChanged = true + } + } + + if hasChanged { + jsonBytes, err := json.Marshal(jsonData) + if err != nil { + return err + } + + err = json.Unmarshal(jsonBytes, &constants.EnvData) + if err != nil { + return err + } + + configData, err := json.Marshal(constants.EnvData) + if err != nil { + return err + } + encryptedConfig, err := utils.EncryptAES(configData) + if err != nil { + return err + } + + config.Config = encryptedConfig + _, err = db.Mgr.UpdateConfig(config) + if err != nil { + log.Println("error updating config:", err) + return err + } + } + + } + + return nil +} diff --git a/server/go.mod b/server/go.mod index 04b55a4..982e431 100644 --- a/server/go.mod +++ b/server/go.mod @@ -20,7 +20,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f - github.com/stretchr/testify v1.7.0 github.com/ugorji/go v1.2.6 // indirect github.com/vektah/gqlparser/v2 v2.2.0 go.mongodb.org/mongo-driver v1.8.1 diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 300307a..c7f2882 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -43,6 +43,11 @@ type DirectiveRoot struct { } type ComplexityRoot struct { + AdminLoginResponse struct { + AccessToken func(childComplexity int) int + Message func(childComplexity int) int + } + AuthResponse struct { AccessToken func(childComplexity int) int ExpiresAt func(childComplexity int) int @@ -50,6 +55,41 @@ type ComplexityRoot struct { User func(childComplexity int) int } + Config struct { + AdminSecret func(childComplexity int) int + AllowedOrigins func(childComplexity int) int + AppURL func(childComplexity int) int + AuthorizerURL func(childComplexity int) int + CookieName func(childComplexity int) int + DatabaseName func(childComplexity int) int + DatabaseType func(childComplexity int) int + DatabaseURL func(childComplexity int) int + DefaultRoles func(childComplexity int) int + DisableBasicAuthentication func(childComplexity int) int + DisableEmailVerification func(childComplexity int) int + DisableLoginPage func(childComplexity int) int + DisableMagicLinkLogin func(childComplexity int) int + FacebookClientID func(childComplexity int) int + FacebookClientSecret func(childComplexity int) int + GithubClientID func(childComplexity int) int + GithubClientSecret func(childComplexity int) int + GoogleClientID func(childComplexity int) int + GoogleClientSecret func(childComplexity int) int + JwtRoleClaim func(childComplexity int) int + JwtSecret func(childComplexity int) int + JwtType func(childComplexity int) int + OrganizationLogo func(childComplexity int) int + OrganizationName func(childComplexity int) int + ProtectedRoles func(childComplexity int) int + RedisURL func(childComplexity int) int + ResetPasswordURL func(childComplexity int) int + Roles func(childComplexity int) int + SMTPHost func(childComplexity int) int + SMTPPort func(childComplexity int) int + SenderEmail func(childComplexity int) int + SenderPassword func(childComplexity int) int + } + Error struct { Message func(childComplexity int) int Reason func(childComplexity int) int @@ -66,6 +106,7 @@ type ComplexityRoot struct { } Mutation struct { + AdminLogin func(childComplexity int, params model.AdminLoginInput) int DeleteUser func(childComplexity int, params model.DeleteUserInput) int ForgotPassword func(childComplexity int, params model.ForgotPasswordInput) int Login func(childComplexity int, params model.LoginInput) int @@ -74,12 +115,15 @@ type ComplexityRoot struct { ResendVerifyEmail func(childComplexity int, params model.ResendVerifyEmailInput) int ResetPassword func(childComplexity int, params model.ResetPasswordInput) int Signup func(childComplexity int, params model.SignUpInput) int + UpdateConfig func(childComplexity int, params model.UpdateConfigInput) int UpdateProfile func(childComplexity int, params model.UpdateProfileInput) int UpdateUser func(childComplexity int, params model.UpdateUserInput) int VerifyEmail func(childComplexity int, params model.VerifyEmailInput) int } Query struct { + AdminSession func(childComplexity int) int + Config func(childComplexity int) int Meta func(childComplexity int) int Profile func(childComplexity int) int Session func(childComplexity int, roles []string) int @@ -134,6 +178,8 @@ type MutationResolver interface { ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) + AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) + UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) } type QueryResolver interface { Meta(ctx context.Context) (*model.Meta, error) @@ -141,6 +187,8 @@ type QueryResolver interface { Profile(ctx context.Context) (*model.User, error) Users(ctx context.Context) ([]*model.User, error) VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) + AdminSession(ctx context.Context) (*model.AdminLoginResponse, error) + Config(ctx context.Context) (*model.Config, error) } type executableSchema struct { @@ -158,6 +206,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in _ = ec switch typeName + "." + field { + case "AdminLoginResponse.access_token": + if e.complexity.AdminLoginResponse.AccessToken == nil { + break + } + + return e.complexity.AdminLoginResponse.AccessToken(childComplexity), true + + case "AdminLoginResponse.message": + if e.complexity.AdminLoginResponse.Message == nil { + break + } + + return e.complexity.AdminLoginResponse.Message(childComplexity), true + case "AuthResponse.access_token": if e.complexity.AuthResponse.AccessToken == nil { break @@ -186,6 +248,230 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.AuthResponse.User(childComplexity), true + case "Config.ADMIN_SECRET": + if e.complexity.Config.AdminSecret == nil { + break + } + + return e.complexity.Config.AdminSecret(childComplexity), true + + case "Config.ALLOWED_ORIGINS": + if e.complexity.Config.AllowedOrigins == nil { + break + } + + return e.complexity.Config.AllowedOrigins(childComplexity), true + + case "Config.APP_URL": + if e.complexity.Config.AppURL == nil { + break + } + + return e.complexity.Config.AppURL(childComplexity), true + + case "Config.AUTHORIZER_URL": + if e.complexity.Config.AuthorizerURL == nil { + break + } + + return e.complexity.Config.AuthorizerURL(childComplexity), true + + case "Config.COOKIE_NAME": + if e.complexity.Config.CookieName == nil { + break + } + + return e.complexity.Config.CookieName(childComplexity), true + + case "Config.DATABASE_NAME": + if e.complexity.Config.DatabaseName == nil { + break + } + + return e.complexity.Config.DatabaseName(childComplexity), true + + case "Config.DATABASE_TYPE": + if e.complexity.Config.DatabaseType == nil { + break + } + + return e.complexity.Config.DatabaseType(childComplexity), true + + case "Config.DATABASE_URL": + if e.complexity.Config.DatabaseURL == nil { + break + } + + return e.complexity.Config.DatabaseURL(childComplexity), true + + case "Config.DEFAULT_ROLES": + if e.complexity.Config.DefaultRoles == nil { + break + } + + return e.complexity.Config.DefaultRoles(childComplexity), true + + case "Config.DISABLE_BASIC_AUTHENTICATION": + if e.complexity.Config.DisableBasicAuthentication == nil { + break + } + + return e.complexity.Config.DisableBasicAuthentication(childComplexity), true + + case "Config.DISABLE_EMAIL_VERIFICATION": + if e.complexity.Config.DisableEmailVerification == nil { + break + } + + return e.complexity.Config.DisableEmailVerification(childComplexity), true + + case "Config.DISABLE_LOGIN_PAGE": + if e.complexity.Config.DisableLoginPage == nil { + break + } + + return e.complexity.Config.DisableLoginPage(childComplexity), true + + case "Config.DISABLE_MAGIC_LINK_LOGIN": + if e.complexity.Config.DisableMagicLinkLogin == nil { + break + } + + return e.complexity.Config.DisableMagicLinkLogin(childComplexity), true + + case "Config.FACEBOOK_CLIENT_ID": + if e.complexity.Config.FacebookClientID == nil { + break + } + + return e.complexity.Config.FacebookClientID(childComplexity), true + + case "Config.FACEBOOK_CLIENT_SECRET": + if e.complexity.Config.FacebookClientSecret == nil { + break + } + + return e.complexity.Config.FacebookClientSecret(childComplexity), true + + case "Config.GITHUB_CLIENT_ID": + if e.complexity.Config.GithubClientID == nil { + break + } + + return e.complexity.Config.GithubClientID(childComplexity), true + + case "Config.GITHUB_CLIENT_SECRET": + if e.complexity.Config.GithubClientSecret == nil { + break + } + + return e.complexity.Config.GithubClientSecret(childComplexity), true + + case "Config.GOOGLE_CLIENT_ID": + if e.complexity.Config.GoogleClientID == nil { + break + } + + return e.complexity.Config.GoogleClientID(childComplexity), true + + case "Config.GOOGLE_CLIENT_SECRET": + if e.complexity.Config.GoogleClientSecret == nil { + break + } + + return e.complexity.Config.GoogleClientSecret(childComplexity), true + + case "Config.JWT_ROLE_CLAIM": + if e.complexity.Config.JwtRoleClaim == nil { + break + } + + return e.complexity.Config.JwtRoleClaim(childComplexity), true + + case "Config.JWT_SECRET": + if e.complexity.Config.JwtSecret == nil { + break + } + + return e.complexity.Config.JwtSecret(childComplexity), true + + case "Config.JWT_TYPE": + if e.complexity.Config.JwtType == nil { + break + } + + return e.complexity.Config.JwtType(childComplexity), true + + case "Config.ORGANIZATION_LOGO": + if e.complexity.Config.OrganizationLogo == nil { + break + } + + return e.complexity.Config.OrganizationLogo(childComplexity), true + + case "Config.ORGANIZATION_NAME": + if e.complexity.Config.OrganizationName == nil { + break + } + + return e.complexity.Config.OrganizationName(childComplexity), true + + case "Config.PROTECTED_ROLES": + if e.complexity.Config.ProtectedRoles == nil { + break + } + + return e.complexity.Config.ProtectedRoles(childComplexity), true + + case "Config.REDIS_URL": + if e.complexity.Config.RedisURL == nil { + break + } + + return e.complexity.Config.RedisURL(childComplexity), true + + case "Config.RESET_PASSWORD_URL": + if e.complexity.Config.ResetPasswordURL == nil { + break + } + + return e.complexity.Config.ResetPasswordURL(childComplexity), true + + case "Config.ROLES": + if e.complexity.Config.Roles == nil { + break + } + + return e.complexity.Config.Roles(childComplexity), true + + case "Config.SMTP_HOST": + if e.complexity.Config.SMTPHost == nil { + break + } + + return e.complexity.Config.SMTPHost(childComplexity), true + + case "Config.SMTP_PORT": + if e.complexity.Config.SMTPPort == nil { + break + } + + return e.complexity.Config.SMTPPort(childComplexity), true + + case "Config.SENDER_EMAIL": + if e.complexity.Config.SenderEmail == nil { + break + } + + return e.complexity.Config.SenderEmail(childComplexity), true + + case "Config.SENDER_PASSWORD": + if e.complexity.Config.SenderPassword == nil { + break + } + + return e.complexity.Config.SenderPassword(childComplexity), true + case "Error.message": if e.complexity.Error.Message == nil { break @@ -249,6 +535,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Meta.Version(childComplexity), true + case "Mutation._admin_login": + if e.complexity.Mutation.AdminLogin == nil { + break + } + + args, err := ec.field_Mutation__admin_login_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.AdminLogin(childComplexity, args["params"].(model.AdminLoginInput)), true + case "Mutation._delete_user": if e.complexity.Mutation.DeleteUser == nil { break @@ -340,6 +638,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.Signup(childComplexity, args["params"].(model.SignUpInput)), true + case "Mutation._update_config": + if e.complexity.Mutation.UpdateConfig == nil { + break + } + + args, err := ec.field_Mutation__update_config_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateConfig(childComplexity, args["params"].(model.UpdateConfigInput)), true + case "Mutation.update_profile": if e.complexity.Mutation.UpdateProfile == nil { break @@ -376,6 +686,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.VerifyEmail(childComplexity, args["params"].(model.VerifyEmailInput)), true + case "Query._admin_session": + if e.complexity.Query.AdminSession == nil { + break + } + + return e.complexity.Query.AdminSession(childComplexity), true + + case "Query._config": + if e.complexity.Query.Config == nil { + break + } + + return e.complexity.Query.Config(childComplexity), true + case "Query.meta": if e.complexity.Query.Meta == nil { break @@ -719,6 +1043,85 @@ type Response { message: String! } +type AdminLoginResponse { + message: String! + access_token: String! +} + +type Config { + ADMIN_SECRET: String + DATABASE_TYPE: String + DATABASE_URL: String + DATABASE_NAME: String + SMTP_HOST: String + SMTP_PORT: String + SENDER_EMAIL: String + SENDER_PASSWORD: String + JWT_TYPE: String + JWT_SECRET: String + ALLOWED_ORIGINS: [String!] + AUTHORIZER_URL: String + APP_URL: String + REDIS_URL: String + COOKIE_NAME: String + RESET_PASSWORD_URL: String + DISABLE_EMAIL_VERIFICATION: Boolean + DISABLE_BASIC_AUTHENTICATION: Boolean + DISABLE_MAGIC_LINK_LOGIN: Boolean + DISABLE_LOGIN_PAGE: Boolean + ROLES: [String!] + PROTECTED_ROLES: [String!] + DEFAULT_ROLES: [String!] + JWT_ROLE_CLAIM: String + GOOGLE_CLIENT_ID: String + GOOGLE_CLIENT_SECRET: String + GITHUB_CLIENT_ID: String + GITHUB_CLIENT_SECRET: String + FACEBOOK_CLIENT_ID: String + FACEBOOK_CLIENT_SECRET: String + ORGANIZATION_NAME: String + ORGANIZATION_LOGO: String +} + +input UpdateConfigInput { + ADMIN_SECRET: String + DATABASE_TYPE: String + DATABASE_URL: String + DATABASE_NAME: String + SMTP_HOST: String + SMTP_PORT: String + SENDER_EMAIL: String + SENDER_PASSWORD: String + JWT_TYPE: String + JWT_SECRET: String + ALLOWED_ORIGINS: [String!] + AUTHORIZER_URL: String + APP_URL: String + REDIS_URL: String + COOKIE_NAME: String + RESET_PASSWORD_URL: String + DISABLE_EMAIL_VERIFICATION: Boolean + DISABLE_BASIC_AUTHENTICATION: Boolean + DISABLE_MAGIC_LINK_LOGIN: Boolean + DISABLE_LOGIN_PAGE: Boolean + ROLES: [String!] + PROTECTED_ROLES: [String!] + DEFAULT_ROLES: [String!] + JWT_ROLE_CLAIM: String + GOOGLE_CLIENT_ID: String + GOOGLE_CLIENT_SECRET: String + GITHUB_CLIENT_ID: String + GITHUB_CLIENT_SECRET: String + FACEBOOK_CLIENT_ID: String + FACEBOOK_CLIENT_SECRET: String + ORGANIZATION_NAME: String + ORGANIZATION_LOGO: String +} + +input AdminLoginInput { + admin_secret: String! +} + input SignUpInput { email: String! given_name: String @@ -810,15 +1213,19 @@ type Mutation { # admin only apis _delete_user(params: DeleteUserInput!): Response! _update_user(params: UpdateUserInput!): User! + _admin_login(params: AdminLoginInput!): AdminLoginResponse! + _update_config(params: UpdateConfigInput!): Response! } type Query { meta: Meta! - session(roles: [String!]): AuthResponse + session(roles: [String!]): AuthResponse! profile: User! # admin only apis _users: [User!]! _verification_requests: [VerificationRequest!]! + _admin_session: AdminLoginResponse! + _config: Config! } `, BuiltIn: false}, } @@ -828,6 +1235,21 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** +func (ec *executionContext) field_Mutation__admin_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.AdminLoginInput + if tmp, ok := rawArgs["params"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + arg0, err = ec.unmarshalNAdminLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["params"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -843,6 +1265,21 @@ func (ec *executionContext) field_Mutation__delete_user_args(ctx context.Context return args, nil } +func (ec *executionContext) field_Mutation__update_config_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.UpdateConfigInput + if tmp, ok := rawArgs["params"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("params")) + arg0, err = ec.unmarshalNUpdateConfigInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateConfigInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["params"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation__update_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1046,6 +1483,76 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg // region **************************** field.gotpl ***************************** +func (ec *executionContext) _AdminLoginResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.AdminLoginResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AdminLoginResponse", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _AdminLoginResponse_access_token(ctx context.Context, field graphql.CollectedField, obj *model.AdminLoginResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "AdminLoginResponse", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AccessToken, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _AuthResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.AuthResponse) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1177,6 +1684,1030 @@ func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphq return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } +func (ec *executionContext) _Config_ADMIN_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AdminSecret, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DATABASE_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DatabaseType, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DATABASE_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DatabaseURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DATABASE_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DatabaseName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_SMTP_HOST(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SMTPHost, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_SMTP_PORT(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SMTPPort, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SenderEmail, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_SENDER_PASSWORD(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SenderPassword, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_JWT_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.JwtType, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_JWT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.JwtSecret, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_ALLOWED_ORIGINS(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AllowedOrigins, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_AUTHORIZER_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AuthorizerURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_APP_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AppURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_REDIS_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RedisURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_COOKIE_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CookieName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_RESET_PASSWORD_URL(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ResetPasswordURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DISABLE_EMAIL_VERIFICATION(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisableEmailVerification, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DISABLE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisableBasicAuthentication, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisableMagicLinkLogin, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DISABLE_LOGIN_PAGE(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DisableLoginPage, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*bool) + fc.Result = res + return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Roles, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_PROTECTED_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProtectedRoles, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_DEFAULT_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DefaultRoles, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_JWT_ROLE_CLAIM(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.JwtRoleClaim, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_GOOGLE_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GoogleClientID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_GOOGLE_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GoogleClientSecret, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_GITHUB_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GithubClientID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_GITHUB_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GithubClientSecret, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_FACEBOOK_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FacebookClientID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_FACEBOOK_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FacebookClientSecret, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OrganizationName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Config_ORGANIZATION_LOGO(ctx context.Context, field graphql.CollectedField, obj *model.Config) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Config", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OrganizationLogo, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1947,6 +3478,90 @@ func (ec *executionContext) _Mutation__update_user(ctx context.Context, field gr return ec.marshalNUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation__admin_login(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation__admin_login_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AdminLogin(rctx, args["params"].(model.AdminLoginInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.AdminLoginResponse) + fc.Result = res + return ec.marshalNAdminLoginResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) _Mutation__update_config(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation__update_config_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().UpdateConfig(rctx, args["params"].(model.UpdateConfigInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Response) + fc.Result = res + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_meta(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -2014,11 +3629,14 @@ func (ec *executionContext) _Query_session(ctx context.Context, field graphql.Co return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } res := resTmp.(*model.AuthResponse) fc.Result = res - return ec.marshalOAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) + return ec.marshalNAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx, field.Selections, res) } func (ec *executionContext) _Query_profile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { @@ -2126,6 +3744,76 @@ func (ec *executionContext) _Query__verification_requests(ctx context.Context, f return ec.marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx, field.Selections, res) } +func (ec *executionContext) _Query__admin_session(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().AdminSession(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.AdminLoginResponse) + fc.Result = res + return ec.marshalNAdminLoginResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) _Query__config(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Config(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Config) + fc.Result = res + return ec.marshalNConfig2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx, field.Selections, res) +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -4140,6 +5828,29 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co // region **************************** input.gotpl ***************************** +func (ec *executionContext) unmarshalInputAdminLoginInput(ctx context.Context, obj interface{}) (model.AdminLoginInput, error) { + var it model.AdminLoginInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + for k, v := range asMap { + switch k { + case "admin_secret": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("admin_secret")) + it.AdminSecret, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeleteUserInput(ctx context.Context, obj interface{}) (model.DeleteUserInput, error) { var it model.DeleteUserInput asMap := map[string]interface{}{} @@ -4437,6 +6148,277 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i return it, nil } +func (ec *executionContext) unmarshalInputUpdateConfigInput(ctx context.Context, obj interface{}) (model.UpdateConfigInput, error) { + var it model.UpdateConfigInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + for k, v := range asMap { + switch k { + case "ADMIN_SECRET": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ADMIN_SECRET")) + it.AdminSecret, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "DATABASE_TYPE": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_TYPE")) + it.DatabaseType, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "DATABASE_URL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_URL")) + it.DatabaseURL, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "DATABASE_NAME": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DATABASE_NAME")) + it.DatabaseName, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "SMTP_HOST": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_HOST")) + it.SMTPHost, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "SMTP_PORT": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_PORT")) + it.SMTPPort, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "SENDER_EMAIL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SENDER_EMAIL")) + it.SenderEmail, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "SENDER_PASSWORD": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SENDER_PASSWORD")) + it.SenderPassword, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "JWT_TYPE": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_TYPE")) + it.JwtType, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "JWT_SECRET": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_SECRET")) + it.JwtSecret, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "ALLOWED_ORIGINS": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ALLOWED_ORIGINS")) + it.AllowedOrigins, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "AUTHORIZER_URL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("AUTHORIZER_URL")) + it.AuthorizerURL, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "APP_URL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("APP_URL")) + it.AppURL, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "REDIS_URL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("REDIS_URL")) + it.RedisURL, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "COOKIE_NAME": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("COOKIE_NAME")) + it.CookieName, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "RESET_PASSWORD_URL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("RESET_PASSWORD_URL")) + it.ResetPasswordURL, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "DISABLE_EMAIL_VERIFICATION": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_EMAIL_VERIFICATION")) + it.DisableEmailVerification, err = ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + case "DISABLE_BASIC_AUTHENTICATION": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_BASIC_AUTHENTICATION")) + it.DisableBasicAuthentication, err = ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + case "DISABLE_MAGIC_LINK_LOGIN": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_MAGIC_LINK_LOGIN")) + it.DisableMagicLinkLogin, err = ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + case "DISABLE_LOGIN_PAGE": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_LOGIN_PAGE")) + it.DisableLoginPage, err = ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + case "ROLES": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ROLES")) + it.Roles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "PROTECTED_ROLES": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("PROTECTED_ROLES")) + it.ProtectedRoles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "DEFAULT_ROLES": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DEFAULT_ROLES")) + it.DefaultRoles, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "JWT_ROLE_CLAIM": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_ROLE_CLAIM")) + it.JwtRoleClaim, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "GOOGLE_CLIENT_ID": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GOOGLE_CLIENT_ID")) + it.GoogleClientID, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "GOOGLE_CLIENT_SECRET": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GOOGLE_CLIENT_SECRET")) + it.GoogleClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "GITHUB_CLIENT_ID": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GITHUB_CLIENT_ID")) + it.GithubClientID, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "GITHUB_CLIENT_SECRET": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("GITHUB_CLIENT_SECRET")) + it.GithubClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "FACEBOOK_CLIENT_ID": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("FACEBOOK_CLIENT_ID")) + it.FacebookClientID, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "FACEBOOK_CLIENT_SECRET": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("FACEBOOK_CLIENT_SECRET")) + it.FacebookClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "ORGANIZATION_NAME": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ORGANIZATION_NAME")) + it.OrganizationName, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "ORGANIZATION_LOGO": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ORGANIZATION_LOGO")) + it.OrganizationLogo, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context, obj interface{}) (model.UpdateProfileInput, error) { var it model.UpdateProfileInput asMap := map[string]interface{}{} @@ -4682,6 +6664,38 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context, // region **************************** object.gotpl **************************** +var adminLoginResponseImplementors = []string{"AdminLoginResponse"} + +func (ec *executionContext) _AdminLoginResponse(ctx context.Context, sel ast.SelectionSet, obj *model.AdminLoginResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, adminLoginResponseImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("AdminLoginResponse") + case "message": + out.Values[i] = ec._AdminLoginResponse_message(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "access_token": + out.Values[i] = ec._AdminLoginResponse_access_token(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var authResponseImplementors = []string{"AuthResponse"} func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.SelectionSet, obj *model.AuthResponse) graphql.Marshaler { @@ -4715,6 +6729,92 @@ func (ec *executionContext) _AuthResponse(ctx context.Context, sel ast.Selection return out } +var configImplementors = []string{"Config"} + +func (ec *executionContext) _Config(ctx context.Context, sel ast.SelectionSet, obj *model.Config) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, configImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Config") + case "ADMIN_SECRET": + out.Values[i] = ec._Config_ADMIN_SECRET(ctx, field, obj) + case "DATABASE_TYPE": + out.Values[i] = ec._Config_DATABASE_TYPE(ctx, field, obj) + case "DATABASE_URL": + out.Values[i] = ec._Config_DATABASE_URL(ctx, field, obj) + case "DATABASE_NAME": + out.Values[i] = ec._Config_DATABASE_NAME(ctx, field, obj) + case "SMTP_HOST": + out.Values[i] = ec._Config_SMTP_HOST(ctx, field, obj) + case "SMTP_PORT": + out.Values[i] = ec._Config_SMTP_PORT(ctx, field, obj) + case "SENDER_EMAIL": + out.Values[i] = ec._Config_SENDER_EMAIL(ctx, field, obj) + case "SENDER_PASSWORD": + out.Values[i] = ec._Config_SENDER_PASSWORD(ctx, field, obj) + case "JWT_TYPE": + out.Values[i] = ec._Config_JWT_TYPE(ctx, field, obj) + case "JWT_SECRET": + out.Values[i] = ec._Config_JWT_SECRET(ctx, field, obj) + case "ALLOWED_ORIGINS": + out.Values[i] = ec._Config_ALLOWED_ORIGINS(ctx, field, obj) + case "AUTHORIZER_URL": + out.Values[i] = ec._Config_AUTHORIZER_URL(ctx, field, obj) + case "APP_URL": + out.Values[i] = ec._Config_APP_URL(ctx, field, obj) + case "REDIS_URL": + out.Values[i] = ec._Config_REDIS_URL(ctx, field, obj) + case "COOKIE_NAME": + out.Values[i] = ec._Config_COOKIE_NAME(ctx, field, obj) + case "RESET_PASSWORD_URL": + out.Values[i] = ec._Config_RESET_PASSWORD_URL(ctx, field, obj) + case "DISABLE_EMAIL_VERIFICATION": + out.Values[i] = ec._Config_DISABLE_EMAIL_VERIFICATION(ctx, field, obj) + case "DISABLE_BASIC_AUTHENTICATION": + out.Values[i] = ec._Config_DISABLE_BASIC_AUTHENTICATION(ctx, field, obj) + case "DISABLE_MAGIC_LINK_LOGIN": + out.Values[i] = ec._Config_DISABLE_MAGIC_LINK_LOGIN(ctx, field, obj) + case "DISABLE_LOGIN_PAGE": + out.Values[i] = ec._Config_DISABLE_LOGIN_PAGE(ctx, field, obj) + case "ROLES": + out.Values[i] = ec._Config_ROLES(ctx, field, obj) + case "PROTECTED_ROLES": + out.Values[i] = ec._Config_PROTECTED_ROLES(ctx, field, obj) + case "DEFAULT_ROLES": + out.Values[i] = ec._Config_DEFAULT_ROLES(ctx, field, obj) + case "JWT_ROLE_CLAIM": + out.Values[i] = ec._Config_JWT_ROLE_CLAIM(ctx, field, obj) + case "GOOGLE_CLIENT_ID": + out.Values[i] = ec._Config_GOOGLE_CLIENT_ID(ctx, field, obj) + case "GOOGLE_CLIENT_SECRET": + out.Values[i] = ec._Config_GOOGLE_CLIENT_SECRET(ctx, field, obj) + case "GITHUB_CLIENT_ID": + out.Values[i] = ec._Config_GITHUB_CLIENT_ID(ctx, field, obj) + case "GITHUB_CLIENT_SECRET": + out.Values[i] = ec._Config_GITHUB_CLIENT_SECRET(ctx, field, obj) + case "FACEBOOK_CLIENT_ID": + out.Values[i] = ec._Config_FACEBOOK_CLIENT_ID(ctx, field, obj) + case "FACEBOOK_CLIENT_SECRET": + out.Values[i] = ec._Config_FACEBOOK_CLIENT_SECRET(ctx, field, obj) + case "ORGANIZATION_NAME": + out.Values[i] = ec._Config_ORGANIZATION_NAME(ctx, field, obj) + case "ORGANIZATION_LOGO": + out.Values[i] = ec._Config_ORGANIZATION_LOGO(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var errorImplementors = []string{"Error"} func (ec *executionContext) _Error(ctx context.Context, sel ast.SelectionSet, obj *model.Error) graphql.Marshaler { @@ -4874,6 +6974,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } + case "_admin_login": + out.Values[i] = ec._Mutation__admin_login(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } + case "_update_config": + out.Values[i] = ec._Mutation__update_config(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -4923,6 +7033,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_session(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } return res }) case "profile": @@ -4967,6 +7080,34 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) + case "_admin_session": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query__admin_session(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + case "_config": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query__config(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "__type": out.Values[i] = ec._Query___type(ctx, field) case "__schema": @@ -5369,6 +7510,25 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o // region ***************************** type.gotpl ***************************** +func (ec *executionContext) unmarshalNAdminLoginInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginInput(ctx context.Context, v interface{}) (model.AdminLoginInput, error) { + res, err := ec.unmarshalInputAdminLoginInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNAdminLoginResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginResponse(ctx context.Context, sel ast.SelectionSet, v model.AdminLoginResponse) graphql.Marshaler { + return ec._AdminLoginResponse(ctx, sel, &v) +} + +func (ec *executionContext) marshalNAdminLoginResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAdminLoginResponse(ctx context.Context, sel ast.SelectionSet, v *model.AdminLoginResponse) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._AdminLoginResponse(ctx, sel, v) +} + func (ec *executionContext) marshalNAuthResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v model.AuthResponse) graphql.Marshaler { return ec._AuthResponse(ctx, sel, &v) } @@ -5398,6 +7558,20 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } +func (ec *executionContext) marshalNConfig2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx context.Context, sel ast.SelectionSet, v model.Config) graphql.Marshaler { + return ec._Config(ctx, sel, &v) +} + +func (ec *executionContext) marshalNConfig2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐConfig(ctx context.Context, sel ast.SelectionSet, v *model.Config) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Config(ctx, sel, v) +} + func (ec *executionContext) unmarshalNDeleteUserInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐDeleteUserInput(ctx context.Context, v interface{}) (model.DeleteUserInput, error) { res, err := ec.unmarshalInputDeleteUserInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -5527,6 +7701,11 @@ func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel return ret } +func (ec *executionContext) unmarshalNUpdateConfigInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateConfigInput(ctx context.Context, v interface{}) (model.UpdateConfigInput, error) { + res, err := ec.unmarshalInputUpdateConfigInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNUpdateProfileInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUpdateProfileInput(ctx context.Context, v interface{}) (model.UpdateProfileInput, error) { res, err := ec.unmarshalInputUpdateProfileInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -5911,13 +8090,6 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } -func (ec *executionContext) marshalOAuthResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐAuthResponse(ctx context.Context, sel ast.SelectionSet, v *model.AuthResponse) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._AuthResponse(ctx, sel, v) -} - func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index ffd76ea..877ee96 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -2,6 +2,15 @@ package model +type AdminLoginInput struct { + AdminSecret string `json:"admin_secret"` +} + +type AdminLoginResponse struct { + Message string `json:"message"` + AccessToken string `json:"access_token"` +} + type AuthResponse struct { Message string `json:"message"` AccessToken *string `json:"access_token"` @@ -9,6 +18,41 @@ type AuthResponse struct { User *User `json:"user"` } +type Config struct { + AdminSecret *string `json:"ADMIN_SECRET"` + DatabaseType *string `json:"DATABASE_TYPE"` + DatabaseURL *string `json:"DATABASE_URL"` + DatabaseName *string `json:"DATABASE_NAME"` + SMTPHost *string `json:"SMTP_HOST"` + SMTPPort *string `json:"SMTP_PORT"` + SenderEmail *string `json:"SENDER_EMAIL"` + SenderPassword *string `json:"SENDER_PASSWORD"` + JwtType *string `json:"JWT_TYPE"` + JwtSecret *string `json:"JWT_SECRET"` + AllowedOrigins []string `json:"ALLOWED_ORIGINS"` + AuthorizerURL *string `json:"AUTHORIZER_URL"` + AppURL *string `json:"APP_URL"` + RedisURL *string `json:"REDIS_URL"` + CookieName *string `json:"COOKIE_NAME"` + ResetPasswordURL *string `json:"RESET_PASSWORD_URL"` + DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"` + DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"` + DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"` + DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"` + Roles []string `json:"ROLES"` + ProtectedRoles []string `json:"PROTECTED_ROLES"` + DefaultRoles []string `json:"DEFAULT_ROLES"` + JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"` + GoogleClientID *string `json:"GOOGLE_CLIENT_ID"` + GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"` + GithubClientID *string `json:"GITHUB_CLIENT_ID"` + GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"` + FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"` + FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"` + OrganizationName *string `json:"ORGANIZATION_NAME"` + OrganizationLogo *string `json:"ORGANIZATION_LOGO"` +} + type DeleteUserInput struct { Email string `json:"email"` } @@ -73,6 +117,41 @@ type SignUpInput struct { Roles []string `json:"roles"` } +type UpdateConfigInput struct { + AdminSecret *string `json:"ADMIN_SECRET"` + DatabaseType *string `json:"DATABASE_TYPE"` + DatabaseURL *string `json:"DATABASE_URL"` + DatabaseName *string `json:"DATABASE_NAME"` + SMTPHost *string `json:"SMTP_HOST"` + SMTPPort *string `json:"SMTP_PORT"` + SenderEmail *string `json:"SENDER_EMAIL"` + SenderPassword *string `json:"SENDER_PASSWORD"` + JwtType *string `json:"JWT_TYPE"` + JwtSecret *string `json:"JWT_SECRET"` + AllowedOrigins []string `json:"ALLOWED_ORIGINS"` + AuthorizerURL *string `json:"AUTHORIZER_URL"` + AppURL *string `json:"APP_URL"` + RedisURL *string `json:"REDIS_URL"` + CookieName *string `json:"COOKIE_NAME"` + ResetPasswordURL *string `json:"RESET_PASSWORD_URL"` + DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION"` + DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION"` + DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN"` + DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"` + Roles []string `json:"ROLES"` + ProtectedRoles []string `json:"PROTECTED_ROLES"` + DefaultRoles []string `json:"DEFAULT_ROLES"` + JwtRoleClaim *string `json:"JWT_ROLE_CLAIM"` + GoogleClientID *string `json:"GOOGLE_CLIENT_ID"` + GoogleClientSecret *string `json:"GOOGLE_CLIENT_SECRET"` + GithubClientID *string `json:"GITHUB_CLIENT_ID"` + GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"` + FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"` + FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"` + OrganizationName *string `json:"ORGANIZATION_NAME"` + OrganizationLogo *string `json:"ORGANIZATION_LOGO"` +} + type UpdateProfileInput struct { OldPassword *string `json:"old_password"` NewPassword *string `json:"new_password"` diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 4353073..cfb5ad8 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -62,6 +62,85 @@ type Response { message: String! } +type AdminLoginResponse { + message: String! + access_token: String! +} + +type Config { + ADMIN_SECRET: String + DATABASE_TYPE: String + DATABASE_URL: String + DATABASE_NAME: String + SMTP_HOST: String + SMTP_PORT: String + SENDER_EMAIL: String + SENDER_PASSWORD: String + JWT_TYPE: String + JWT_SECRET: String + ALLOWED_ORIGINS: [String!] + AUTHORIZER_URL: String + APP_URL: String + REDIS_URL: String + COOKIE_NAME: String + RESET_PASSWORD_URL: String + DISABLE_EMAIL_VERIFICATION: Boolean + DISABLE_BASIC_AUTHENTICATION: Boolean + DISABLE_MAGIC_LINK_LOGIN: Boolean + DISABLE_LOGIN_PAGE: Boolean + ROLES: [String!] + PROTECTED_ROLES: [String!] + DEFAULT_ROLES: [String!] + JWT_ROLE_CLAIM: String + GOOGLE_CLIENT_ID: String + GOOGLE_CLIENT_SECRET: String + GITHUB_CLIENT_ID: String + GITHUB_CLIENT_SECRET: String + FACEBOOK_CLIENT_ID: String + FACEBOOK_CLIENT_SECRET: String + ORGANIZATION_NAME: String + ORGANIZATION_LOGO: String +} + +input UpdateConfigInput { + ADMIN_SECRET: String + DATABASE_TYPE: String + DATABASE_URL: String + DATABASE_NAME: String + SMTP_HOST: String + SMTP_PORT: String + SENDER_EMAIL: String + SENDER_PASSWORD: String + JWT_TYPE: String + JWT_SECRET: String + ALLOWED_ORIGINS: [String!] + AUTHORIZER_URL: String + APP_URL: String + REDIS_URL: String + COOKIE_NAME: String + RESET_PASSWORD_URL: String + DISABLE_EMAIL_VERIFICATION: Boolean + DISABLE_BASIC_AUTHENTICATION: Boolean + DISABLE_MAGIC_LINK_LOGIN: Boolean + DISABLE_LOGIN_PAGE: Boolean + ROLES: [String!] + PROTECTED_ROLES: [String!] + DEFAULT_ROLES: [String!] + JWT_ROLE_CLAIM: String + GOOGLE_CLIENT_ID: String + GOOGLE_CLIENT_SECRET: String + GITHUB_CLIENT_ID: String + GITHUB_CLIENT_SECRET: String + FACEBOOK_CLIENT_ID: String + FACEBOOK_CLIENT_SECRET: String + ORGANIZATION_NAME: String + ORGANIZATION_LOGO: String +} + +input AdminLoginInput { + admin_secret: String! +} + input SignUpInput { email: String! given_name: String @@ -153,13 +232,17 @@ type Mutation { # admin only apis _delete_user(params: DeleteUserInput!): Response! _update_user(params: UpdateUserInput!): User! + _admin_login(params: AdminLoginInput!): AdminLoginResponse! + _update_config(params: UpdateConfigInput!): Response! } type Query { meta: Meta! - session(roles: [String!]): AuthResponse + session(roles: [String!]): AuthResponse! profile: User! # admin only apis _users: [User!]! _verification_requests: [VerificationRequest!]! + _admin_session: AdminLoginResponse! + _config: Config! } diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index 9510800..4bf8a5a 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -55,6 +55,14 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUs return resolvers.UpdateUser(ctx, params) } +func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) { + return resolvers.AdminLoginResolver(ctx, params) +} + +func (r *mutationResolver) UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) { + return resolvers.UpdateConfigResolver(ctx, params) +} + func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) { return resolvers.Meta(ctx) } @@ -75,6 +83,14 @@ func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.Veri return resolvers.VerificationRequests(ctx) } +func (r *queryResolver) AdminSession(ctx context.Context) (*model.AdminLoginResponse, error) { + return resolvers.AdminSession(ctx) +} + +func (r *queryResolver) Config(ctx context.Context) (*model.Config, error) { + return resolvers.ConfigResolver(ctx) +} + // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } diff --git a/server/handlers/app.go b/server/handlers/app.go index 4fb7070..e2569e4 100644 --- a/server/handlers/app.go +++ b/server/handlers/app.go @@ -1,7 +1,6 @@ package handlers import ( - "encoding/base64" "encoding/json" "log" "net/http" @@ -30,17 +29,17 @@ func AppHandler() gin.HandlerFunc { // return // } - stateObj.AuthorizerURL = constants.AUTHORIZER_URL - stateObj.RedirectURL = constants.AUTHORIZER_URL + "/app" + stateObj.AuthorizerURL = constants.EnvData.AUTHORIZER_URL + stateObj.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/app" } else { - decodedState, err := base64.StdEncoding.DecodeString(state) + decodedState, err := utils.DecryptB64(state) if err != nil { c.JSON(400, gin.H{"error": "[unable to decode state] invalid state"}) return } - err = json.Unmarshal(decodedState, &stateObj) + err = json.Unmarshal([]byte(decodedState), &stateObj) if err != nil { c.JSON(400, gin.H{"error": "[unable to parse state] invalid state"}) return @@ -60,7 +59,7 @@ func AppHandler() gin.HandlerFunc { } // validate host and domain of authorizer url - if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.AUTHORIZER_URL { + if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.EnvData.AUTHORIZER_URL { c.JSON(400, gin.H{"error": "invalid host url"}) return } @@ -77,8 +76,8 @@ func AppHandler() gin.HandlerFunc { "data": map[string]string{ "authorizerURL": stateObj.AuthorizerURL, "redirectURL": stateObj.RedirectURL, - "organizationName": constants.ORGANIZATION_NAME, - "organizationLogo": constants.ORGANIZATION_LOGO, + "organizationName": constants.EnvData.ORGANIZATION_NAME, + "organizationLogo": constants.EnvData.ORGANIZATION_LOGO, }, }) } diff --git a/server/handlers/dashboard.go b/server/handlers/dashboard.go index 88eb40b..f16e442 100644 --- a/server/handlers/dashboard.go +++ b/server/handlers/dashboard.go @@ -1,79 +1,23 @@ package handlers import ( - "encoding/base64" - "encoding/json" - "log" "net/http" - "strings" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/utils" "github.com/gin-gonic/gin" ) func DashboardHandler() gin.HandlerFunc { return func(c *gin.Context) { - state := c.Query("state") + isOnboardingCompleted := false - var stateObj State - - if state == "" { - // cookie, err := utils.GetAuthToken(c) - // if err != nil { - // c.JSON(400, gin.H{"error": "invalid state"}) - // return - // } - - stateObj.AuthorizerURL = constants.AUTHORIZER_URL - stateObj.RedirectURL = constants.AUTHORIZER_URL + "/app" - - } else { - decodedState, err := base64.StdEncoding.DecodeString(state) - if err != nil { - c.JSON(400, gin.H{"error": "[unable to decode state] invalid state"}) - return - } - - err = json.Unmarshal(decodedState, &stateObj) - if err != nil { - c.JSON(400, gin.H{"error": "[unable to parse state] invalid state"}) - return - } - stateObj.AuthorizerURL = strings.TrimSuffix(stateObj.AuthorizerURL, "/") - stateObj.RedirectURL = strings.TrimSuffix(stateObj.RedirectURL, "/") - - // validate redirect url with allowed origins - if !utils.IsValidOrigin(stateObj.RedirectURL) { - c.JSON(400, gin.H{"error": "invalid redirect url"}) - return - } - - if stateObj.AuthorizerURL == "" { - c.JSON(400, gin.H{"error": "invalid authorizer url"}) - return - } - - // validate host and domain of authorizer url - if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.AUTHORIZER_URL { - c.JSON(400, gin.H{"error": "invalid host url"}) - return - } + if constants.EnvData.ADMIN_SECRET != "" { + isOnboardingCompleted = true } - // debug the request state - if pusher := c.Writer.Pusher(); pusher != nil { - // use pusher.Push() to do server push - if err := pusher.Push("/app/build/bundle.js", nil); err != nil { - log.Printf("Failed to push: %v", err) - } - } c.HTML(http.StatusOK, "dashboard.tmpl", gin.H{ - "data": map[string]string{ - "authorizerURL": stateObj.AuthorizerURL, - "redirectURL": stateObj.RedirectURL, - "organizationName": constants.ORGANIZATION_NAME, - "organizationLogo": constants.ORGANIZATION_LOGO, + "data": map[string]interface{}{ + "isOnboardingCompleted": isOnboardingCompleted, }, }) } diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 4fd0364..a6c922a 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -195,7 +195,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { // make sure inputRoles don't include protected roles hasProtectedRole := false for _, ir := range inputRoles { - if utils.StringSliceContains(constants.PROTECTED_ROLES, ir) { + if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ir) { hasProtectedRole = true } } @@ -238,7 +238,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { // check if it contains protected unassigned role hasProtectedRole := false for _, ur := range unasignedRoles { - if utils.StringSliceContains(constants.PROTECTED_ROLES, ur) { + if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) { hasProtectedRole = true } } diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go index 1f3cd4e..0363f70 100644 --- a/server/handlers/oauth_login.go +++ b/server/handlers/oauth_login.go @@ -34,14 +34,14 @@ func OAuthLoginHandler() gin.HandlerFunc { // use protected roles verification for admin login only. // though if not associated with user, it will be rejected from oauth_callback - if !utils.IsValidRoles(append([]string{}, append(constants.ROLES, constants.PROTECTED_ROLES...)...), rolesSplit) { + if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), rolesSplit) { c.JSON(400, gin.H{ "error": "invalid role", }) return } } else { - roles = strings.Join(constants.DEFAULT_ROLES, ",") + roles = strings.Join(constants.EnvData.DEFAULT_ROLES, ",") } uuid := uuid.New() @@ -57,7 +57,7 @@ func OAuthLoginHandler() gin.HandlerFunc { } session.SetSocailLoginState(oauthStateString, enum.Google.String()) // during the init of OAuthProvider authorizer url might be empty - oauth.OAuthProviders.GoogleConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/google" + oauth.OAuthProviders.GoogleConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google" url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case enum.Github.String(): @@ -66,7 +66,7 @@ func OAuthLoginHandler() gin.HandlerFunc { break } session.SetSocailLoginState(oauthStateString, enum.Github.String()) - oauth.OAuthProviders.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github" + oauth.OAuthProviders.GithubConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github" url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case enum.Facebook.String(): @@ -75,7 +75,7 @@ func OAuthLoginHandler() gin.HandlerFunc { break } session.SetSocailLoginState(oauthStateString, enum.Facebook.String()) - oauth.OAuthProviders.FacebookConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/facebook" + oauth.OAuthProviders.FacebookConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook" url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) default: diff --git a/server/main.go b/server/main.go index 8d2af0d..7e7c88e 100644 --- a/server/main.go +++ b/server/main.go @@ -22,10 +22,12 @@ func main() { env.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") flag.Parse() - constants.VERSION = VERSION + constants.EnvData.VERSION = VERSION env.InitEnv() db.InitDB() + env.PersistEnv() + session.InitSession() oauth.InitOAuth() utils.InitServer() @@ -35,7 +37,7 @@ func main() { router.LoadHTMLGlob("templates/*") // login page app related routes. // if we put them in router file then tests would fail as templates or build path will be different - if !constants.DISABLE_LOGIN_PAGE { + if !constants.EnvData.DISABLE_LOGIN_PAGE { app := router.Group("/app") { app.Static("/build", "app/build") @@ -50,5 +52,5 @@ func main() { app.GET("/", handlers.DashboardHandler()) } - router.Run(":" + constants.PORT) + router.Run(":" + constants.EnvData.PORT) } diff --git a/server/middlewares/context.go b/server/middlewares/context.go index 32e824b..fd205ac 100644 --- a/server/middlewares/context.go +++ b/server/middlewares/context.go @@ -11,10 +11,10 @@ import ( func GinContextToContextMiddleware() gin.HandlerFunc { return func(c *gin.Context) { - if constants.AUTHORIZER_URL == "" { + if constants.EnvData.AUTHORIZER_URL == "" { url := location.Get(c) - constants.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host - log.Println("authorizer url:", constants.AUTHORIZER_URL) + constants.EnvData.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host + log.Println("authorizer url:", constants.EnvData.AUTHORIZER_URL) } ctx := context.WithValue(c.Request.Context(), "GinContextKey", c) c.Request = c.Request.WithContext(ctx) diff --git a/server/middlewares/cors.go b/server/middlewares/cors.go index e0bb4a9..f093e8a 100644 --- a/server/middlewares/cors.go +++ b/server/middlewares/cors.go @@ -1,7 +1,6 @@ package middlewares import ( - "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/utils" "github.com/gin-gonic/gin" ) @@ -9,7 +8,6 @@ import ( func CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { origin := c.Request.Header.Get("Origin") - constants.APP_URL = origin if utils.IsValidOrigin(origin) { c.Writer.Header().Set("Access-Control-Allow-Origin", origin) diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go index 64b6927..5c6d943 100644 --- a/server/oauth/oauth.go +++ b/server/oauth/oauth.go @@ -28,33 +28,33 @@ var ( func InitOAuth() { ctx := context.Background() - if constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "" { + if constants.EnvData.GOOGLE_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "" { p, err := oidc.NewProvider(ctx, "https://accounts.google.com") if err != nil { log.Fatalln("error creating oidc provider for google:", err) } OIDCProviders.GoogleOIDC = p OAuthProviders.GoogleConfig = &oauth2.Config{ - ClientID: constants.GOOGLE_CLIENT_ID, - ClientSecret: constants.GOOGLE_CLIENT_SECRET, - RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/google", + ClientID: constants.EnvData.GOOGLE_CLIENT_ID, + ClientSecret: constants.EnvData.GOOGLE_CLIENT_SECRET, + RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google", Endpoint: OIDCProviders.GoogleOIDC.Endpoint(), Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, } } - if constants.GITHUB_CLIENT_ID != "" && constants.GITHUB_CLIENT_SECRET != "" { + if constants.EnvData.GITHUB_CLIENT_ID != "" && constants.EnvData.GITHUB_CLIENT_SECRET != "" { OAuthProviders.GithubConfig = &oauth2.Config{ - ClientID: constants.GITHUB_CLIENT_ID, - ClientSecret: constants.GITHUB_CLIENT_SECRET, - RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/github", + ClientID: constants.EnvData.GITHUB_CLIENT_ID, + ClientSecret: constants.EnvData.GITHUB_CLIENT_SECRET, + RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github", Endpoint: githubOAuth2.Endpoint, } } - if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" { + if constants.EnvData.FACEBOOK_CLIENT_ID != "" && constants.EnvData.FACEBOOK_CLIENT_SECRET != "" { OAuthProviders.FacebookConfig = &oauth2.Config{ - ClientID: constants.FACEBOOK_CLIENT_ID, - ClientSecret: constants.FACEBOOK_CLIENT_SECRET, - RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/facebook", + ClientID: constants.EnvData.FACEBOOK_CLIENT_ID, + ClientSecret: constants.EnvData.FACEBOOK_CLIENT_SECRET, + RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook", Endpoint: facebookOAuth2.Endpoint, Scopes: []string{"public_profile", "email"}, } diff --git a/server/resolvers/admin_login.go b/server/resolvers/admin_login.go new file mode 100644 index 0000000..8c46ffc --- /dev/null +++ b/server/resolvers/admin_login.go @@ -0,0 +1,35 @@ +package resolvers + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/utils" +) + +func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.AdminLoginResponse, error) { + gc, err := utils.GinContextFromContext(ctx) + var res *model.AdminLoginResponse + + if err != nil { + return res, err + } + + if params.AdminSecret != constants.EnvData.ADMIN_SECRET { + return res, fmt.Errorf(`invalid admin secret`) + } + + hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + if err != nil { + return res, err + } + utils.SetAdminCookie(gc, hashedKey) + + res = &model.AdminLoginResponse{ + AccessToken: hashedKey, + Message: "admin logged in successfully", + } + return res, nil +} diff --git a/server/resolvers/admin_session.go b/server/resolvers/admin_session.go new file mode 100644 index 0000000..fafe33b --- /dev/null +++ b/server/resolvers/admin_session.go @@ -0,0 +1,35 @@ +package resolvers + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/utils" +) + +func AdminSession(ctx context.Context) (*model.AdminLoginResponse, error) { + gc, err := utils.GinContextFromContext(ctx) + var res *model.AdminLoginResponse + + if err != nil { + return res, err + } + + if !utils.IsSuperAdmin(gc) { + return res, fmt.Errorf("unauthorized") + } + + hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + if err != nil { + return res, err + } + utils.SetAdminCookie(gc, hashedKey) + + res = &model.AdminLoginResponse{ + AccessToken: hashedKey, + Message: "admin logged in successfully", + } + return res, nil +} diff --git a/server/resolvers/config.go b/server/resolvers/config.go new file mode 100644 index 0000000..6165eea --- /dev/null +++ b/server/resolvers/config.go @@ -0,0 +1,59 @@ +package resolvers + +import ( + "context" + "fmt" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/utils" +) + +func ConfigResolver(ctx context.Context) (*model.Config, error) { + gc, err := utils.GinContextFromContext(ctx) + var res *model.Config + + if err != nil { + return res, err + } + + if !utils.IsSuperAdmin(gc) { + return res, fmt.Errorf("unauthorized") + } + + res = &model.Config{ + AdminSecret: &constants.EnvData.ADMIN_SECRET, + DatabaseType: &constants.EnvData.DATABASE_TYPE, + DatabaseURL: &constants.EnvData.DATABASE_URL, + DatabaseName: &constants.EnvData.DATABASE_NAME, + SMTPHost: &constants.EnvData.SMTP_HOST, + SMTPPort: &constants.EnvData.SMTP_PORT, + SenderEmail: &constants.EnvData.SENDER_EMAIL, + SenderPassword: &constants.EnvData.SENDER_PASSWORD, + JwtType: &constants.EnvData.JWT_TYPE, + JwtSecret: &constants.EnvData.JWT_SECRET, + AllowedOrigins: constants.EnvData.ALLOWED_ORIGINS, + AuthorizerURL: &constants.EnvData.AUTHORIZER_URL, + AppURL: &constants.EnvData.APP_URL, + RedisURL: &constants.EnvData.REDIS_URL, + CookieName: &constants.EnvData.COOKIE_NAME, + ResetPasswordURL: &constants.EnvData.RESET_PASSWORD_URL, + DisableEmailVerification: &constants.EnvData.DISABLE_EMAIL_VERIFICATION, + DisableBasicAuthentication: &constants.EnvData.DISABLE_BASIC_AUTHENTICATION, + DisableMagicLinkLogin: &constants.EnvData.DISABLE_MAGIC_LINK_LOGIN, + DisableLoginPage: &constants.EnvData.DISABLE_LOGIN_PAGE, + Roles: constants.EnvData.ROLES, + ProtectedRoles: constants.EnvData.PROTECTED_ROLES, + DefaultRoles: constants.EnvData.DEFAULT_ROLES, + JwtRoleClaim: &constants.EnvData.JWT_ROLE_CLAIM, + GoogleClientID: &constants.EnvData.GOOGLE_CLIENT_ID, + GoogleClientSecret: &constants.EnvData.GOOGLE_CLIENT_SECRET, + GithubClientID: &constants.EnvData.GITHUB_CLIENT_ID, + GithubClientSecret: &constants.EnvData.GITHUB_CLIENT_SECRET, + FacebookClientID: &constants.EnvData.FACEBOOK_CLIENT_ID, + FacebookClientSecret: &constants.EnvData.FACEBOOK_CLIENT_SECRET, + OrganizationName: &constants.EnvData.ORGANIZATION_NAME, + OrganizationLogo: &constants.EnvData.ORGANIZATION_LOGO, + } + return res, nil +} diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index fc5ba16..8c5c583 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -20,7 +20,7 @@ func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*mod if err != nil { return res, err } - if constants.DISABLE_BASIC_AUTHENTICATION { + if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { return res, fmt.Errorf(`basic authentication is disabled for this instance`) } host := gc.Request.Host diff --git a/server/resolvers/login.go b/server/resolvers/login.go index 00b444e..482cf4b 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -22,7 +22,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e return res, err } - if constants.DISABLE_BASIC_AUTHENTICATION { + if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { return res, fmt.Errorf(`basic authentication is disabled for this instance`) } @@ -46,7 +46,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e log.Println("compare password error:", err) return res, fmt.Errorf(`invalid password`) } - roles := constants.DEFAULT_ROLES + roles := constants.EnvData.DEFAULT_ROLES currentRoles := strings.Split(user.Roles, ",") if len(params.Roles) > 0 { if !utils.IsValidRoles(currentRoles, params.Roles) { diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index 2bb3d9d..8ba726a 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -17,7 +17,7 @@ import ( func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { var res *model.Response - if constants.DISABLE_MAGIC_LINK_LOGIN { + if constants.EnvData.DISABLE_MAGIC_LINK_LOGIN { return res, fmt.Errorf(`magic link login is disabled for this instance`) } @@ -41,13 +41,13 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod // define roles for new user if len(params.Roles) > 0 { // check if roles exists - if !utils.IsValidRoles(constants.ROLES, params.Roles) { + if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) { return res, fmt.Errorf(`invalid roles`) } else { inputRoles = params.Roles } } else { - inputRoles = constants.DEFAULT_ROLES + inputRoles = constants.EnvData.DEFAULT_ROLES } user.Roles = strings.Join(inputRoles, ",") @@ -72,7 +72,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod // check if it contains protected unassigned role hasProtectedRole := false for _, ur := range unasignedRoles { - if utils.StringSliceContains(constants.PROTECTED_ROLES, ur) { + if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) { hasProtectedRole = true } } @@ -98,7 +98,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod } } - if !constants.DISABLE_EMAIL_VERIFICATION { + if !constants.EnvData.DISABLE_EMAIL_VERIFICATION { // insert verification request verificationType := enum.MagicLinkLogin.String() token, err := utils.CreateVerificationToken(params.Email, verificationType) diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go index 4c914c0..d459a83 100644 --- a/server/resolvers/reset_password.go +++ b/server/resolvers/reset_password.go @@ -14,7 +14,7 @@ import ( func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { var res *model.Response - if constants.DISABLE_BASIC_AUTHENTICATION { + if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { return res, fmt.Errorf(`basic authentication is disabled for this instance`) } diff --git a/server/resolvers/session.go b/server/resolvers/session.go index cecc0fe..a587deb 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -45,7 +45,7 @@ func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) { expiresTimeObj := time.Unix(expiresAt, 0) currentTimeObj := time.Now() - claimRoleInterface := claim[constants.JWT_ROLE_CLAIM].([]interface{}) + claimRoleInterface := claim[constants.EnvData.JWT_ROLE_CLAIM].([]interface{}) claimRoles := make([]string, len(claimRoleInterface)) for i, v := range claimRoleInterface { claimRoles[i] = v.(string) diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index aa9a241..ba19b45 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -22,7 +22,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, return res, err } - if constants.DISABLE_BASIC_AUTHENTICATION { + if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { return res, fmt.Errorf(`basic authentication is disabled for this instance`) } if params.ConfirmPassword != params.Password { @@ -52,13 +52,13 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, if len(params.Roles) > 0 { // check if roles exists - if !utils.IsValidRoles(constants.ROLES, params.Roles) { + if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) { return res, fmt.Errorf(`invalid roles`) } else { inputRoles = params.Roles } } else { - inputRoles = constants.DEFAULT_ROLES + inputRoles = constants.EnvData.DEFAULT_ROLES } user := db.User{ @@ -103,7 +103,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, } user.SignupMethods = enum.BasicAuth.String() - if constants.DISABLE_EMAIL_VERIFICATION { + if constants.EnvData.DISABLE_EMAIL_VERIFICATION { now := time.Now().Unix() user.EmailVerifiedAt = &now } @@ -115,7 +115,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, roles := strings.Split(user.Roles, ",") userToReturn := utils.GetResponseUserData(user) - if !constants.DISABLE_EMAIL_VERIFICATION { + if !constants.EnvData.DISABLE_EMAIL_VERIFICATION { // insert verification request verificationType := enum.BasicAuthSignup.String() token, err := utils.CreateVerificationToken(params.Email, verificationType) diff --git a/server/resolvers/update_config.go b/server/resolvers/update_config.go new file mode 100644 index 0000000..089b0cc --- /dev/null +++ b/server/resolvers/update_config.go @@ -0,0 +1,119 @@ +package resolvers + +import ( + "context" + "encoding/json" + "fmt" + "log" + "reflect" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/utils" +) + +func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) { + gc, err := utils.GinContextFromContext(ctx) + var res *model.Response + + if err != nil { + return res, err + } + + if !utils.IsSuperAdmin(gc) { + return res, fmt.Errorf("unauthorized") + } + + var data map[string]interface{} + byteData, err := json.Marshal(params) + if err != nil { + return res, fmt.Errorf("error marshalling params: %t", err) + } + + err = json.Unmarshal(byteData, &data) + if err != nil { + return res, fmt.Errorf("error un-marshalling params: %t", err) + } + + updatedData := make(map[string]interface{}) + for key, value := range data { + if value != nil { + fieldType := reflect.TypeOf(value).String() + + if fieldType == "string" || fieldType == "bool" { + updatedData[key] = value + } + + if fieldType == "[]interface {}" { + stringArr := []string{} + for _, v := range value.([]interface{}) { + stringArr = append(stringArr, v.(string)) + } + updatedData[key] = stringArr + } + } + } + + // handle derivative cases like disabling email verification & magic login + // in case SMTP is off but env is set to true + if updatedData["SMTP_HOST"] == "" || updatedData["SENDER_EMAIL"] == "" || updatedData["SENDER_PASSWORD"] == "" { + if !updatedData["DISABLE_EMAIL_VERIFICATION"].(bool) { + updatedData["DISABLE_EMAIL_VERIFICATION"] = true + } + + if !updatedData["DISABLE_MAGIC_LINK_LOGIN"].(bool) { + updatedData["DISABLE_MAGIC_LINK_LOGIN"] = true + } + } + + config, err := db.Mgr.GetConfig() + if err != nil { + return res, err + } + + jsonBytes, err := json.Marshal(updatedData) + if err != nil { + return res, err + } + + err = json.Unmarshal(jsonBytes, &constants.EnvData) + if err != nil { + return res, err + } + + configData, err := json.Marshal(constants.EnvData) + if err != nil { + return res, err + } + encryptedConfig, err := utils.EncryptAES(configData) + if err != nil { + return res, err + } + + // in case of db change re-initialize db + if params.DatabaseType != nil || params.DatabaseURL != nil || params.DatabaseName != nil { + db.InitDB() + } + + // in case of admin secret change update the cookie with new hash + if params.AdminSecret != nil { + hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) + if err != nil { + return res, err + } + utils.SetAdminCookie(gc, hashedKey) + } + + config.Config = encryptedConfig + _, err = db.Mgr.UpdateConfig(config) + if err != nil { + log.Println("error updating config:", err) + return res, err + } + + res = &model.Response{ + Message: "configurations updated successfully", + } + return res, nil +} diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index 93222de..c67021b 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -112,7 +112,7 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, inputRoles = append(inputRoles, *item) } - if !utils.IsValidRoles(append([]string{}, append(constants.ROLES, constants.PROTECTED_ROLES...)...), inputRoles) { + if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), inputRoles) { return res, fmt.Errorf("invalid list of roles") } diff --git a/server/session/session.go b/server/session/session.go index 08138b0..39727b3 100644 --- a/server/session/session.go +++ b/server/session/session.go @@ -95,9 +95,9 @@ func RemoveSocialLoginState(key string) { } func InitSession() { - if constants.REDIS_URL != "" { + if constants.EnvData.REDIS_URL != "" { log.Println("using redis store to save sessions") - opt, err := redis.ParseURL(constants.REDIS_URL) + opt, err := redis.ParseURL(constants.EnvData.REDIS_URL) if err != nil { log.Fatalln("Error parsing redis url:", err) } diff --git a/server/utils/auth_token.go b/server/utils/auth_token.go index 23995de..18ed7ea 100644 --- a/server/utils/auth_token.go +++ b/server/utils/auth_token.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "log" + "net/url" "os" "strings" "time" @@ -14,10 +15,11 @@ import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" "github.com/robertkrimen/otto" + "golang.org/x/crypto/bcrypt" ) func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (string, int64, error) { - t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE)) + t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE)) expiryBound := time.Hour if tokenType == enum.RefreshToken { // expires in 1 year @@ -32,11 +34,11 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st json.Unmarshal(userBytes, &userMap) customClaims := jwt.MapClaims{ - "exp": expiresAt, - "iat": time.Now().Unix(), - "token_type": tokenType.String(), - "allowed_roles": strings.Split(user.Roles, ","), - constants.JWT_ROLE_CLAIM: roles, + "exp": expiresAt, + "iat": time.Now().Unix(), + "token_type": tokenType.String(), + "allowed_roles": strings.Split(user.Roles, ","), + constants.EnvData.JWT_ROLE_CLAIM: roles, } for k, v := range userMap { @@ -77,7 +79,7 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st t.Claims = customClaims - token, err := t.SignedString([]byte(constants.JWT_SECRET)) + token, err := t.SignedString([]byte(constants.EnvData.JWT_SECRET)) if err != nil { return "", 0, err } @@ -89,7 +91,6 @@ func GetAuthToken(gc *gin.Context) (string, error) { token, err := GetCookie(gc) if err != nil || token == "" { // try to check in auth header for cookie - log.Println("cookie not found checking headers") auth := gc.Request.Header.Get("Authorization") if auth == "" { return "", fmt.Errorf(`unauthorized`) @@ -105,7 +106,7 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) { claims := jwt.MapClaims{} _, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { - return []byte(constants.JWT_SECRET), nil + return []byte(constants.EnvData.JWT_SECRET), nil }) if err != nil { return res, err @@ -124,3 +125,36 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) { return res, nil } + +func CreateAdminAuthToken(tokenType enum.TokenType, c *gin.Context) (string, error) { + return HashPassword(constants.EnvData.ADMIN_SECRET) +} + +func GetAdminAuthToken(gc *gin.Context) (string, error) { + token, err := GetAdminCookie(gc) + if err != nil || token == "" { + // try to check in auth header for cookie + auth := gc.Request.Header.Get("Authorization") + if auth == "" { + return "", fmt.Errorf(`unauthorized`) + } + + token = strings.TrimPrefix(auth, "Bearer ") + + } + + // cookie escapes special characters like $ + // hence we need to unescape before comparing + decodedValue, err := url.QueryUnescape(token) + if err != nil { + return "", err + } + + err = bcrypt.CompareHashAndPassword([]byte(decodedValue), []byte(constants.EnvData.ADMIN_SECRET)) + log.Println("error comparing hash:", err) + if err != nil { + return "", fmt.Errorf(`unauthorized`) + } + + return token, nil +} diff --git a/server/utils/cookie.go b/server/utils/cookie.go index 38cf327..996bee7 100644 --- a/server/utils/cookie.go +++ b/server/utils/cookie.go @@ -10,21 +10,21 @@ import ( func SetCookie(gc *gin.Context, token string) { secure := true httpOnly := true - host, _ := GetHostParts(constants.AUTHORIZER_URL) - domain := GetDomainName(constants.AUTHORIZER_URL) + host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL) + domain := GetDomainName(constants.EnvData.AUTHORIZER_URL) if domain != "localhost" { domain = "." + domain } gc.SetSameSite(http.SameSiteNoneMode) - gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly) - gc.SetCookie(constants.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly) + gc.SetCookie(constants.EnvData.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly) + gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly) } func GetCookie(gc *gin.Context) (string, error) { - cookie, err := gc.Request.Cookie(constants.COOKIE_NAME) + cookie, err := gc.Request.Cookie(constants.EnvData.COOKIE_NAME) if err != nil { - cookie, err = gc.Request.Cookie(constants.COOKIE_NAME + "-client") + cookie, err = gc.Request.Cookie(constants.EnvData.COOKIE_NAME + "-client") if err != nil { return "", err } @@ -37,13 +37,37 @@ func DeleteCookie(gc *gin.Context) { secure := true httpOnly := true - host, _ := GetHostParts(constants.AUTHORIZER_URL) - domain := GetDomainName(constants.AUTHORIZER_URL) + host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL) + domain := GetDomainName(constants.EnvData.AUTHORIZER_URL) if domain != "localhost" { domain = "." + domain } gc.SetSameSite(http.SameSiteNoneMode) - gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly) - gc.SetCookie(constants.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly) + gc.SetCookie(constants.EnvData.COOKIE_NAME, "", -1, "/", host, secure, httpOnly) + gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly) +} + +func SetAdminCookie(gc *gin.Context, token string) { + secure := true + httpOnly := true + host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL) + + gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, token, 3600, "/", host, secure, httpOnly) +} + +func GetAdminCookie(gc *gin.Context) (string, error) { + cookie, err := gc.Request.Cookie(constants.EnvData.ADMIN_COOKIE_NAME) + if err != nil { + return "", err + } + return cookie.Value, nil +} + +func DeleteAdminCookie(gc *gin.Context, token string) { + secure := true + httpOnly := true + host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL) + + gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, "", -1, "/", host, secure, httpOnly) } diff --git a/server/utils/crypto.go b/server/utils/crypto.go new file mode 100644 index 0000000..de7ce39 --- /dev/null +++ b/server/utils/crypto.go @@ -0,0 +1,83 @@ +package utils + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "io" + + "github.com/authorizerdev/authorizer/server/constants" +) + +func EncryptB64(text string) string { + return base64.StdEncoding.EncodeToString([]byte(text)) +} + +func DecryptB64(s string) (string, error) { + data, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return "", err + } + return string(data), nil +} + +func EncryptAES(text []byte) ([]byte, error) { + key := []byte(constants.EnvData.ENCRYPTION_KEY) + c, err := aes.NewCipher(key) + var res []byte + if err != nil { + return res, err + } + + // gcm or Galois/Counter Mode, is a mode of operation + // for symmetric key cryptographic block ciphers + // - https://en.wikipedia.org/wiki/Galois/Counter_Mode + gcm, err := cipher.NewGCM(c) + if err != nil { + return res, err + } + + // creates a new byte array the size of the nonce + // which must be passed to Seal + nonce := make([]byte, gcm.NonceSize()) + // populates our nonce with a cryptographically secure + // random sequence + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return res, err + } + + // here we encrypt our text using the Seal function + // Seal encrypts and authenticates plaintext, authenticates the + // additional data and appends the result to dst, returning the updated + // slice. The nonce must be NonceSize() bytes long and unique for all + // time, for a given key. + return gcm.Seal(nonce, nonce, text, nil), nil +} + +func DecryptAES(ciphertext []byte) ([]byte, error) { + key := []byte(constants.EnvData.ENCRYPTION_KEY) + c, err := aes.NewCipher(key) + var res []byte + if err != nil { + return res, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return res, err + } + + nonceSize := gcm.NonceSize() + if len(ciphertext) < nonceSize { + return res, err + } + + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return res, err + } + + return plaintext, nil +} diff --git a/server/utils/email.go b/server/utils/email.go index 29c1ebc..3e4b9b2 100644 --- a/server/utils/email.go +++ b/server/utils/email.go @@ -100,7 +100,7 @@ func SendVerificationMail(toEmail, token string) error {
- `, constants.ORGANIZATION_LOGO, constants.ORGANIZATION_NAME, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token) + `, constants.EnvData.ORGANIZATION_LOGO, constants.EnvData.ORGANIZATION_NAME, constants.EnvData.AUTHORIZER_URL+"/verify_email"+"?token="+token) bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message) return sender.SendMail(Receiver, Subject, bodyMessage) @@ -108,8 +108,8 @@ func SendVerificationMail(toEmail, token string) error { // SendForgotPasswordMail to send verification email func SendForgotPasswordMail(toEmail, token, host string) error { - if constants.RESET_PASSWORD_URL == "" { - constants.RESET_PASSWORD_URL = constants.AUTHORIZER_URL + "/app/reset-password" + if constants.EnvData.RESET_PASSWORD_URL == "" { + constants.EnvData.RESET_PASSWORD_URL = constants.EnvData.AUTHORIZER_URL + "/app/reset-password" } sender := email.NewSender() @@ -204,7 +204,7 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
- `, constants.ORGANIZATION_LOGO, toEmail, constants.RESET_PASSWORD_URL+"?token="+token) + `, constants.EnvData.ORGANIZATION_LOGO, toEmail, constants.EnvData.RESET_PASSWORD_URL+"?token="+token) bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message) diff --git a/server/utils/meta.go b/server/utils/meta.go index e7c2e6e..115abc6 100644 --- a/server/utils/meta.go +++ b/server/utils/meta.go @@ -9,12 +9,12 @@ import ( // version, func GetMetaInfo() model.Meta { return model.Meta{ - Version: constants.VERSION, - IsGoogleLoginEnabled: constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "", - IsGithubLoginEnabled: constants.GITHUB_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "", - IsFacebookLoginEnabled: constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "", - IsBasicAuthenticationEnabled: !constants.DISABLE_BASIC_AUTHENTICATION, - IsEmailVerificationEnabled: !constants.DISABLE_EMAIL_VERIFICATION, - IsMagicLinkLoginEnabled: !constants.DISABLE_MAGIC_LINK_LOGIN, + Version: constants.EnvData.VERSION, + IsGoogleLoginEnabled: constants.EnvData.GOOGLE_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "", + IsGithubLoginEnabled: constants.EnvData.GITHUB_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "", + IsFacebookLoginEnabled: constants.EnvData.FACEBOOK_CLIENT_ID != "" && constants.EnvData.FACEBOOK_CLIENT_SECRET != "", + IsBasicAuthenticationEnabled: !constants.EnvData.DISABLE_BASIC_AUTHENTICATION, + IsEmailVerificationEnabled: !constants.EnvData.DISABLE_EMAIL_VERIFICATION, + IsMagicLinkLoginEnabled: !constants.EnvData.DISABLE_MAGIC_LINK_LOGIN, } } diff --git a/server/utils/validator.go b/server/utils/validator.go index 4c0c6ed..74b718a 100644 --- a/server/utils/validator.go +++ b/server/utils/validator.go @@ -16,7 +16,7 @@ func IsValidEmail(email string) bool { } func IsValidOrigin(url string) bool { - if len(constants.ALLOWED_ORIGINS) == 1 && constants.ALLOWED_ORIGINS[0] == "*" { + if len(constants.EnvData.ALLOWED_ORIGINS) == 1 && constants.EnvData.ALLOWED_ORIGINS[0] == "*" { return true } @@ -24,7 +24,7 @@ func IsValidOrigin(url string) bool { hostName, port := GetHostParts(url) currentOrigin := hostName + ":" + port - for _, origin := range constants.ALLOWED_ORIGINS { + for _, origin := range constants.EnvData.ALLOWED_ORIGINS { replacedString := origin // if has regex whitelisted domains if strings.Contains(origin, "*") { @@ -50,12 +50,17 @@ func IsValidOrigin(url string) bool { } func IsSuperAdmin(gc *gin.Context) bool { - secret := gc.Request.Header.Get("x-authorizer-admin-secret") - if secret == "" { - return false + token, err := GetAdminAuthToken(gc) + if err != nil { + secret := gc.Request.Header.Get("x-authorizer-admin-secret") + if secret == "" { + return false + } + + return secret == constants.EnvData.ADMIN_SECRET } - return secret == constants.ADMIN_SECRET + return token != "" } func IsValidRoles(userRoles []string, roles []string) bool { diff --git a/server/utils/verification_token.go b/server/utils/verification_token.go index 7dbef67..254e8ac 100644 --- a/server/utils/verification_token.go +++ b/server/utils/verification_token.go @@ -20,23 +20,23 @@ type CustomClaim struct { } func CreateVerificationToken(email string, tokenType string) (string, error) { - t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE)) + t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE)) t.Claims = &CustomClaim{ &jwt.StandardClaims{ ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), }, tokenType, - UserInfo{Email: email, Host: constants.AUTHORIZER_URL, RedirectURL: constants.APP_URL}, + UserInfo{Email: email, Host: constants.EnvData.AUTHORIZER_URL, RedirectURL: constants.EnvData.APP_URL}, } - return t.SignedString([]byte(constants.JWT_SECRET)) + return t.SignedString([]byte(constants.EnvData.JWT_SECRET)) } func VerifyVerificationToken(token string) (*CustomClaim, error) { claims := &CustomClaim{} _, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { - return []byte(constants.JWT_SECRET), nil + return []byte(constants.EnvData.JWT_SECRET), nil }) if err != nil { return claims, err