Feat/dashboard (#105)

This commit is contained in:
Lakhan Samani 2022-01-17 11:32:13 +05:30 committed by GitHub
parent 7ce96367a3
commit f1b4141367
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 3381 additions and 3044 deletions

View File

@ -70,7 +70,11 @@ docker run --name arangodb -d -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb
If you are adding new resolver, If you are adding new resolver,
1. create new resolver test file [here](https://github.com/authorizerdev/authorizer/tree/main/server/__test__) 1. create new resolver test file [here](https://github.com/authorizerdev/authorizer/tree/main/server/__test__)
<<<<<<< HEAD
Naming convention filename: `resolver_name_test.go` function name: `resolverNameTest(t *testing.T, s TestSetup)`
=======
Naming convention filename: `resolver_name_test.go` function name: `resolverNameTest(s TestSetup, t *testing.T)` Naming convention filename: `resolver_name_test.go` function name: `resolverNameTest(s TestSetup, t *testing.T)`
>>>>>>> main
2. Add your tests [here](https://github.com/authorizerdev/authorizer/blob/main/server/__test__/resolvers_test.go#L38) 2. Add your tests [here](https://github.com/authorizerdev/authorizer/blob/main/server/__test__/resolvers_test.go#L38)
**Command to run tests:** **Command to run tests:**

View File

@ -10,4 +10,4 @@ build-dashboard:
clean: clean:
rm -rf build rm -rf build
test: test:
cd server && go clean --testcache && go test -v ./__test__ cd server && go clean --testcache && go test -v ./test

View File

@ -42,7 +42,11 @@ export default function App() {
<BrowserRouter> <BrowserRouter>
<AuthorizerProvider <AuthorizerProvider
config={{ config={{
<<<<<<< HEAD
authorizerURL: window.location.origin,
=======
authorizerURL: globalState.authorizerURL, authorizerURL: globalState.authorizerURL,
>>>>>>> main
redirectURL: globalState.redirectURL, redirectURL: globalState.redirectURL,
}} }}
> >

0
dashboard/src/Router.tsx Normal file
View File

View File

@ -0,0 +1,5 @@
import React from 'react';
export default function AuthLayout() {
return <h1>Auth Layout</h1>;
}

View File

@ -0,0 +1,5 @@
import React from 'react';
export default function DefaultLayout() {
return <h1>Default Layout</h1>;
}

View File

View File

@ -1,26 +0,0 @@
package test
import (
"fmt"
"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 adminLogoutTests(s TestSetup, t *testing.T) {
t.Run(`should get admin session`, func(t *testing.T) {
req, ctx := createContext(s)
_, err := resolvers.AdminLogout(ctx)
assert.NotNil(t, err)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET)
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.AdminLogout(ctx)
assert.Nil(t, err)
})
}

View File

@ -1,28 +0,0 @@
package test
import (
"fmt"
"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.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h))
_, err = resolvers.AdminSession(ctx)
assert.Nil(t, err)
})
}

View File

@ -1,25 +0,0 @@
package test
import (
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/stretchr/testify/assert"
)
func TestEnvs(t *testing.T) {
constants.EnvData.ENV_PATH = "../../.env.sample"
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{"*"})
}

View File

@ -1,65 +0,0 @@
package test
import (
"log"
"testing"
"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://localhost:8529",
enum.Mongodb.String(): "mongodb://localhost:27017",
}
for dbType, dbURL := range databases {
constants.EnvData.DATABASE_URL = dbURL
constants.EnvData.DATABASE_TYPE = dbType
db.InitDB()
// clean the persisted config for test to use fresh config
config, err := db.Mgr.GetConfig()
if err == nil {
config.Config = []byte{}
db.Mgr.UpdateConfig(config)
}
env.PersistEnv()
s := testSetup()
defer s.Server.Close()
log.Println("EnvData:", constants.EnvData)
t.Run("should pass tests for "+dbType, func(t *testing.T) {
// admin tests
adminSignupTests(s, t)
verificationRequestsTest(s, t)
usersTest(s, t)
deleteUserTest(s, t)
updateUserTest(s, t)
adminLoginTests(s, t)
adminLogoutTests(s, t)
adminSessionTests(s, t)
updateConfigTests(s, t)
configTests(s, t)
// user tests
loginTests(s, t)
signupTests(s, t)
forgotPasswordTest(s, t)
resendVerifyEmailTests(s, t)
resetPasswordTest(s, t)
verifyEmailTest(s, t)
sessionTests(s, t)
profileTests(s, t)
updateProfileTests(s, t)
magicLinkLoginTests(s, t)
logoutTests(s, t)
metaTests(s, t)
})
}
}

View File

@ -1,62 +0,0 @@
package constants
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
SMTP_PASSWORD string
SMTP_USERNAME string
SENDER_EMAIL 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 string
// OAuth login
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 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,
}

View File

@ -0,0 +1,16 @@
package constants
const (
// DbTypePostgres is the postgres database type
DbTypePostgres = "postgres"
// DbTypeSqlite is the sqlite database type
DbTypeSqlite = "sqlite"
// DbTypeMysql is the mysql database type
DbTypeMysql = "mysql"
// DbTypeSqlserver is the sqlserver database type
DbTypeSqlserver = "sqlserver"
// DbTypeArangodb is the arangodb database type
DbTypeArangodb = "arangodb"
// DbTypeMongodb is the mongodb database type
DbTypeMongodb = "mongodb"
)

87
server/constants/env.go Normal file
View File

@ -0,0 +1,87 @@
package constants
const (
// EnvKeyEnv key for env variable ENV
EnvKeyEnv = "ENV"
// EnvKeyEnvPath key for cli arg variable ENV_PATH
EnvKeyEnvPath = "ENV_PATH"
// EnvKeyVersion key for build arg version
EnvKeyVersion = "VERSION"
// EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL
EnvKeyAuthorizerURL = "AUTHORIZER_URL"
// EnvKeyPort key for env variable PORT
EnvKeyPort = "PORT"
// EnvKeyAdminSecret key for env variable ADMIN_SECRET
EnvKeyAdminSecret = "ADMIN_SECRET"
// EnvKeyDatabaseType key for env variable DATABASE_TYPE
EnvKeyDatabaseType = "DATABASE_TYPE"
// EnvKeyDatabaseURL key for env variable DATABASE_URL
EnvKeyDatabaseURL = "DATABASE_URL"
// EnvKeyDatabaseName key for env variable DATABASE_NAME
EnvKeyDatabaseName = "DATABASE_NAME"
// EnvKeySmtpHost key for env variable SMTP_HOST
EnvKeySmtpHost = "SMTP_HOST"
// EnvKeySmtpPort key for env variable SMTP_PORT
EnvKeySmtpPort = "SMTP_PORT"
// EnvKeySmtpUsername key for env variable SMTP_USERNAME
EnvKeySmtpUsername = "SMTP_USERNAME"
// EnvKeySmtpPassword key for env variable SMTP_PASSWORD
EnvKeySmtpPassword = "SMTP_PASSWORD"
// EnvKeySenderEmail key for env variable SENDER_EMAIL
EnvKeySenderEmail = "SENDER_EMAIL"
// EnvKeyJwtType key for env variable JWT_TYPE
EnvKeyJwtType = "JWT_TYPE"
// EnvKeyJwtSecret key for env variable JWT_SECRET
EnvKeyJwtSecret = "JWT_SECRET"
// EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
// EnvKeyAppURL key for env variable APP_URL
EnvKeyAppURL = "APP_URL"
// EnvKeyRedisURL key for env variable REDIS_URL
EnvKeyRedisURL = "REDIS_URL"
// EnvKeyCookieName key for env variable COOKIE_NAME
EnvKeyCookieName = "COOKIE_NAME"
// EnvKeyAdminCookieName key for env variable ADMIN_COOKIE_NAME
EnvKeyAdminCookieName = "ADMIN_COOKIE_NAME"
// EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL
EnvKeyResetPasswordURL = "RESET_PASSWORD_URL"
// EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY
EnvKeyEncryptionKey = "ENCRYPTION_KEY"
// EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
EnvKeyDisableLoginPage = "DISABLE_LOGIN_PAGE"
// EnvKeyRoles key for env variable ROLES
EnvKeyRoles = "ROLES"
// EnvKeyProtectedRoles key for env variable PROTECTED_ROLES
EnvKeyProtectedRoles = "PROTECTED_ROLES"
// EnvKeyDefaultRoles key for env variable DEFAULT_ROLES
EnvKeyDefaultRoles = "DEFAULT_ROLES"
// EnvKeyJwtRoleClaim key for env variable JWT_ROLE_CLAIM
EnvKeyJwtRoleClaim = "JWT_ROLE_CLAIM"
// EnvKeyGoogleClientID key for env variable GOOGLE_CLIENT_ID
EnvKeyGoogleClientID = "GOOGLE_CLIENT_ID"
// EnvKeyGoogleClientSecret key for env variable GOOGLE_CLIENT_SECRET
EnvKeyGoogleClientSecret = "GOOGLE_CLIENT_SECRET"
// EnvKeyGithubClientID key for env variable GITHUB_CLIENT_ID
EnvKeyGithubClientID = "GITHUB_CLIENT_ID"
// EnvKeyGithubClientSecret key for env variable GITHUB_CLIENT_SECRET
EnvKeyGithubClientSecret = "GITHUB_CLIENT_SECRET"
// EnvKeyFacebookClientID key for env variable FACEBOOK_CLIENT_ID
EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID"
// EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET
EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET"
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
EnvKeyOrganizationName = "ORGANIZATION_NAME"
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
EnvKeyOrganizationLogo = "ORGANIZATION_LOGO"
// EnvKeyIsProd key for env variable IS_PROD
EnvKeyIsProd = "IS_PROD"
// EnvKeyCustomAccessTokenScript key for env variable CUSTOM_ACCESS_TOKEN_SCRIPT
EnvKeyCustomAccessTokenScript = "CUSTOM_ACCESS_TOKEN_SCRIPT"
)

View File

@ -1,6 +1,6 @@
package constants package constants
var ( const (
// Ref: https://github.com/qor/auth/blob/master/providers/google/google.go // Ref: https://github.com/qor/auth/blob/master/providers/google/google.go
// deprecated and not used. instead we follow open id approach for google login // deprecated and not used. instead we follow open id approach for google login
GoogleUserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo" GoogleUserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo"

View File

@ -0,0 +1,14 @@
package constants
const (
// SignupMethodBasicAuth is the basic_auth signup method
SignupMethodBasicAuth = "basic_auth"
// SignupMethodMagicLinkLogin is the magic_link_login signup method
SignupMethodMagicLinkLogin = "magic_link_login"
// SignupMethodGoogle is the google signup method
SignupMethodGoogle = "google"
// SignupMethodGithub is the github signup method
SignupMethodGithub = "github"
// SignupMethodFacebook is the facebook signup method
SignupMethodFacebook = "facebook"
)

View File

@ -0,0 +1,8 @@
package constants
const (
// TokenTypeRefreshToken is the refresh_token token type
TokenTypeRefreshToken = "refresh_token"
// TokenTypeAccessToken is the access_token token type
TokenTypeAccessToken = "access_token"
)

View File

@ -0,0 +1,12 @@
package constants
const (
// VerificationTypeBasicAuthSignup is the basic_auth_signup verification type
VerificationTypeBasicAuthSignup = "basic_auth_signup"
// VerificationTypeMagicLinkLogin is the magic_link_login verification type
VerificationTypeMagicLinkLogin = "magic_link_login"
// VerificationTypeUpdateEmail is the update_email verification type
VerificationTypeUpdateEmail = "update_email"
// VerificationTypeForgotPassword is the forgot_password verification type
VerificationTypeForgotPassword = "forgot_password"
)

View File

@ -8,6 +8,7 @@ import (
arangoDriver "github.com/arangodb/go-driver" arangoDriver "github.com/arangodb/go-driver"
"github.com/arangodb/go-driver/http" "github.com/arangodb/go-driver/http"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
) )
// for this we need arangodb instance up and running // for this we need arangodb instance up and running
@ -17,7 +18,7 @@ import (
func initArangodb() (arangoDriver.Database, error) { func initArangodb() (arangoDriver.Database, error) {
ctx := context.Background() ctx := context.Background()
conn, err := http.NewConnection(http.ConnectionConfig{ conn, err := http.NewConnection(http.ConnectionConfig{
Endpoints: []string{constants.EnvData.DATABASE_URL}, Endpoints: []string{envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string)},
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -32,16 +33,16 @@ func initArangodb() (arangoDriver.Database, error) {
var arangodb driver.Database var arangodb driver.Database
arangodb_exists, err := arangoClient.DatabaseExists(nil, constants.EnvData.DATABASE_NAME) arangodb_exists, err := arangoClient.DatabaseExists(nil, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseName).(string))
if arangodb_exists { if arangodb_exists {
log.Println(constants.EnvData.DATABASE_NAME + " db exists already") log.Println(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseName).(string) + " db exists already")
arangodb, err = arangoClient.Database(nil, constants.EnvData.DATABASE_NAME) arangodb, err = arangoClient.Database(nil, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseName).(string))
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else { } else {
arangodb, err = arangoClient.CreateDatabase(nil, constants.EnvData.DATABASE_NAME, nil) arangodb, err = arangoClient.CreateDatabase(nil, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseName).(string), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,7 +5,7 @@ import (
arangoDriver "github.com/arangodb/go-driver" arangoDriver "github.com/arangodb/go-driver"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
@ -66,9 +66,9 @@ func InitDB() {
var sqlDB *gorm.DB var sqlDB *gorm.DB
var err error var err error
IsORMSupported = constants.EnvData.DATABASE_TYPE != enum.Arangodb.String() && constants.EnvData.DATABASE_TYPE != enum.Mongodb.String() IsORMSupported = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string) != constants.DbTypeArangodb && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string) != constants.DbTypeMongodb
IsArangoDB = constants.EnvData.DATABASE_TYPE == enum.Arangodb.String() IsArangoDB = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string) == constants.DbTypeArangodb
IsMongoDB = constants.EnvData.DATABASE_TYPE == enum.Mongodb.String() IsMongoDB = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string) == constants.DbTypeMongodb
// sql db orm config // sql db orm config
ormConfig := &gorm.Config{ ormConfig := &gorm.Config{
@ -77,22 +77,22 @@ func InitDB() {
}, },
} }
log.Println("db type:", constants.EnvData.DATABASE_TYPE) log.Println("db type:", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string))
switch constants.EnvData.DATABASE_TYPE { switch envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseType).(string) {
case enum.Postgres.String(): case constants.DbTypePostgres:
sqlDB, err = gorm.Open(postgres.Open(constants.EnvData.DATABASE_URL), ormConfig) sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string)), ormConfig)
break break
case enum.Sqlite.String(): case constants.DbTypeSqlite:
sqlDB, err = gorm.Open(sqlite.Open(constants.EnvData.DATABASE_URL), ormConfig) sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string)), ormConfig)
break break
case enum.Mysql.String(): case constants.DbTypeMysql:
sqlDB, err = gorm.Open(mysql.Open(constants.EnvData.DATABASE_URL), ormConfig) sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string)), ormConfig)
break break
case enum.SQLServer.String(): case constants.DbTypeSqlserver:
sqlDB, err = gorm.Open(sqlserver.Open(constants.EnvData.DATABASE_URL), ormConfig) sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string)), ormConfig)
break break
case enum.Arangodb.String(): case constants.DbTypeArangodb:
arangodb, err := initArangodb() arangodb, err := initArangodb()
if err != nil { if err != nil {
log.Fatal("error initializing arangodb:", err) log.Fatal("error initializing arangodb:", err)
@ -105,7 +105,7 @@ func InitDB() {
} }
break break
case enum.Mongodb.String(): case constants.DbTypeMongodb:
mongodb, err := initMongodb() mongodb, err := initMongodb()
if err != nil { if err != nil {
log.Fatal("error initializing mongodb connection:", err) log.Fatal("error initializing mongodb connection:", err)

View File

@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
@ -12,7 +13,7 @@ import (
) )
func initMongodb() (*mongo.Database, error) { func initMongodb() (*mongo.Database, error) {
mongodbOptions := options.Client().ApplyURI(constants.EnvData.DATABASE_URL) mongodbOptions := options.Client().ApplyURI(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseURL).(string))
maxWait := time.Duration(5 * time.Second) maxWait := time.Duration(5 * time.Second)
mongodbOptions.ConnectTimeout = &maxWait mongodbOptions.ConnectTimeout = &maxWait
mongoClient, err := mongo.NewClient(mongodbOptions) mongoClient, err := mongo.NewClient(mongodbOptions)
@ -30,7 +31,7 @@ func initMongodb() (*mongo.Database, error) {
return nil, err return nil, err
} }
mongodb := mongoClient.Database(constants.EnvData.DATABASE_NAME, options.Database()) mongodb := mongoClient.Database(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDatabaseName).(string), options.Database())
mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection()) mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection())
userCollection := mongodb.Collection(Collections.User, options.Collection()) userCollection := mongodb.Collection(Collections.User, options.Collection())

View File

@ -3,11 +3,13 @@ package db
import ( import (
"fmt" "fmt"
"log" "log"
"strings"
"time" "time"
"github.com/arangodb/go-driver" "github.com/arangodb/go-driver"
arangoDriver "github.com/arangodb/go-driver" arangoDriver "github.com/arangodb/go-driver"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/google/uuid" "github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
@ -43,7 +45,7 @@ func (mgr *manager) AddUser(user User) (User, error) {
} }
if user.Roles == "" { if user.Roles == "" {
user.Roles = constants.EnvData.DEFAULT_ROLES[0] user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDefaultRoles).([]string), ",")
} }
if IsORMSupported { if IsORMSupported {
@ -185,6 +187,7 @@ func (mgr *manager) GetUsers() ([]User, error) {
return users, nil return users, nil
} }
// GetUserByEmail function to get user by email
func (mgr *manager) GetUserByEmail(email string) (User, error) { func (mgr *manager) GetUserByEmail(email string) (User, error) {
var user User var user User
@ -233,6 +236,7 @@ func (mgr *manager) GetUserByEmail(email string) (User, error) {
return user, nil return user, nil
} }
// GetUserByID function to get user by ID
func (mgr *manager) GetUserByID(id string) (User, error) { func (mgr *manager) GetUserByID(id string) (User, error) {
var user User var user User
@ -281,6 +285,7 @@ func (mgr *manager) GetUserByID(id string) (User, error) {
return user, nil return user, nil
} }
// DeleteUser function to delete user
func (mgr *manager) DeleteUser(user User) error { func (mgr *manager) DeleteUser(user User) error {
if IsORMSupported { if IsORMSupported {
result := mgr.sqlDB.Delete(&user) result := mgr.sqlDB.Delete(&user)

View File

@ -1,23 +1,44 @@
package email package email
import ( import (
"bytes"
"crypto/tls" "crypto/tls"
"encoding/json"
"log" "log"
"strconv" "strconv"
"text/template"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
gomail "gopkg.in/mail.v2" gomail "gopkg.in/mail.v2"
) )
// addEmailTemplate is used to add html template in email body
func addEmailTemplate(a string, b map[string]interface{}, templateName string) string {
tmpl, err := template.New(templateName).Parse(a)
if err != nil {
output, _ := json.Marshal(b)
return string(output)
}
buf := &bytes.Buffer{}
err = tmpl.Execute(buf, b)
if err != nil {
panic(err)
}
s := buf.String()
return s
}
// SendMail function to send mail
func SendMail(to []string, Subject, bodyMessage string) error { func SendMail(to []string, Subject, bodyMessage string) error {
m := gomail.NewMessage() m := gomail.NewMessage()
m.SetHeader("From", constants.EnvData.SENDER_EMAIL) m.SetHeader("From", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeySenderEmail).(string))
m.SetHeader("To", to...) m.SetHeader("To", to...)
m.SetHeader("Subject", Subject) m.SetHeader("Subject", Subject)
m.SetBody("text/html", bodyMessage) m.SetBody("text/html", bodyMessage)
port, _ := strconv.Atoi(constants.EnvData.SMTP_PORT) port, _ := strconv.Atoi(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeySmtpPort).(string))
d := gomail.NewDialer(constants.EnvData.SMTP_HOST, port, constants.EnvData.SMTP_USERNAME, constants.EnvData.SMTP_PASSWORD) d := gomail.NewDialer(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeySmtpHost).(string), port, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeySmtpUsername).(string), envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeySmtpPassword).(string))
if constants.EnvData.ENV == "development" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyEnv).(string) == "development" {
d.TLSConfig = &tls.Config{InsecureSkipVerify: true} d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
} }
if err := d.DialAndSend(m); err != nil { if err := d.DialAndSend(m); err != nil {

View File

@ -0,0 +1,112 @@
package email
import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
)
// SendForgotPasswordMail to send forgot password email
func SendForgotPasswordMail(toEmail, token, host string) error {
resetPasswordUrl := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyResetPasswordURL).(string)
if resetPasswordUrl == "" {
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string)+"/app/reset-password")
}
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Reset Password"
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="telephone=no" name="format-detection">
<title></title>
<!--[if (mso 16)]>
<style type="text/css">
a {}
</style>
<![endif]-->
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
<!--[if gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG></o:AllowPNG>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
<v:fill type="tile" color="#ffffff"></v:fill>
</v:background>
<![endif]-->
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-email-paddings" valign="top">
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td class="esd-stripe" align="center">
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
<tbody>
<tr>
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-container-frame" width="518" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We have received a request to reset password for email: <b>{{.org_name}}</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
<a clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`
data := make(map[string]interface{}, 3)
data["org_logo"] = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationLogo).(string)
data["org_name"] = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationName).(string)
data["verification_url"] = resetPasswordUrl + "?token=" + token
message = addEmailTemplate(message, data, "reset_password_email.tmpl")
return SendMail(Receiver, Subject, message)
}

View File

@ -0,0 +1,107 @@
package email
import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
)
// SendVerificationMail to send verification email
func SendVerificationMail(toEmail, token string) error {
// The receiver needs to be in slice as the receive supports multiple receiver
Receiver := []string{toEmail}
Subject := "Please verify your email"
message := `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<meta name="x-apple-disable-message-reformatting">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="telephone=no" name="format-detection">
<title></title>
<!--[if (mso 16)]>
<style type="text/css">
a {}
</style>
<![endif]-->
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
<!--[if gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG></o:AllowPNG>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
</head>
<body style="font-family: sans-serif;">
<div class="es-wrapper-color">
<!--[if gte mso 9]>
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
<v:fill type="tile" color="#ffffff"></v:fill>
</v:background>
<![endif]-->
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-email-paddings" valign="top">
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td class="esd-stripe" align="center">
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
<tbody>
<tr>
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-container-frame" width="518" align="left">
<table width="100%%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
</tr>
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
<p>Hey there 👋</p>
<p>We have received request to verify email for <b>{{.org_name}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
<a
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
</body>
</html>
`
data := make(map[string]interface{}, 3)
data["org_logo"] = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationLogo).(string)
data["org_name"] = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationName).(string)
data["verification_url"] = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/verify_email?token=" + token
message = addEmailTemplate(message, data, "verify_email.tmpl")
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
return SendMail(Receiver, Subject, message)
}

View File

@ -1,23 +0,0 @@
package enum
type DbType int
const (
Postgres DbType = iota
Sqlite
Mysql
SQLServer
Arangodb
Mongodb
)
func (d DbType) String() string {
return [...]string{
"postgres",
"sqlite",
"mysql",
"sqlserver",
"arangodb",
"mongodb",
}[d]
}

View File

@ -1,15 +0,0 @@
package enum
type OAuthProvider int
const (
GoogleProvider OAuthProvider = iota
GithubProvider
)
func (d OAuthProvider) String() string {
return [...]string{
"google_provider",
"github_provider",
}[d]
}

View File

@ -1,21 +0,0 @@
package enum
type SignupMethod int
const (
BasicAuth SignupMethod = iota
MagicLinkLogin
Google
Github
Facebook
)
func (d SignupMethod) String() string {
return [...]string{
"basic_auth",
"magic_link_login",
"google",
"github",
"facebook",
}[d]
}

View File

@ -1,15 +0,0 @@
package enum
type TokenType int
const (
RefreshToken TokenType = iota
AccessToken
)
func (d TokenType) String() string {
return [...]string{
"refresh_token",
"access_token",
}[d]
}

View File

@ -1,17 +0,0 @@
package enum
type VerificationType int
const (
BasicAuthSignup VerificationType = iota
UpdateEmail
ForgotPassword
)
func (d VerificationType) String() string {
return [...]string{
"basic_auth_signup",
"update_email",
"forgot_password",
}[d]
}

247
server/env/env.go vendored
View File

@ -6,188 +6,197 @@ import (
"strings" "strings"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/joho/godotenv" "github.com/joho/godotenv"
) )
// build variables // TODO move this to env store
var ( var (
// ARG_DB_URL is the cli arg variable for the database url
ARG_DB_URL *string ARG_DB_URL *string
// ARG_DB_TYPE is the cli arg variable for the database type
ARG_DB_TYPE *string ARG_DB_TYPE *string
ARG_AUTHORIZER_URL *string // ARG_ENV_FILE is the cli arg variable for the env file
ARG_ENV_FILE *string ARG_ENV_FILE *string
) )
// InitEnv -> to initialize env and through error if required env are not present // InitEnv to initialize EnvData and through error if required env are not present
func InitEnv() { func InitEnv() {
if constants.EnvData.ENV_PATH == "" { // get clone of current store
constants.EnvData.ENV_PATH = `.env` envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
if envData[constants.EnvKeyEnv] == nil || envData[constants.EnvKeyEnv] == "" {
envData[constants.EnvKeyEnv] = os.Getenv("ENV")
if envData[constants.EnvKeyEnv] == "" {
envData[constants.EnvKeyEnv] = "production"
}
if envData[constants.EnvKeyEnv] == "production" {
envData[constants.EnvKeyIsProd] = true
os.Setenv("GIN_MODE", "release")
} else {
envData[constants.EnvKeyIsProd] = false
}
}
// set authorizer url to empty string so that fresh url is obtained with every server start
envData[constants.EnvKeyAuthorizerURL] = ""
if envData[constants.EnvKeyAppURL] == nil || envData[constants.EnvKeyAppURL] == "" {
envData[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL)
}
if envData[constants.EnvKeyEnvPath] == nil || envData[constants.EnvKeyEnvPath].(string) == "" {
envData[constants.EnvKeyEnvPath] = `.env`
} }
if ARG_ENV_FILE != nil && *ARG_ENV_FILE != "" { if ARG_ENV_FILE != nil && *ARG_ENV_FILE != "" {
constants.EnvData.ENV_PATH = *ARG_ENV_FILE envData[constants.EnvKeyEnvPath] = *ARG_ENV_FILE
} }
err := godotenv.Load(constants.EnvData.ENV_PATH) err := godotenv.Load(envData[constants.EnvKeyEnvPath].(string))
if err != nil { if err != nil {
log.Printf("error loading %s file", constants.EnvData.ENV_PATH) log.Printf("error loading %s file", envData[constants.EnvKeyEnvPath])
} }
if constants.EnvData.ADMIN_SECRET == "" { if envData[constants.EnvKeyPort] == nil || envData[constants.EnvKeyPort].(string) == "" {
constants.EnvData.ADMIN_SECRET = os.Getenv("ADMIN_SECRET") envData[constants.EnvKeyPort] = os.Getenv("PORT")
if envData[constants.EnvKeyPort].(string) == "" {
envData[constants.EnvKeyPort] = "8080"
}
} }
if constants.EnvData.DATABASE_TYPE == "" { if envData[constants.EnvKeyAdminSecret] == nil || envData[constants.EnvKeyAdminSecret].(string) == "" {
constants.EnvData.DATABASE_TYPE = os.Getenv("DATABASE_TYPE") envData[constants.EnvKeyAdminSecret] = os.Getenv("ADMIN_SECRET")
log.Println(constants.EnvData.DATABASE_TYPE) }
if envData[constants.EnvKeyDatabaseType] == nil || envData[constants.EnvKeyDatabaseType].(string) == "" {
envData[constants.EnvKeyDatabaseType] = os.Getenv("DATABASE_TYPE")
log.Println(envData[constants.EnvKeyDatabaseType].(string))
if ARG_DB_TYPE != nil && *ARG_DB_TYPE != "" { if ARG_DB_TYPE != nil && *ARG_DB_TYPE != "" {
constants.EnvData.DATABASE_TYPE = *ARG_DB_TYPE envData[constants.EnvKeyDatabaseType] = *ARG_DB_TYPE
} }
if constants.EnvData.DATABASE_TYPE == "" { if envData[constants.EnvKeyDatabaseType].(string) == "" {
panic("DATABASE_TYPE is required") panic("DATABASE_TYPE is required")
} }
} }
if constants.EnvData.DATABASE_URL == "" { if envData[constants.EnvKeyDatabaseURL] == nil || envData[constants.EnvKeyDatabaseURL].(string) == "" {
constants.EnvData.DATABASE_URL = os.Getenv("DATABASE_URL") envData[constants.EnvKeyDatabaseURL] = os.Getenv("DATABASE_URL")
if ARG_DB_URL != nil && *ARG_DB_URL != "" { if ARG_DB_URL != nil && *ARG_DB_URL != "" {
constants.EnvData.DATABASE_URL = *ARG_DB_URL envData[constants.EnvKeyDatabaseURL] = *ARG_DB_URL
} }
if constants.EnvData.DATABASE_URL == "" { if envData[constants.EnvKeyDatabaseURL] == "" {
panic("DATABASE_URL is required") panic("DATABASE_URL is required")
} }
} }
if constants.EnvData.DATABASE_NAME == "" { if envData[constants.EnvKeyDatabaseName] == nil || envData[constants.EnvKeyDatabaseName].(string) == "" {
constants.EnvData.DATABASE_NAME = os.Getenv("DATABASE_NAME") envData[constants.EnvKeyDatabaseName] = os.Getenv("DATABASE_NAME")
if constants.EnvData.DATABASE_NAME == "" { if envData[constants.EnvKeyDatabaseName].(string) == "" {
constants.EnvData.DATABASE_NAME = "authorizer" envData[constants.EnvKeyDatabaseName] = "authorizer"
} }
} }
if constants.EnvData.ENV == "" { if envData[constants.EnvKeySmtpHost] == nil || envData[constants.EnvKeySmtpHost].(string) == "" {
constants.EnvData.ENV = os.Getenv("ENV") envData[constants.EnvKeySmtpHost] = os.Getenv("SMTP_HOST")
if constants.EnvData.ENV == "" {
constants.EnvData.ENV = "production"
} }
if constants.EnvData.ENV == "production" { if envData[constants.EnvKeySmtpPort] == nil || envData[constants.EnvKeySmtpPort].(string) == "" {
constants.EnvData.IS_PROD = true envData[constants.EnvKeySmtpPort] = os.Getenv("SMTP_PORT")
os.Setenv("GIN_MODE", "release") }
} else {
constants.EnvData.IS_PROD = false if envData[constants.EnvKeySmtpUsername] == nil || envData[constants.EnvKeySmtpUsername].(string) == "" {
envData[constants.EnvKeySmtpUsername] = os.Getenv("SMTP_USERNAME")
}
if envData[constants.EnvKeySmtpPassword] == nil || envData[constants.EnvKeySmtpPassword].(string) == "" {
envData[constants.EnvKeySmtpPassword] = os.Getenv("SMTP_PASSWORD")
}
if envData[constants.EnvKeySenderEmail] == nil || envData[constants.EnvKeySenderEmail].(string) == "" {
envData[constants.EnvKeySenderEmail] = os.Getenv("SENDER_EMAIL")
}
if envData[constants.EnvKeyJwtSecret] == nil || envData[constants.EnvKeyJwtSecret].(string) == "" {
envData[constants.EnvKeyJwtSecret] = os.Getenv("JWT_SECRET")
if envData[constants.EnvKeyJwtSecret].(string) == "" {
envData[constants.EnvKeyJwtSecret] = uuid.New().String()
} }
} }
if constants.EnvData.SMTP_HOST == "" { if envData[constants.EnvKeyJwtType] == nil || envData[constants.EnvKeyJwtType].(string) == "" {
constants.EnvData.SMTP_HOST = os.Getenv("SMTP_HOST") envData[constants.EnvKeyJwtType] = os.Getenv("JWT_TYPE")
} if envData[constants.EnvKeyJwtType].(string) == "" {
envData[constants.EnvKeyJwtType] = "HS256"
if constants.EnvData.SMTP_PORT == "" {
constants.EnvData.SMTP_PORT = os.Getenv("SMTP_PORT")
}
if constants.EnvData.SMTP_USERNAME == "" {
constants.EnvData.SMTP_USERNAME = os.Getenv("SMTP_USERNAME")
}
if constants.EnvData.SMTP_PASSWORD == "" {
constants.EnvData.SMTP_PASSWORD = os.Getenv("SMTP_PASSWORD")
}
if constants.EnvData.SENDER_EMAIL == "" {
constants.EnvData.SENDER_EMAIL = os.Getenv("SENDER_EMAIL")
}
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 == "" { if envData[constants.EnvKeyJwtRoleClaim] == nil || envData[constants.EnvKeyJwtRoleClaim].(string) == "" {
constants.EnvData.JWT_TYPE = os.Getenv("JWT_TYPE") envData[constants.EnvKeyJwtRoleClaim] = os.Getenv("JWT_ROLE_CLAIM")
if constants.EnvData.JWT_TYPE == "" {
constants.EnvData.JWT_TYPE = "HS256" if envData[constants.EnvKeyJwtRoleClaim].(string) == "" {
envData[constants.EnvKeyJwtRoleClaim] = "role"
} }
} }
if constants.EnvData.JWT_ROLE_CLAIM == "" { if envData[constants.EnvKeyRedisURL] == nil || envData[constants.EnvKeyRedisURL].(string) == "" {
constants.EnvData.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM") envData[constants.EnvKeyRedisURL] = os.Getenv("REDIS_URL")
}
if constants.EnvData.JWT_ROLE_CLAIM == "" { if envData[constants.EnvKeyCookieName] == nil || envData[constants.EnvKeyCookieName].(string) == "" {
constants.EnvData.JWT_ROLE_CLAIM = "role" envData[constants.EnvKeyCookieName] = os.Getenv("COOKIE_NAME")
if envData[constants.EnvKeyCookieName].(string) == "" {
envData[constants.EnvKeyCookieName] = "authorizer"
} }
} }
if constants.EnvData.AUTHORIZER_URL == "" { if envData[constants.EnvKeyGoogleClientID] == nil || envData[constants.EnvKeyGoogleClientID].(string) == "" {
constants.EnvData.AUTHORIZER_URL = strings.TrimSuffix(os.Getenv("AUTHORIZER_URL"), "/") envData[constants.EnvKeyGoogleClientID] = os.Getenv("GOOGLE_CLIENT_ID")
if ARG_AUTHORIZER_URL != nil && *ARG_AUTHORIZER_URL != "" {
constants.EnvData.AUTHORIZER_URL = *ARG_AUTHORIZER_URL
}
} }
if constants.EnvData.PORT == "" { if envData[constants.EnvKeyGoogleClientSecret] == nil || envData[constants.EnvKeyGoogleClientSecret].(string) == "" {
constants.EnvData.PORT = os.Getenv("PORT") envData[constants.EnvKeyGoogleClientSecret] = os.Getenv("GOOGLE_CLIENT_SECRET")
if constants.EnvData.PORT == "" {
constants.EnvData.PORT = "8080"
}
} }
if constants.EnvData.REDIS_URL == "" { if envData[constants.EnvKeyGithubClientID] == nil || envData[constants.EnvKeyGithubClientID].(string) == "" {
constants.EnvData.REDIS_URL = os.Getenv("REDIS_URL") envData[constants.EnvKeyGithubClientID] = os.Getenv("GITHUB_CLIENT_ID")
} }
if constants.EnvData.COOKIE_NAME == "" { if envData[constants.EnvKeyGithubClientSecret] == nil || envData[constants.EnvKeyGithubClientSecret].(string) == "" {
constants.EnvData.COOKIE_NAME = os.Getenv("COOKIE_NAME") envData[constants.EnvKeyGithubClientSecret] = os.Getenv("GITHUB_CLIENT_SECRET")
if constants.EnvData.COOKIE_NAME == "" {
constants.EnvData.COOKIE_NAME = "authorizer"
}
} }
if constants.EnvData.GOOGLE_CLIENT_ID == "" { if envData[constants.EnvKeyFacebookClientID] == nil || envData[constants.EnvKeyFacebookClientID].(string) == "" {
constants.EnvData.GOOGLE_CLIENT_ID = os.Getenv("GOOGLE_CLIENT_ID") envData[constants.EnvKeyFacebookClientID] = os.Getenv("FACEBOOK_CLIENT_ID")
} }
if constants.EnvData.GOOGLE_CLIENT_SECRET == "" { if envData[constants.EnvKeyFacebookClientSecret] == nil || envData[constants.EnvKeyFacebookClientSecret].(string) == "" {
constants.EnvData.GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET") envData[constants.EnvKeyFacebookClientSecret] = os.Getenv("FACEBOOK_CLIENT_SECRET")
} }
if constants.EnvData.GITHUB_CLIENT_ID == "" { if envData[constants.EnvKeyResetPasswordURL] == nil || envData[constants.EnvKeyResetPasswordURL].(string) == "" {
constants.EnvData.GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID") envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
} }
if constants.EnvData.GITHUB_CLIENT_SECRET == "" { envData[constants.EnvKeyDisableBasicAuthentication] = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true"
constants.EnvData.GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET") envData[constants.EnvKeyDisableEmailVerification] = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true"
envData[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true"
envData[constants.EnvKeyDisableLoginPage] = os.Getenv("DISABLE_LOGIN_PAGE") == "true"
// no need to add nil check as its already done above
if envData[constants.EnvKeySmtpHost].(string) == "" || envData[constants.EnvKeySmtpUsername].(string) == "" || envData[constants.EnvKeySmtpPassword].(string) == "" || envData[constants.EnvKeySenderEmail].(string) == "" {
envData[constants.EnvKeyDisableEmailVerification] = true
envData[constants.EnvKeyDisableMagicLinkLogin] = true
} }
if constants.EnvData.FACEBOOK_CLIENT_ID == "" { if envData[constants.EnvKeyDisableEmailVerification].(bool) {
constants.EnvData.FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID") envData[constants.EnvKeyDisableMagicLinkLogin] = true
}
if constants.EnvData.FACEBOOK_CLIENT_SECRET == "" {
constants.EnvData.FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
}
if constants.EnvData.RESET_PASSWORD_URL == "" {
constants.EnvData.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
}
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.EnvData.SMTP_HOST == "" || constants.EnvData.SMTP_USERNAME == "" || constants.EnvData.SMTP_PASSWORD == "" || constants.EnvData.SENDER_EMAIL == "" {
constants.EnvData.DISABLE_EMAIL_VERIFICATION = true
constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true
} }
allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",") allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")
@ -216,11 +225,7 @@ func InitEnv() {
allowedOrigins = []string{"*"} allowedOrigins = []string{"*"}
} }
constants.EnvData.ALLOWED_ORIGINS = allowedOrigins envData[constants.EnvKeyAllowedOrigins] = allowedOrigins
if constants.EnvData.DISABLE_EMAIL_VERIFICATION {
constants.EnvData.DISABLE_MAGIC_LINK_LOGIN = true
}
rolesEnv := strings.TrimSpace(os.Getenv("ROLES")) rolesEnv := strings.TrimSpace(os.Getenv("ROLES"))
rolesSplit := strings.Split(rolesEnv, ",") rolesSplit := strings.Split(rolesEnv, ",")
@ -263,15 +268,17 @@ func InitEnv() {
panic(`Invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`) panic(`Invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`)
} }
constants.EnvData.ROLES = roles envData[constants.EnvKeyRoles] = roles
constants.EnvData.DEFAULT_ROLES = defaultRoles envData[constants.EnvKeyDefaultRoles] = defaultRoles
constants.EnvData.PROTECTED_ROLES = protectedRoles envData[constants.EnvKeyProtectedRoles] = protectedRoles
if os.Getenv("ORGANIZATION_NAME") != "" { if os.Getenv("ORGANIZATION_NAME") != "" {
constants.EnvData.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME") envData[constants.EnvKeyOrganizationName] = os.Getenv("ORGANIZATION_NAME")
} }
if os.Getenv("ORGANIZATION_LOGO") != "" { if os.Getenv("ORGANIZATION_LOGO") != "" {
constants.EnvData.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO") envData[constants.EnvKeyOrganizationLogo] = os.Getenv("ORGANIZATION_LOGO")
} }
envstore.EnvInMemoryStoreObj.UpdateEnvStore(envData)
} }

View File

@ -9,20 +9,22 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid" "github.com/google/uuid"
) )
// PersistEnv persists the environment variables to the database
func PersistEnv() error { func PersistEnv() error {
config, err := db.Mgr.GetConfig() config, err := db.Mgr.GetConfig()
// config not found in db // config not found in db
if err != nil { if err != nil {
// AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid
hash := uuid.New().String()[:36-4] hash := uuid.New().String()[:36-4]
constants.EnvData.ENCRYPTION_KEY = hash envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash)
encodedHash := utils.EncryptB64(hash) encodedHash := utils.EncryptB64(hash)
configData, err := json.Marshal(constants.EnvData) configData, err := json.Marshal(envstore.EnvInMemoryStoreObj.GetEnvStoreClone())
if err != nil { if err != nil {
return err return err
} }
@ -45,7 +47,8 @@ func PersistEnv() error {
if err != nil { if err != nil {
return err return err
} }
constants.EnvData.ENCRYPTION_KEY = decryptedEncryptionKey
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
decryptedConfigs, err := utils.DecryptAES(config.Config) decryptedConfigs, err := utils.DecryptAES(config.Config)
if err != nil { if err != nil {
return err return err
@ -119,7 +122,7 @@ func PersistEnv() error {
} }
if hasChanged { if hasChanged {
encryptedConfig, err := utils.EncryptConfig(jsonData) encryptedConfig, err := utils.EncryptEnvData(jsonData)
if err != nil { if err != nil {
return err return err
} }

65
server/envstore/store.go Normal file
View File

@ -0,0 +1,65 @@
package envstore
import (
"sync"
"github.com/authorizerdev/authorizer/server/constants"
)
// EnvInMemoryStore struct
type EnvInMemoryStore struct {
mutex sync.Mutex
store map[string]interface{}
}
// EnvInMemoryStoreObj global variable for EnvInMemoryStore
var EnvInMemoryStoreObj = &EnvInMemoryStore{
store: map[string]interface{}{
constants.EnvKeyAdminCookieName: "authorizer-admin",
constants.EnvKeyJwtRoleClaim: "role",
constants.EnvKeyOrganizationName: "Authorizer",
constants.EnvKeyOrganizationLogo: "https://www.authorizer.io/images/logo.png",
constants.EnvKeyDisableBasicAuthentication: false,
constants.EnvKeyDisableMagicLinkLogin: false,
constants.EnvKeyDisableEmailVerification: false,
constants.EnvKeyDisableLoginPage: false,
},
}
// UpdateEnvStore to update the whole env store object
func (e *EnvInMemoryStore) UpdateEnvStore(data map[string]interface{}) {
e.mutex.Lock()
defer e.mutex.Unlock()
// just override the keys + new keys
for key, value := range data {
e.store[key] = value
}
}
// UpdateEnvVariable to update the particular env variable
func (e *EnvInMemoryStore) UpdateEnvVariable(key string, value interface{}) map[string]interface{} {
e.mutex.Lock()
defer e.mutex.Unlock()
e.store[key] = value
return e.store
}
// GetEnvStore to get the env variable from env store object
func (e *EnvInMemoryStore) GetEnvVariable(key string) interface{} {
// e.mutex.Lock()
// defer e.mutex.Unlock()
return e.store[key]
}
// GetEnvStoreClone to get clone of current env store object
func (e *EnvInMemoryStore) GetEnvStoreClone() map[string]interface{} {
e.mutex.Lock()
defer e.mutex.Unlock()
result := make(map[string]interface{})
for key, value := range e.store {
result[key] = value
}
return result
}

View File

@ -1182,6 +1182,7 @@ input UpdateProfileInput {
input UpdateUserInput { input UpdateUserInput {
id: ID! id: ID!
email: String email: String
email_verified: Boolean
given_name: String given_name: String
family_name: String family_name: String
middle_name: String middle_name: String
@ -6646,6 +6647,14 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o
if err != nil { if err != nil {
return it, err return it, err
} }
case "email_verified":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email_verified"))
it.EmailVerified, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
case "given_name": case "given_name":
var err error var err error

View File

@ -170,6 +170,7 @@ type UpdateProfileInput struct {
type UpdateUserInput struct { type UpdateUserInput struct {
ID string `json:"id"` ID string `json:"id"`
Email *string `json:"email"` Email *string `json:"email"`
EmailVerified *bool `json:"email_verified"`
GivenName *string `json:"given_name"` GivenName *string `json:"given_name"`
FamilyName *string `json:"family_name"` FamilyName *string `json:"family_name"`
MiddleName *string `json:"middle_name"` MiddleName *string `json:"middle_name"`

View File

@ -189,6 +189,7 @@ input UpdateProfileInput {
input UpdateUserInput { input UpdateUserInput {
id: ID! id: ID!
email: String email: String
email_verified: Boolean
given_name: String given_name: String
family_name: String family_name: String
middle_name: String middle_name: String

View File

@ -12,47 +12,47 @@ import (
) )
func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) {
return resolvers.Signup(ctx, params) return resolvers.SignupResolver(ctx, params)
} }
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
return resolvers.Login(ctx, params) return resolvers.LoginResolver(ctx, params)
} }
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
return resolvers.MagicLinkLogin(ctx, params) return resolvers.MagicLinkLoginResolver(ctx, params)
} }
func (r *mutationResolver) Logout(ctx context.Context) (*model.Response, error) { func (r *mutationResolver) Logout(ctx context.Context) (*model.Response, error) {
return resolvers.Logout(ctx) return resolvers.LogoutResolver(ctx)
} }
func (r *mutationResolver) UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) { func (r *mutationResolver) UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) {
return resolvers.UpdateProfile(ctx, params) return resolvers.UpdateProfileResolver(ctx, params)
} }
func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) { func (r *mutationResolver) VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) {
return resolvers.VerifyEmail(ctx, params) return resolvers.VerifyEmailResolver(ctx, params)
} }
func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) {
return resolvers.ResendVerifyEmail(ctx, params) return resolvers.ResendVerifyEmailResolver(ctx, params)
} }
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) { func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
return resolvers.ForgotPassword(ctx, params) return resolvers.ForgotPasswordResolver(ctx, params)
} }
func (r *mutationResolver) ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { func (r *mutationResolver) ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) {
return resolvers.ResetPassword(ctx, params) return resolvers.ResetPasswordResolver(ctx, params)
} }
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
return resolvers.DeleteUser(ctx, params) return resolvers.DeleteUserResolver(ctx, params)
} }
func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) { func (r *mutationResolver) UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) {
return resolvers.UpdateUser(ctx, params) return resolvers.UpdateUserResolver(ctx, params)
} }
func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) { func (r *mutationResolver) AdminSignup(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) {
@ -64,7 +64,7 @@ func (r *mutationResolver) AdminLogin(ctx context.Context, params model.AdminLog
} }
func (r *mutationResolver) AdminLogout(ctx context.Context) (*model.Response, error) { func (r *mutationResolver) AdminLogout(ctx context.Context) (*model.Response, error) {
return resolvers.AdminLogout(ctx) return resolvers.AdminLogoutResolver(ctx)
} }
func (r *mutationResolver) UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) { func (r *mutationResolver) UpdateConfig(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) {
@ -72,27 +72,27 @@ func (r *mutationResolver) UpdateConfig(ctx context.Context, params model.Update
} }
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) { func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
return resolvers.Meta(ctx) return resolvers.MetaResolver(ctx)
} }
func (r *queryResolver) Session(ctx context.Context, roles []string) (*model.AuthResponse, error) { func (r *queryResolver) Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
return resolvers.Session(ctx, roles) return resolvers.SessionResolver(ctx, roles)
} }
func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) { func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) {
return resolvers.Profile(ctx) return resolvers.ProfileResolver(ctx)
} }
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) { func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
return resolvers.Users(ctx) return resolvers.UsersResolver(ctx)
} }
func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) { func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) {
return resolvers.VerificationRequests(ctx) return resolvers.VerificationRequestsResolver(ctx)
} }
func (r *queryResolver) AdminSession(ctx context.Context) (*model.Response, error) { func (r *queryResolver) AdminSession(ctx context.Context) (*model.Response, error) {
return resolvers.AdminSession(ctx) return resolvers.AdminSessionResolver(ctx)
} }
func (r *queryResolver) Config(ctx context.Context) (*model.Config, error) { func (r *queryResolver) Config(ctx context.Context) (*model.Config, error) {
@ -105,5 +105,7 @@ func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResol
// Query returns generated.QueryResolver implementation. // Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type mutationResolver struct{ *Resolver } type (
type queryResolver struct{ *Resolver } mutationResolver struct{ *Resolver }
queryResolver struct{ *Resolver }
)

View File

@ -7,15 +7,19 @@ import (
"strings" "strings"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// State is the struct that holds authorizer url and redirect url
// They are provided via query string in the request
type State struct { type State struct {
AuthorizerURL string `json:"authorizerURL"` AuthorizerURL string `json:"authorizerURL"`
RedirectURL string `json:"redirectURL"` RedirectURL string `json:"redirectURL"`
} }
// AppHandler is the handler for the /app route
func AppHandler() gin.HandlerFunc { func AppHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
state := c.Query("state") state := c.Query("state")
@ -23,14 +27,8 @@ func AppHandler() gin.HandlerFunc {
var stateObj State var stateObj State
if state == "" { if state == "" {
// cookie, err := utils.GetAuthToken(c) stateObj.AuthorizerURL = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string)
// if err != nil { stateObj.RedirectURL = stateObj.AuthorizerURL + "/app"
// c.JSON(400, gin.H{"error": "invalid state"})
// return
// }
stateObj.AuthorizerURL = constants.EnvData.AUTHORIZER_URL
stateObj.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/app"
} else { } else {
decodedState, err := utils.DecryptB64(state) decodedState, err := utils.DecryptB64(state)
@ -59,7 +57,7 @@ func AppHandler() gin.HandlerFunc {
} }
// validate host and domain of authorizer url // validate host and domain of authorizer url
if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != constants.EnvData.AUTHORIZER_URL { if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) {
c.JSON(400, gin.H{"error": "invalid host url"}) c.JSON(400, gin.H{"error": "invalid host url"})
return return
} }
@ -76,8 +74,8 @@ func AppHandler() gin.HandlerFunc {
"data": map[string]string{ "data": map[string]string{
"authorizerURL": stateObj.AuthorizerURL, "authorizerURL": stateObj.AuthorizerURL,
"redirectURL": stateObj.RedirectURL, "redirectURL": stateObj.RedirectURL,
"organizationName": constants.EnvData.ORGANIZATION_NAME, "organizationName": envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationName).(string),
"organizationLogo": constants.EnvData.ORGANIZATION_LOGO, "organizationLogo": envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyOrganizationLogo).(string),
}, },
}) })
} }

View File

@ -4,14 +4,16 @@ import (
"net/http" "net/http"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// DashboardHandler is the handler for the /dashboard route
func DashboardHandler() gin.HandlerFunc { func DashboardHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
isOnboardingCompleted := false isOnboardingCompleted := false
if constants.EnvData.ADMIN_SECRET != "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret) != nil && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string) != "" {
isOnboardingCompleted = true isOnboardingCompleted = true
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// Defining the Graphql handler // GraphqlHandler is the main handler that handels all the graphql requests
func GraphqlHandler() gin.HandlerFunc { func GraphqlHandler() gin.HandlerFunc {
// NewExecutableSchema and Config are in the generated.go file // NewExecutableSchema and Config are in the generated.go file
// Resolver is in the resolver.go file // Resolver is in the resolver.go file

View File

@ -12,7 +12,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
@ -21,6 +21,131 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// OAuthCallbackHandler handles the OAuth callback for various oauth providers
func OAuthCallbackHandler() gin.HandlerFunc {
return func(c *gin.Context) {
provider := c.Param("oauth_provider")
state := c.Request.FormValue("state")
sessionState := session.GetSocailLoginState(state)
if sessionState == "" {
c.JSON(400, gin.H{"error": "invalid oauth state"})
}
session.RemoveSocialLoginState(state)
// contains random token, redirect url, role
sessionSplit := strings.Split(state, "___")
// TODO validate redirect url
if len(sessionSplit) < 2 {
c.JSON(400, gin.H{"error": "invalid redirect url"})
return
}
inputRoles := strings.Split(sessionSplit[2], ",")
redirectURL := sessionSplit[1]
var err error
user := db.User{}
code := c.Request.FormValue("code")
switch provider {
case constants.SignupMethodGoogle:
user, err = processGoogleUserInfo(code)
case constants.SignupMethodGithub:
user, err = processGithubUserInfo(code)
case constants.SignupMethodFacebook:
user, err = processFacebookUserInfo(code)
default:
err = fmt.Errorf(`invalid oauth provider`)
}
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
existingUser, err := db.Mgr.GetUserByEmail(user.Email)
if err != nil {
// user not registered, register user and generate session token
user.SignupMethods = provider
// make sure inputRoles don't include protected roles
hasProtectedRole := false
for _, ir := range inputRoles {
if utils.StringSliceContains(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyProtectedRoles).([]string), ir) {
hasProtectedRole = true
}
}
if hasProtectedRole {
c.JSON(400, gin.H{"error": "invalid role"})
return
}
user.Roles = strings.Join(inputRoles, ",")
now := time.Now().Unix()
user.EmailVerifiedAt = &now
user, _ = db.Mgr.AddUser(user)
} else {
// user exists in db, check if method was google
// if not append google to existing signup method and save it
signupMethod := existingUser.SignupMethods
if !strings.Contains(signupMethod, provider) {
signupMethod = signupMethod + "," + provider
}
user.SignupMethods = signupMethod
user.Password = existingUser.Password
// There multiple scenarios with roles here in social login
// 1. user has access to protected roles + roles and trying to login
// 2. user has not signed up for one of the available role but trying to signup.
// Need to modify roles in this case
// find the unassigned roles
existingRoles := strings.Split(existingUser.Roles, ",")
unasignedRoles := []string{}
for _, ir := range inputRoles {
if !utils.StringSliceContains(existingRoles, ir) {
unasignedRoles = append(unasignedRoles, ir)
}
}
if len(unasignedRoles) > 0 {
// check if it contains protected unassigned role
hasProtectedRole := false
for _, ur := range unasignedRoles {
if utils.StringSliceContains(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyProtectedRoles).([]string), ur) {
hasProtectedRole = true
}
}
if hasProtectedRole {
c.JSON(400, gin.H{"error": "invalid role"})
return
} else {
user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",")
}
} else {
user.Roles = existingUser.Roles
}
user.Key = existingUser.Key
user.ID = existingUser.ID
user, err = db.Mgr.UpdateUser(user)
}
user, _ = db.Mgr.GetUserByEmail(user.Email)
userIdStr := fmt.Sprintf("%v", user.ID)
refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, inputRoles)
accessToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeAccessToken, inputRoles)
utils.SetCookie(c, accessToken)
session.SetUserSession(userIdStr, accessToken, refreshToken)
utils.SaveSessionInDB(user.ID, c)
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
}
}
func processGoogleUserInfo(code string) (db.User, error) { func processGoogleUserInfo(code string) (db.User, error) {
user := db.User{} user := db.User{}
ctx := context.Background() ctx := context.Background()
@ -145,127 +270,3 @@ func processFacebookUserInfo(code string) (db.User, error) {
return user, nil return user, nil
} }
func OAuthCallbackHandler() gin.HandlerFunc {
return func(c *gin.Context) {
provider := c.Param("oauth_provider")
state := c.Request.FormValue("state")
sessionState := session.GetSocailLoginState(state)
if sessionState == "" {
c.JSON(400, gin.H{"error": "invalid oauth state"})
}
session.RemoveSocialLoginState(state)
// contains random token, redirect url, role
sessionSplit := strings.Split(state, "___")
// TODO validate redirect url
if len(sessionSplit) < 2 {
c.JSON(400, gin.H{"error": "invalid redirect url"})
return
}
inputRoles := strings.Split(sessionSplit[2], ",")
redirectURL := sessionSplit[1]
var err error
user := db.User{}
code := c.Request.FormValue("code")
switch provider {
case enum.Google.String():
user, err = processGoogleUserInfo(code)
case enum.Github.String():
user, err = processGithubUserInfo(code)
case enum.Facebook.String():
user, err = processFacebookUserInfo(code)
default:
err = fmt.Errorf(`invalid oauth provider`)
}
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
existingUser, err := db.Mgr.GetUserByEmail(user.Email)
if err != nil {
// user not registered, register user and generate session token
user.SignupMethods = provider
// make sure inputRoles don't include protected roles
hasProtectedRole := false
for _, ir := range inputRoles {
if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ir) {
hasProtectedRole = true
}
}
if hasProtectedRole {
c.JSON(400, gin.H{"error": "invalid role"})
return
}
user.Roles = strings.Join(inputRoles, ",")
now := time.Now().Unix()
user.EmailVerifiedAt = &now
user, _ = db.Mgr.AddUser(user)
} else {
// user exists in db, check if method was google
// if not append google to existing signup method and save it
signupMethod := existingUser.SignupMethods
if !strings.Contains(signupMethod, provider) {
signupMethod = signupMethod + "," + provider
}
user.SignupMethods = signupMethod
user.Password = existingUser.Password
// There multiple scenarios with roles here in social login
// 1. user has access to protected roles + roles and trying to login
// 2. user has not signed up for one of the available role but trying to signup.
// Need to modify roles in this case
// find the unassigned roles
existingRoles := strings.Split(existingUser.Roles, ",")
unasignedRoles := []string{}
for _, ir := range inputRoles {
if !utils.StringSliceContains(existingRoles, ir) {
unasignedRoles = append(unasignedRoles, ir)
}
}
if len(unasignedRoles) > 0 {
// check if it contains protected unassigned role
hasProtectedRole := false
for _, ur := range unasignedRoles {
if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) {
hasProtectedRole = true
}
}
if hasProtectedRole {
c.JSON(400, gin.H{"error": "invalid role"})
return
} else {
user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",")
}
} else {
user.Roles = existingUser.Roles
}
user.Key = existingUser.Key
user.ID = existingUser.ID
user, err = db.Mgr.UpdateUser(user)
}
user, _ = db.Mgr.GetUserByEmail(user.Email)
userIdStr := fmt.Sprintf("%v", user.ID)
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, inputRoles)
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, inputRoles)
utils.SetCookie(c, accessToken)
session.SetToken(userIdStr, accessToken, refreshToken)
utils.CreateSession(user.ID, c)
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
}
}

View File

@ -5,7 +5,7 @@ import (
"strings" "strings"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
@ -13,8 +13,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
// set host in the oauth state that is useful for redirecting // OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback
func OAuthLoginHandler() gin.HandlerFunc { func OAuthLoginHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
// TODO validate redirect URL // TODO validate redirect URL
@ -34,14 +33,14 @@ func OAuthLoginHandler() gin.HandlerFunc {
// use protected roles verification for admin login only. // use protected roles verification for admin login only.
// though if not associated with user, it will be rejected from oauth_callback // though if not associated with user, it will be rejected from oauth_callback
if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), rolesSplit) { if !utils.IsValidRoles(append([]string{}, append(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRoles).([]string), envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyProtectedRoles).([]string)...)...), rolesSplit) {
c.JSON(400, gin.H{ c.JSON(400, gin.H{
"error": "invalid role", "error": "invalid role",
}) })
return return
} }
} else { } else {
roles = strings.Join(constants.EnvData.DEFAULT_ROLES, ",") roles = strings.Join(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDefaultRoles).([]string), ",")
} }
uuid := uuid.New() uuid := uuid.New()
@ -50,32 +49,32 @@ func OAuthLoginHandler() gin.HandlerFunc {
provider := c.Param("oauth_provider") provider := c.Param("oauth_provider")
isProviderConfigured := true isProviderConfigured := true
switch provider { switch provider {
case enum.Google.String(): case constants.SignupMethodGoogle:
if oauth.OAuthProviders.GoogleConfig == nil { if oauth.OAuthProviders.GoogleConfig == nil {
isProviderConfigured = false isProviderConfigured = false
break break
} }
session.SetSocailLoginState(oauthStateString, enum.Google.String()) session.SetSocailLoginState(oauthStateString, constants.SignupMethodGoogle)
// during the init of OAuthProvider authorizer url might be empty // during the init of OAuthProvider authorizer url might be empty
oauth.OAuthProviders.GoogleConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google" oauth.OAuthProviders.GoogleConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/google"
url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString) url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url) c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Github.String(): case constants.SignupMethodGithub:
if oauth.OAuthProviders.GithubConfig == nil { if oauth.OAuthProviders.GithubConfig == nil {
isProviderConfigured = false isProviderConfigured = false
break break
} }
session.SetSocailLoginState(oauthStateString, enum.Github.String()) session.SetSocailLoginState(oauthStateString, constants.SignupMethodGithub)
oauth.OAuthProviders.GithubConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github" oauth.OAuthProviders.GithubConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/github"
url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString) url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url) c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Facebook.String(): case constants.SignupMethodFacebook:
if oauth.OAuthProviders.FacebookConfig == nil { if oauth.OAuthProviders.FacebookConfig == nil {
isProviderConfigured = false isProviderConfigured = false
break break
} }
session.SetSocailLoginState(oauthStateString, enum.Facebook.String()) session.SetSocailLoginState(oauthStateString, constants.SignupMethodFacebook)
oauth.OAuthProviders.FacebookConfig.RedirectURL = constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook" oauth.OAuthProviders.FacebookConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/facebook"
url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url) c.Redirect(http.StatusTemporaryRedirect, url)
default: default:

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// PlaygroundHandler is the handler for the /playground route
func PlaygroundHandler() gin.HandlerFunc { func PlaygroundHandler() gin.HandlerFunc {
h := playground.Handler("GraphQL", "/graphql") h := playground.Handler("GraphQL", "/graphql")

14
server/handlers/root.go Normal file
View File

@ -0,0 +1,14 @@
package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
)
// RootHandler is the handler for / root route.
func RootHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, "/dashboard")
}
}

View File

@ -5,13 +5,15 @@ import (
"strings" "strings"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// VerifyEmailHandler handles the verify email route.
// It verifies email based on JWT token in query string
func VerifyEmailHandler() gin.HandlerFunc { func VerifyEmailHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
errorRes := gin.H{ errorRes := gin.H{
@ -54,12 +56,12 @@ func VerifyEmailHandler() gin.HandlerFunc {
db.Mgr.DeleteVerificationRequest(verificationRequest) db.Mgr.DeleteVerificationRequest(verificationRequest)
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles) refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles)
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, roles) accessToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeAccessToken, roles)
session.SetToken(user.ID, accessToken, refreshToken) session.SetUserSession(user.ID, accessToken, refreshToken)
utils.CreateSession(user.ID, c) utils.SaveSessionInDB(user.ID, c)
utils.SetCookie(c, accessToken) utils.SetCookie(c, accessToken)
c.Redirect(http.StatusTemporaryRedirect, claim.RedirectURL) c.Redirect(http.StatusTemporaryRedirect, claim.RedirectURL)
} }

View File

@ -6,11 +6,10 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/env" "github.com/authorizerdev/authorizer/server/env"
"github.com/authorizerdev/authorizer/server/handlers" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/router" "github.com/authorizerdev/authorizer/server/routes"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils"
) )
var VERSION string var VERSION string
@ -18,11 +17,10 @@ var VERSION string
func main() { func main() {
env.ARG_DB_URL = flag.String("database_url", "", "Database connection string") env.ARG_DB_URL = flag.String("database_url", "", "Database connection string")
env.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") env.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite")
env.ARG_AUTHORIZER_URL = flag.String("authorizer_url", "", "URL for authorizer instance, eg: https://xyz.herokuapp.com")
env.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") env.ARG_ENV_FILE = flag.String("env_file", "", "Env file path")
flag.Parse() flag.Parse()
constants.EnvData.VERSION = VERSION envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyVersion, VERSION)
env.InitEnv() env.InitEnv()
db.InitDB() db.InitDB()
@ -30,27 +28,8 @@ func main() {
session.InitSession() session.InitSession()
oauth.InitOAuth() oauth.InitOAuth()
utils.InitServer()
router := router.InitRouter() router := routes.InitRouter()
router.LoadHTMLGlob("templates/*") router.Run(":" + envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyPort).(string))
// 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.EnvData.DISABLE_LOGIN_PAGE {
app := router.Group("/app")
{
app.Static("/build", "app/build")
app.GET("/", handlers.AppHandler())
app.GET("/reset-password", handlers.AppHandler())
}
}
app := router.Group("/dashboard")
{
app.Static("/build", "dashboard/build")
app.GET("/", handlers.DashboardHandler())
}
router.Run(":" + constants.EnvData.PORT)
} }

View File

@ -2,19 +2,19 @@ package middlewares
import ( import (
"context" "context"
"log"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/gin-contrib/location" "github.com/gin-contrib/location"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// GinContextToContextMiddleware is a middleware to add gin context in context
func GinContextToContextMiddleware() gin.HandlerFunc { func GinContextToContextMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
if constants.EnvData.AUTHORIZER_URL == "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) == "" {
url := location.Get(c) url := location.Get(c)
constants.EnvData.AUTHORIZER_URL = url.Scheme + "://" + c.Request.Host envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyAuthorizerURL, url.Scheme+"://"+c.Request.Host)
log.Println("authorizer url:", constants.EnvData.AUTHORIZER_URL)
} }
ctx := context.WithValue(c.Request.Context(), "GinContextKey", c) ctx := context.WithValue(c.Request.Context(), "GinContextKey", c)
c.Request = c.Request.WithContext(ctx) c.Request = c.Request.WithContext(ctx)

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// CORSMiddleware is a middleware to add cors headers
func CORSMiddleware() gin.HandlerFunc { func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin") origin := c.Request.Header.Get("Origin")

View File

@ -5,56 +5,62 @@ import (
"log" "log"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2" "golang.org/x/oauth2"
facebookOAuth2 "golang.org/x/oauth2/facebook" facebookOAuth2 "golang.org/x/oauth2/facebook"
githubOAuth2 "golang.org/x/oauth2/github" githubOAuth2 "golang.org/x/oauth2/github"
) )
// OAuthProviders is a struct that contains reference all the OAuth providers
type OAuthProvider struct { type OAuthProvider struct {
GoogleConfig *oauth2.Config GoogleConfig *oauth2.Config
GithubConfig *oauth2.Config GithubConfig *oauth2.Config
FacebookConfig *oauth2.Config FacebookConfig *oauth2.Config
} }
// OIDCProviders is a struct that contains reference all the OpenID providers
type OIDCProvider struct { type OIDCProvider struct {
GoogleOIDC *oidc.Provider GoogleOIDC *oidc.Provider
} }
var ( var (
// OAuthProviders is a global variable that contains instance for all enabled the OAuth providers
OAuthProviders OAuthProvider OAuthProviders OAuthProvider
// OIDCProviders is a global variable that contains instance for all enabled the OpenID providers
OIDCProviders OIDCProvider OIDCProviders OIDCProvider
) )
// InitOAuth initializes the OAuth providers based on EnvData
func InitOAuth() { func InitOAuth() {
ctx := context.Background() ctx := context.Background()
if constants.EnvData.GOOGLE_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientSecret).(string) != "" {
p, err := oidc.NewProvider(ctx, "https://accounts.google.com") p, err := oidc.NewProvider(ctx, "https://accounts.google.com")
if err != nil { if err != nil {
log.Fatalln("error creating oidc provider for google:", err) log.Fatalln("error creating oidc provider for google:", err)
} }
OIDCProviders.GoogleOIDC = p OIDCProviders.GoogleOIDC = p
OAuthProviders.GoogleConfig = &oauth2.Config{ OAuthProviders.GoogleConfig = &oauth2.Config{
ClientID: constants.EnvData.GOOGLE_CLIENT_ID, ClientID: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientID).(string),
ClientSecret: constants.EnvData.GOOGLE_CLIENT_SECRET, ClientSecret: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientSecret).(string),
RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/google", RedirectURL: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/google",
Endpoint: OIDCProviders.GoogleOIDC.Endpoint(), Endpoint: OIDCProviders.GoogleOIDC.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
} }
} }
if constants.EnvData.GITHUB_CLIENT_ID != "" && constants.EnvData.GITHUB_CLIENT_SECRET != "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientSecret).(string) != "" {
OAuthProviders.GithubConfig = &oauth2.Config{ OAuthProviders.GithubConfig = &oauth2.Config{
ClientID: constants.EnvData.GITHUB_CLIENT_ID, ClientID: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientID).(string),
ClientSecret: constants.EnvData.GITHUB_CLIENT_SECRET, ClientSecret: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGithubClientSecret).(string),
RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/github", RedirectURL: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/github",
Endpoint: githubOAuth2.Endpoint, Endpoint: githubOAuth2.Endpoint,
} }
} }
if constants.EnvData.FACEBOOK_CLIENT_ID != "" && constants.EnvData.FACEBOOK_CLIENT_SECRET != "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyFacebookClientID).(string) != "" && envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyGoogleClientID).(string) != "" {
OAuthProviders.FacebookConfig = &oauth2.Config{ OAuthProviders.FacebookConfig = &oauth2.Config{
ClientID: constants.EnvData.FACEBOOK_CLIENT_ID, ClientID: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyFacebookClientID).(string),
ClientSecret: constants.EnvData.FACEBOOK_CLIENT_SECRET, ClientSecret: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyFacebookClientSecret).(string),
RedirectURL: constants.EnvData.AUTHORIZER_URL + "/oauth_callback/facebook", RedirectURL: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAuthorizerURL).(string) + "/oauth_callback/facebook",
Endpoint: facebookOAuth2.Endpoint, Endpoint: facebookOAuth2.Endpoint,
Scopes: []string{"public_profile", "email"}, Scopes: []string{"public_profile", "email"},
} }

View File

@ -5,10 +5,12 @@ import (
"fmt" "fmt"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
// AdminLoginResolver is a resolver for admin login mutation
func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) { func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
@ -17,11 +19,12 @@ func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*mod
return res, err return res, err
} }
if params.AdminSecret != constants.EnvData.ADMIN_SECRET { adminSecret := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string)
if params.AdminSecret != adminSecret {
return res, fmt.Errorf(`invalid admin secret`) return res, fmt.Errorf(`invalid admin secret`)
} }
hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) hashedKey, err := utils.EncryptPassword(adminSecret)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -8,7 +8,8 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func AdminLogout(ctx context.Context) (*model.Response, error) { // AdminLogoutResolver is a resolver for admin logout mutation
func AdminLogoutResolver(ctx context.Context) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response

View File

@ -5,11 +5,13 @@ import (
"fmt" "fmt"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func AdminSession(ctx context.Context) (*model.Response, error) { // AdminSessionResolver is a resolver for admin session query
func AdminSessionResolver(ctx context.Context) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
@ -21,7 +23,7 @@ func AdminSession(ctx context.Context) (*model.Response, error) {
return res, fmt.Errorf("unauthorized") return res, fmt.Errorf("unauthorized")
} }
hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) hashedKey, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -8,10 +8,12 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
// AdminSignupResolver is a resolver for admin signup mutation
func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) { func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
@ -30,17 +32,18 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m
return res, err return res, err
} }
if constants.EnvData.ADMIN_SECRET != "" { adminSecret := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string)
if adminSecret != "" {
err = fmt.Errorf("admin sign up already completed") err = fmt.Errorf("admin sign up already completed")
return res, err return res, err
} }
constants.EnvData.ADMIN_SECRET = params.AdminSecret envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyAdminSecret, params.AdminSecret)
// consvert EnvData to JSON // consvert EnvData to JSON
var jsonData map[string]interface{} var jsonData map[string]interface{}
jsonBytes, err := json.Marshal(constants.EnvData) jsonBytes, err := json.Marshal(envstore.EnvInMemoryStoreObj.GetEnvStoreClone())
if err != nil { if err != nil {
return res, err return res, err
} }
@ -54,7 +57,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m
return res, err return res, err
} }
configData, err := utils.EncryptConfig(jsonData) configData, err := utils.EncryptEnvData(jsonData)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -64,7 +67,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m
return res, err return res, err
} }
hashedKey, err := utils.HashPassword(params.AdminSecret) hashedKey, err := utils.EncryptPassword(params.AdminSecret)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -5,10 +5,15 @@ import (
"fmt" "fmt"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
// TODO rename to env_data
// ConfigResolver is a resolver for config query
// This is admin only query
func ConfigResolver(ctx context.Context) (*model.Config, error) { func ConfigResolver(ctx context.Context) (*model.Config, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Config var res *model.Config
@ -21,40 +26,76 @@ func ConfigResolver(ctx context.Context) (*model.Config, error) {
return res, fmt.Errorf("unauthorized") return res, fmt.Errorf("unauthorized")
} }
// get clone of store
store := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
adminSecret := store[constants.EnvKeyAdminSecret].(string)
databaseType := store[constants.EnvKeyDatabaseType].(string)
databaseURL := store[constants.EnvKeyDatabaseURL].(string)
databaseName := store[constants.EnvKeyDatabaseName].(string)
smtpHost := store[constants.EnvKeySmtpHost].(string)
smtpPort := store[constants.EnvKeySmtpPort].(string)
smtpUsername := store[constants.EnvKeySmtpUsername].(string)
smtpPassword := store[constants.EnvKeySmtpPassword].(string)
senderEmail := store[constants.EnvKeySenderEmail].(string)
jwtType := store[constants.EnvKeyJwtType].(string)
jwtSecret := store[constants.EnvKeyJwtSecret].(string)
jwtRoleClaim := store[constants.EnvKeyJwtRoleClaim].(string)
allowedOrigins := store[constants.EnvKeyAllowedOrigins].([]string)
authorizerURL := store[constants.EnvKeyAuthorizerURL].(string)
appURL := store[constants.EnvKeyAppURL].(string)
redisURL := store[constants.EnvKeyRedisURL].(string)
cookieName := store[constants.EnvKeyCookieName].(string)
resetPasswordURL := store[constants.EnvKeyResetPasswordURL].(string)
disableEmailVerification := store[constants.EnvKeyDisableEmailVerification].(bool)
disableBasicAuthentication := store[constants.EnvKeyDisableBasicAuthentication].(bool)
disableMagicLinkLogin := store[constants.EnvKeyDisableMagicLinkLogin].(bool)
disableLoginPage := store[constants.EnvKeyDisableLoginPage].(bool)
roles := store[constants.EnvKeyRoles].([]string)
defaultRoles := store[constants.EnvKeyDefaultRoles].([]string)
protectedRoles := store[constants.EnvKeyProtectedRoles].([]string)
googleClientID := store[constants.EnvKeyGoogleClientID].(string)
googleClientSecret := store[constants.EnvKeyGoogleClientSecret].(string)
facebookClientID := store[constants.EnvKeyFacebookClientID].(string)
facebookClientSecret := store[constants.EnvKeyFacebookClientSecret].(string)
githubClientID := store[constants.EnvKeyGithubClientID].(string)
githubClientSecret := store[constants.EnvKeyGithubClientSecret].(string)
organizationName := store[constants.EnvKeyOrganizationName].(string)
organizationLogo := store[constants.EnvKeyOrganizationLogo].(string)
res = &model.Config{ res = &model.Config{
AdminSecret: &constants.EnvData.ADMIN_SECRET, AdminSecret: &adminSecret,
DatabaseType: &constants.EnvData.DATABASE_TYPE, DatabaseType: &databaseType,
DatabaseURL: &constants.EnvData.DATABASE_URL, DatabaseURL: &databaseURL,
DatabaseName: &constants.EnvData.DATABASE_NAME, DatabaseName: &databaseName,
SMTPHost: &constants.EnvData.SMTP_HOST, SMTPHost: &smtpHost,
SMTPPort: &constants.EnvData.SMTP_PORT, SMTPPort: &smtpPort,
SMTPPassword: &constants.EnvData.SMTP_PASSWORD, SMTPPassword: &smtpPassword,
SMTPUsername: &constants.EnvData.SMTP_USERNAME, SMTPUsername: &smtpUsername,
SenderEmail: &constants.EnvData.SENDER_EMAIL, SenderEmail: &senderEmail,
JwtType: &constants.EnvData.JWT_TYPE, JwtType: &jwtType,
JwtSecret: &constants.EnvData.JWT_SECRET, JwtSecret: &jwtSecret,
AllowedOrigins: constants.EnvData.ALLOWED_ORIGINS, JwtRoleClaim: &jwtRoleClaim,
AuthorizerURL: &constants.EnvData.AUTHORIZER_URL, AllowedOrigins: allowedOrigins,
AppURL: &constants.EnvData.APP_URL, AuthorizerURL: &authorizerURL,
RedisURL: &constants.EnvData.REDIS_URL, AppURL: &appURL,
CookieName: &constants.EnvData.COOKIE_NAME, RedisURL: &redisURL,
ResetPasswordURL: &constants.EnvData.RESET_PASSWORD_URL, CookieName: &cookieName,
DisableEmailVerification: &constants.EnvData.DISABLE_EMAIL_VERIFICATION, ResetPasswordURL: &resetPasswordURL,
DisableBasicAuthentication: &constants.EnvData.DISABLE_BASIC_AUTHENTICATION, DisableEmailVerification: &disableEmailVerification,
DisableMagicLinkLogin: &constants.EnvData.DISABLE_MAGIC_LINK_LOGIN, DisableBasicAuthentication: &disableBasicAuthentication,
DisableLoginPage: &constants.EnvData.DISABLE_LOGIN_PAGE, DisableMagicLinkLogin: &disableMagicLinkLogin,
Roles: constants.EnvData.ROLES, DisableLoginPage: &disableLoginPage,
ProtectedRoles: constants.EnvData.PROTECTED_ROLES, Roles: roles,
DefaultRoles: constants.EnvData.DEFAULT_ROLES, ProtectedRoles: protectedRoles,
JwtRoleClaim: &constants.EnvData.JWT_ROLE_CLAIM, DefaultRoles: defaultRoles,
GoogleClientID: &constants.EnvData.GOOGLE_CLIENT_ID, GoogleClientID: &googleClientID,
GoogleClientSecret: &constants.EnvData.GOOGLE_CLIENT_SECRET, GoogleClientSecret: &googleClientSecret,
GithubClientID: &constants.EnvData.GITHUB_CLIENT_ID, GithubClientID: &githubClientID,
GithubClientSecret: &constants.EnvData.GITHUB_CLIENT_SECRET, GithubClientSecret: &githubClientSecret,
FacebookClientID: &constants.EnvData.FACEBOOK_CLIENT_ID, FacebookClientID: &facebookClientID,
FacebookClientSecret: &constants.EnvData.FACEBOOK_CLIENT_SECRET, FacebookClientSecret: &facebookClientSecret,
OrganizationName: &constants.EnvData.ORGANIZATION_NAME, OrganizationName: &organizationName,
OrganizationLogo: &constants.EnvData.ORGANIZATION_LOGO, OrganizationLogo: &organizationLogo,
} }
return res, nil return res, nil
} }

View File

@ -11,7 +11,8 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { // DeleteUserResolver is a resolver for delete user mutation
func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
if err != nil { if err != nil {
@ -27,7 +28,7 @@ func DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Respo
return res, err return res, err
} }
session.DeleteUserSession(fmt.Sprintf("%x", user.ID)) session.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
err = db.Mgr.DeleteUser(user) err = db.Mgr.DeleteUser(user)
if err != nil { if err != nil {

View File

@ -9,18 +9,20 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) { // ForgotPasswordResolver is a resolver for forgot password mutation
func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
if err != nil { if err != nil {
return res, err return res, err
} }
if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableBasicAuthentication).(bool) {
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
host := gc.Request.Host host := gc.Request.Host
@ -35,20 +37,20 @@ func ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*mod
return res, fmt.Errorf(`user with this email not found`) return res, fmt.Errorf(`user with this email not found`)
} }
token, err := utils.CreateVerificationToken(params.Email, enum.ForgotPassword.String()) token, err := utils.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword)
if err != nil { if err != nil {
log.Println(`error generating token`, err) log.Println(`error generating token`, err)
} }
db.Mgr.AddVerification(db.VerificationRequest{ db.Mgr.AddVerification(db.VerificationRequest{
Token: token, Token: token,
Identifier: enum.ForgotPassword.String(), Identifier: constants.VerificationTypeForgotPassword,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
Email: params.Email, Email: params.Email,
}) })
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendForgotPasswordMail(params.Email, token, host) email.SendForgotPasswordMail(params.Email, token, host)
}() }()
res = &model.Response{ res = &model.Response{

View File

@ -8,21 +8,22 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { // LoginResolver is a resolver for login mutation
func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.AuthResponse var res *model.AuthResponse
if err != nil { if err != nil {
return res, err return res, err
} }
if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableBasicAuthentication).(bool) {
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
@ -32,7 +33,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
return res, fmt.Errorf(`user with this email not found`) return res, fmt.Errorf(`user with this email not found`)
} }
if !strings.Contains(user.SignupMethods, enum.BasicAuth.String()) { if !strings.Contains(user.SignupMethods, constants.SignupMethodBasicAuth) {
return res, fmt.Errorf(`user has not signed up email & password`) return res, fmt.Errorf(`user has not signed up email & password`)
} }
@ -46,7 +47,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
log.Println("compare password error:", err) log.Println("compare password error:", err)
return res, fmt.Errorf(`invalid password`) return res, fmt.Errorf(`invalid password`)
} }
roles := constants.EnvData.DEFAULT_ROLES roles := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDefaultRoles).([]string)
currentRoles := strings.Split(user.Roles, ",") currentRoles := strings.Split(user.Roles, ",")
if len(params.Roles) > 0 { if len(params.Roles) > 0 {
if !utils.IsValidRoles(currentRoles, params.Roles) { if !utils.IsValidRoles(currentRoles, params.Roles) {
@ -55,12 +56,12 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
roles = params.Roles roles = params.Roles
} }
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles) refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles)
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles) accessToken, expiresAt, _ := utils.CreateAuthToken(user, constants.TokenTypeAccessToken, roles)
session.SetToken(user.ID, accessToken, refreshToken) session.SetUserSession(user.ID, accessToken, refreshToken)
utils.CreateSession(user.ID, gc) utils.SaveSessionInDB(user.ID, gc)
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Logged in successfully`, Message: `Logged in successfully`,

View File

@ -9,7 +9,8 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Logout(ctx context.Context) (*model.Response, error) { // LogoutResolver is a resolver for logout mutation
func LogoutResolver(ctx context.Context) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
if err != nil { if err != nil {
@ -27,7 +28,7 @@ func Logout(ctx context.Context) (*model.Response, error) {
} }
userId := fmt.Sprintf("%v", claim["id"]) userId := fmt.Sprintf("%v", claim["id"])
session.DeleteVerificationRequest(userId, token) session.DeleteUserSession(userId, token)
res = &model.Response{ res = &model.Response{
Message: "Logged out successfully", Message: "Logged out successfully",
} }

View File

@ -9,15 +9,17 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { // MagicLinkLoginResolver is a resolver for magic link login mutation
func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
var res *model.Response var res *model.Response
if constants.EnvData.DISABLE_MAGIC_LINK_LOGIN { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableMagicLinkLogin).(bool) {
return res, fmt.Errorf(`magic link login is disabled for this instance`) return res, fmt.Errorf(`magic link login is disabled for this instance`)
} }
@ -37,17 +39,17 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
existingUser, err := db.Mgr.GetUserByEmail(params.Email) existingUser, err := db.Mgr.GetUserByEmail(params.Email)
if err != nil { if err != nil {
user.SignupMethods = enum.MagicLinkLogin.String() user.SignupMethods = constants.SignupMethodMagicLinkLogin
// define roles for new user // define roles for new user
if len(params.Roles) > 0 { if len(params.Roles) > 0 {
// check if roles exists // check if roles exists
if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) { if !utils.IsValidRoles(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRoles).([]string), params.Roles) {
return res, fmt.Errorf(`invalid roles`) return res, fmt.Errorf(`invalid roles`)
} else { } else {
inputRoles = params.Roles inputRoles = params.Roles
} }
} else { } else {
inputRoles = constants.EnvData.DEFAULT_ROLES inputRoles = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDefaultRoles).([]string)
} }
user.Roles = strings.Join(inputRoles, ",") user.Roles = strings.Join(inputRoles, ",")
@ -72,7 +74,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
// check if it contains protected unassigned role // check if it contains protected unassigned role
hasProtectedRole := false hasProtectedRole := false
for _, ur := range unasignedRoles { for _, ur := range unasignedRoles {
if utils.StringSliceContains(constants.EnvData.PROTECTED_ROLES, ur) { if utils.StringSliceContains(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyProtectedRoles).([]string), ur) {
hasProtectedRole = true hasProtectedRole = true
} }
} }
@ -87,8 +89,8 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
} }
signupMethod := existingUser.SignupMethods signupMethod := existingUser.SignupMethods
if !strings.Contains(signupMethod, enum.MagicLinkLogin.String()) { if !strings.Contains(signupMethod, constants.SignupMethodMagicLinkLogin) {
signupMethod = signupMethod + "," + enum.MagicLinkLogin.String() signupMethod = signupMethod + "," + constants.SignupMethodMagicLinkLogin
} }
user.SignupMethods = signupMethod user.SignupMethods = signupMethod
@ -98,9 +100,9 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
} }
} }
if !constants.EnvData.DISABLE_EMAIL_VERIFICATION { if !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableEmailVerification).(bool) {
// insert verification request // insert verification request
verificationType := enum.MagicLinkLogin.String() verificationType := constants.VerificationTypeMagicLinkLogin
token, err := utils.CreateVerificationToken(params.Email, verificationType) token, err := utils.CreateVerificationToken(params.Email, verificationType)
if err != nil { if err != nil {
log.Println(`error generating token`, err) log.Println(`error generating token`, err)
@ -114,7 +116,7 @@ func MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*mod
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendVerificationMail(params.Email, token) email.SendVerificationMail(params.Email, token)
}() }()
} }

View File

@ -7,7 +7,8 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Meta(ctx context.Context) (*model.Meta, error) { // MetaResolver is a resolver for meta query
func MetaResolver(ctx context.Context) (*model.Meta, error) {
metaInfo := utils.GetMetaInfo() metaInfo := utils.GetMetaInfo()
return &metaInfo, nil return &metaInfo, nil
} }

View File

@ -10,7 +10,8 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Profile(ctx context.Context) (*model.User, error) { // ProfileResolver is a resolver for profile query
func ProfileResolver(ctx context.Context) (*model.User, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.User var res *model.User
if err != nil { if err != nil {
@ -29,7 +30,7 @@ func Profile(ctx context.Context) (*model.User, error) {
userID := fmt.Sprintf("%v", claim["id"]) userID := fmt.Sprintf("%v", claim["id"])
email := fmt.Sprintf("%v", claim["email"]) email := fmt.Sprintf("%v", claim["email"])
sessionToken := session.GetToken(userID, token) sessionToken := session.GetUserSession(userID, token)
if sessionToken == "" { if sessionToken == "" {
return res, fmt.Errorf(`unauthorized`) return res, fmt.Errorf(`unauthorized`)

View File

@ -8,11 +8,13 @@ import (
"time" "time"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { // ResendVerifyEmailResolver is a resolver for resend verify email mutation
func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) {
var res *model.Response var res *model.Response
params.Email = strings.ToLower(params.Email) params.Email = strings.ToLower(params.Email)
@ -48,7 +50,7 @@ func ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput)
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendVerificationMail(params.Email, token) email.SendVerificationMail(params.Email, token)
}() }()
res = &model.Response{ res = &model.Response{

View File

@ -8,14 +8,15 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { // ResetPasswordResolver is a resolver for reset password mutation
func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) {
var res *model.Response var res *model.Response
if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableBasicAuthentication).(bool) {
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
@ -39,12 +40,12 @@ func ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model
return res, err return res, err
} }
password, _ := utils.HashPassword(params.Password) password, _ := utils.EncryptPassword(params.Password)
user.Password = &password user.Password = &password
signupMethod := user.SignupMethods signupMethod := user.SignupMethods
if !strings.Contains(signupMethod, enum.BasicAuth.String()) { if !strings.Contains(signupMethod, constants.SignupMethodBasicAuth) {
signupMethod = signupMethod + "," + enum.BasicAuth.String() signupMethod = signupMethod + "," + constants.SignupMethodBasicAuth
} }
user.SignupMethods = signupMethod user.SignupMethods = signupMethod

View File

@ -7,13 +7,14 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) { // SessionResolver is a resolver for session query
func SessionResolver(ctx context.Context, roles []string) (*model.AuthResponse, error) {
var res *model.AuthResponse var res *model.AuthResponse
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
@ -36,7 +37,7 @@ func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
userIdStr := fmt.Sprintf("%v", user.ID) userIdStr := fmt.Sprintf("%v", user.ID)
sessionToken := session.GetToken(userIdStr, token) sessionToken := session.GetUserSession(userIdStr, token)
if sessionToken == "" { if sessionToken == "" {
return res, fmt.Errorf(`unauthorized`) return res, fmt.Errorf(`unauthorized`)
@ -45,7 +46,7 @@ func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
expiresTimeObj := time.Unix(expiresAt, 0) expiresTimeObj := time.Unix(expiresAt, 0)
currentTimeObj := time.Now() currentTimeObj := time.Now()
claimRoleInterface := claim[constants.EnvData.JWT_ROLE_CLAIM].([]interface{}) claimRoleInterface := claim[envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyJwtRoleClaim).(string)].([]interface{})
claimRoles := make([]string, len(claimRoleInterface)) claimRoles := make([]string, len(claimRoleInterface))
for i, v := range claimRoleInterface { for i, v := range claimRoleInterface {
claimRoles[i] = v.(string) claimRoles[i] = v.(string)
@ -59,14 +60,15 @@ func Session(ctx context.Context, roles []string) (*model.AuthResponse, error) {
} }
} }
// TODO change this logic to make it more secure
if accessTokenErr != nil || expiresTimeObj.Sub(currentTimeObj).Minutes() <= 5 { if accessTokenErr != nil || expiresTimeObj.Sub(currentTimeObj).Minutes() <= 5 {
// if access token has expired and refresh/session token is valid // if access token has expired and refresh/session token is valid
// generate new accessToken // generate new accessToken
currentRefreshToken := session.GetToken(userIdStr, token) currentRefreshToken := session.GetUserSession(userIdStr, token)
session.DeleteVerificationRequest(userIdStr, token) session.DeleteUserSession(userIdStr, token)
token, expiresAt, _ = utils.CreateAuthToken(user, enum.AccessToken, claimRoles) token, expiresAt, _ = utils.CreateAuthToken(user, constants.TokenTypeAccessToken, claimRoles)
session.SetToken(userIdStr, token, currentRefreshToken) session.SetUserSession(userIdStr, token, currentRefreshToken)
utils.CreateSession(user.ID, gc) utils.SaveSessionInDB(user.ID, gc)
} }
utils.SetCookie(gc, token) utils.SetCookie(gc, token)

View File

@ -9,20 +9,23 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { // SignupResolver is a resolver for signup mutation
func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) {
log.Println(envstore.EnvInMemoryStoreObj.GetEnvStoreClone())
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.AuthResponse var res *model.AuthResponse
if err != nil { if err != nil {
return res, err return res, err
} }
if constants.EnvData.DISABLE_BASIC_AUTHENTICATION { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableBasicAuthentication).(bool) {
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
if params.ConfirmPassword != params.Password { if params.ConfirmPassword != params.Password {
@ -52,13 +55,13 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
if len(params.Roles) > 0 { if len(params.Roles) > 0 {
// check if roles exists // check if roles exists
if !utils.IsValidRoles(constants.EnvData.ROLES, params.Roles) { if !utils.IsValidRoles(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRoles).([]string), params.Roles) {
return res, fmt.Errorf(`invalid roles`) return res, fmt.Errorf(`invalid roles`)
} else { } else {
inputRoles = params.Roles inputRoles = params.Roles
} }
} else { } else {
inputRoles = constants.EnvData.DEFAULT_ROLES inputRoles = envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDefaultRoles).([]string)
} }
user := db.User{ user := db.User{
@ -67,7 +70,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
user.Roles = strings.Join(inputRoles, ",") user.Roles = strings.Join(inputRoles, ",")
password, _ := utils.HashPassword(params.Password) password, _ := utils.EncryptPassword(params.Password)
user.Password = &password user.Password = &password
if params.GivenName != nil { if params.GivenName != nil {
@ -102,8 +105,8 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
user.Picture = params.Picture user.Picture = params.Picture
} }
user.SignupMethods = enum.BasicAuth.String() user.SignupMethods = constants.SignupMethodBasicAuth
if constants.EnvData.DISABLE_EMAIL_VERIFICATION { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableEmailVerification).(bool) {
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
} }
@ -115,9 +118,9 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")
userToReturn := utils.GetResponseUserData(user) userToReturn := utils.GetResponseUserData(user)
if !constants.EnvData.DISABLE_EMAIL_VERIFICATION { if !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableEmailVerification).(bool) {
// insert verification request // insert verification request
verificationType := enum.BasicAuthSignup.String() verificationType := constants.VerificationTypeBasicAuthSignup
token, err := utils.CreateVerificationToken(params.Email, verificationType) token, err := utils.CreateVerificationToken(params.Email, verificationType)
if err != nil { if err != nil {
log.Println(`error generating token`, err) log.Println(`error generating token`, err)
@ -131,7 +134,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendVerificationMail(params.Email, token) email.SendVerificationMail(params.Email, token)
}() }()
res = &model.AuthResponse{ res = &model.AuthResponse{
@ -140,12 +143,12 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
} }
} else { } else {
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles) refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles)
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles) accessToken, expiresAt, _ := utils.CreateAuthToken(user, constants.TokenTypeAccessToken, roles)
session.SetToken(userIdStr, accessToken, refreshToken) session.SetUserSession(userIdStr, accessToken, refreshToken)
utils.CreateSession(user.ID, gc) utils.SaveSessionInDB(user.ID, gc)
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Signed up successfully.`, Message: `Signed up successfully.`,
AccessToken: &accessToken, AccessToken: &accessToken,

View File

@ -9,10 +9,15 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
// TODO rename to UpdateEnvDataResolver
// UpdateConfigResolver is a resolver for update config mutation
// This is admin only mutation
func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) { func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
@ -57,13 +62,13 @@ func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (
// handle derivative cases like disabling email verification & magic login // handle derivative cases like disabling email verification & magic login
// in case SMTP is off but env is set to true // in case SMTP is off but env is set to true
if updatedData["SMTP_HOST"] == "" || updatedData["SENDER_EMAIL"] == "" || updatedData["SENDER_PASSWORD"] == "" { if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySenderEmail] == "" || updatedData[constants.EnvKeySmtpPort] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" {
if !updatedData["DISABLE_EMAIL_VERIFICATION"].(bool) { if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
updatedData["DISABLE_EMAIL_VERIFICATION"] = true updatedData[constants.EnvKeyDisableEmailVerification] = true
} }
if !updatedData["DISABLE_MAGIC_LINK_LOGIN"].(bool) { if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
updatedData["DISABLE_MAGIC_LINK_LOGIN"] = true updatedData[constants.EnvKeyDisableMagicLinkLogin] = true
} }
} }
@ -72,7 +77,9 @@ func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (
return res, err return res, err
} }
encryptedConfig, err := utils.EncryptConfig(updatedData) envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData)
encryptedConfig, err := utils.EncryptEnvData(updatedData)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -84,7 +91,7 @@ func UpdateConfigResolver(ctx context.Context, params model.UpdateConfigInput) (
// in case of admin secret change update the cookie with new hash // in case of admin secret change update the cookie with new hash
if params.AdminSecret != nil { if params.AdminSecret != nil {
hashedKey, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) hashedKey, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -7,15 +7,17 @@ import (
"strings" "strings"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) { // UpdateProfileResolver is resolver for update profile mutation
func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.Response var res *model.Response
if err != nil { if err != nil {
@ -33,7 +35,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
} }
id := fmt.Sprintf("%v", claim["id"]) id := fmt.Sprintf("%v", claim["id"])
sessionToken := session.GetToken(id, token) sessionToken := session.GetUserSession(id, token)
if sessionToken == "" { if sessionToken == "" {
return res, fmt.Errorf(`unauthorized`) return res, fmt.Errorf(`unauthorized`)
@ -44,8 +46,8 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
return res, fmt.Errorf("please enter atleast one param to update") return res, fmt.Errorf("please enter atleast one param to update")
} }
email := fmt.Sprintf("%v", claim["email"]) userEmail := fmt.Sprintf("%v", claim["email"])
user, err := db.Mgr.GetUserByEmail(email) user, err := db.Mgr.GetUserByEmail(userEmail)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -99,7 +101,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
return res, fmt.Errorf(`password and confirm password does not match`) return res, fmt.Errorf(`password and confirm password does not match`)
} }
password, _ := utils.HashPassword(*params.NewPassword) password, _ := utils.EncryptPassword(*params.NewPassword)
user.Password = &password user.Password = &password
} }
@ -120,14 +122,14 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
return res, fmt.Errorf("user with this email address already exists") return res, fmt.Errorf("user with this email address already exists")
} }
session.DeleteUserSession(fmt.Sprintf("%v", user.ID)) session.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
utils.DeleteCookie(gc) utils.DeleteCookie(gc)
user.Email = newEmail user.Email = newEmail
user.EmailVerifiedAt = nil user.EmailVerifiedAt = nil
hasEmailChanged = true hasEmailChanged = true
// insert verification request // insert verification request
verificationType := enum.UpdateEmail.String() verificationType := constants.VerificationTypeUpdateEmail
token, err := utils.CreateVerificationToken(newEmail, verificationType) token, err := utils.CreateVerificationToken(newEmail, verificationType)
if err != nil { if err != nil {
log.Println(`error generating token`, err) log.Println(`error generating token`, err)
@ -141,7 +143,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendVerificationMail(newEmail, token) email.SendVerificationMail(newEmail, token)
}() }()
} }

View File

@ -9,13 +9,16 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User, error) { // UpdateUserResolver is a resolver for update user mutation
// This is admin only mutation
func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*model.User, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.User var res *model.User
if err != nil { if err != nil {
@ -67,6 +70,15 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
user.Picture = params.Picture user.Picture = params.Picture
} }
if params.EmailVerified != nil {
if *params.EmailVerified {
now := time.Now().Unix()
user.EmailVerifiedAt = &now
} else {
user.EmailVerifiedAt = nil
}
}
if params.Email != nil && user.Email != *params.Email { if params.Email != nil && user.Email != *params.Email {
// check if valid email // check if valid email
if !utils.IsValidEmail(*params.Email) { if !utils.IsValidEmail(*params.Email) {
@ -80,13 +92,13 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
return res, fmt.Errorf("user with this email address already exists") return res, fmt.Errorf("user with this email address already exists")
} }
session.DeleteUserSession(fmt.Sprintf("%v", user.ID)) session.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
utils.DeleteCookie(gc) utils.DeleteCookie(gc)
user.Email = newEmail user.Email = newEmail
user.EmailVerifiedAt = nil user.EmailVerifiedAt = nil
// insert verification request // insert verification request
verificationType := enum.UpdateEmail.String() verificationType := constants.VerificationTypeUpdateEmail
token, err := utils.CreateVerificationToken(newEmail, verificationType) token, err := utils.CreateVerificationToken(newEmail, verificationType)
if err != nil { if err != nil {
log.Println(`error generating token`, err) log.Println(`error generating token`, err)
@ -100,7 +112,7 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go func() { go func() {
utils.SendVerificationMail(newEmail, token) email.SendVerificationMail(newEmail, token)
}() }()
} }
@ -112,7 +124,7 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
inputRoles = append(inputRoles, *item) inputRoles = append(inputRoles, *item)
} }
if !utils.IsValidRoles(append([]string{}, append(constants.EnvData.ROLES, constants.EnvData.PROTECTED_ROLES...)...), inputRoles) { if !utils.IsValidRoles(append([]string{}, append(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRoles).([]string), envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyProtectedRoles).([]string)...)...), inputRoles) {
return res, fmt.Errorf("invalid list of roles") return res, fmt.Errorf("invalid list of roles")
} }
@ -120,7 +132,7 @@ func UpdateUser(ctx context.Context, params model.UpdateUserInput) (*model.User,
rolesToSave = strings.Join(inputRoles, ",") rolesToSave = strings.Join(inputRoles, ",")
} }
session.DeleteUserSession(fmt.Sprintf("%v", user.ID)) session.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
utils.DeleteCookie(gc) utils.DeleteCookie(gc)
} }

View File

@ -9,7 +9,9 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func Users(ctx context.Context) ([]*model.User, error) { // UsersResolver is a resolver for users query
// This is admin only query
func UsersResolver(ctx context.Context) ([]*model.User, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res []*model.User var res []*model.User
if err != nil { if err != nil {

View File

@ -9,7 +9,9 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) { // VerificationRequestsResolver is a resolver for verification requests query
// This is admin only query
func VerificationRequestsResolver(ctx context.Context) ([]*model.VerificationRequest, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res []*model.VerificationRequest var res []*model.VerificationRequest
if err != nil { if err != nil {

View File

@ -6,14 +6,15 @@ import (
"strings" "strings"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
) )
func VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) { // VerifyEmailResolver is a resolver for verify email mutation
func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) {
gc, err := utils.GinContextFromContext(ctx) gc, err := utils.GinContextFromContext(ctx)
var res *model.AuthResponse var res *model.AuthResponse
if err != nil { if err != nil {
@ -44,12 +45,11 @@ func VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.Aut
db.Mgr.DeleteVerificationRequest(verificationRequest) db.Mgr.DeleteVerificationRequest(verificationRequest)
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")
refreshToken, _, _ := utils.CreateAuthToken(user, enum.RefreshToken, roles) refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles)
accessToken, expiresAt, _ := utils.CreateAuthToken(user, constants.TokenTypeAccessToken, roles)
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles) session.SetUserSession(user.ID, accessToken, refreshToken)
utils.SaveSessionInDB(user.ID, gc)
session.SetToken(user.ID, accessToken, refreshToken)
utils.CreateSession(user.ID, gc)
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Email verified successfully.`, Message: `Email verified successfully.`,

View File

@ -1,23 +0,0 @@
package router
import (
"github.com/authorizerdev/authorizer/server/handlers"
"github.com/authorizerdev/authorizer/server/middlewares"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
)
func InitRouter() *gin.Engine {
router := gin.Default()
router.Use(location.Default())
router.Use(middlewares.GinContextToContextMiddleware())
router.Use(middlewares.CORSMiddleware())
router.GET("/", handlers.PlaygroundHandler())
router.POST("/graphql", handlers.GraphqlHandler())
router.GET("/verify_email", handlers.VerifyEmailHandler())
router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
return router
}

44
server/routes/routes.go Normal file
View File

@ -0,0 +1,44 @@
package routes
import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/handlers"
"github.com/authorizerdev/authorizer/server/middlewares"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
)
// InitRouter initializes gin router
func InitRouter() *gin.Engine {
router := gin.Default()
router.Use(location.Default())
router.Use(middlewares.GinContextToContextMiddleware())
router.Use(middlewares.CORSMiddleware())
router.GET("/", handlers.RootHandler())
router.POST("/graphql", handlers.GraphqlHandler())
router.GET("/playground", handlers.PlaygroundHandler())
router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
router.GET("/verify_email", handlers.VerifyEmailHandler())
router.LoadHTMLGlob("templates/*")
// login page app related routes.
if !envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyDisableLoginPage).(bool) {
app := router.Group("/app")
{
app.Static("/build", "app/build")
app.GET("/", handlers.AppHandler())
app.GET("/reset-password", handlers.AppHandler())
}
}
// dashboard related routes
app := router.Group("/dashboard")
{
app.Static("/build", "dashboard/build")
app.GET("/", handlers.DashboardHandler())
}
return router
}

View File

@ -4,14 +4,17 @@ import (
"sync" "sync"
) )
// InMemoryStore is a simple in-memory store for sessions.
type InMemoryStore struct { type InMemoryStore struct {
mu sync.Mutex mutex sync.Mutex
store map[string]map[string]string store map[string]map[string]string
socialLoginState map[string]string socialLoginState map[string]string
} }
func (c *InMemoryStore) AddToken(userId, accessToken, refreshToken string) { // AddUserSession adds a user session to the in-memory store.
c.mu.Lock() func (c *InMemoryStore) AddUserSession(userId, accessToken, refreshToken string) {
c.mutex.Lock()
defer c.mutex.Unlock()
// delete sessions > 500 // not recommended for production // delete sessions > 500 // not recommended for production
if len(c.store) >= 500 { if len(c.store) >= 500 {
c.store = map[string]map[string]string{} c.store = map[string]map[string]string{}
@ -28,48 +31,57 @@ func (c *InMemoryStore) AddToken(userId, accessToken, refreshToken string) {
} }
c.store[userId] = tempMap c.store[userId] = tempMap
} }
c.mu.Unlock()
} }
func (c *InMemoryStore) DeleteUserSession(userId string) { // DeleteAllUserSession deletes all the user sessions from in-memory store.
c.mu.Lock() func (c *InMemoryStore) DeleteAllUserSession(userId string) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.store, userId) delete(c.store, userId)
c.mu.Unlock()
} }
func (c *InMemoryStore) DeleteVerificationRequest(userId, accessToken string) { // DeleteUserSession deletes the particular user session from in-memory store.
c.mu.Lock() func (c *InMemoryStore) DeleteUserSession(userId, accessToken string) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.store[userId], accessToken) delete(c.store[userId], accessToken)
c.mu.Unlock()
} }
// ClearStore clears the in-memory store.
func (c *InMemoryStore) ClearStore() { func (c *InMemoryStore) ClearStore() {
c.mu.Lock() c.mutex.Lock()
defer c.mutex.Unlock()
c.store = map[string]map[string]string{} c.store = map[string]map[string]string{}
c.mu.Unlock()
} }
func (c *InMemoryStore) GetToken(userId, accessToken string) string { // GetUserSession returns the user session token from the in-memory store.
func (c *InMemoryStore) GetUserSession(userId, accessToken string) string {
// c.mutex.Lock()
// defer c.mutex.Unlock()
token := "" token := ""
c.mu.Lock()
if sessionMap, ok := c.store[userId]; ok { if sessionMap, ok := c.store[userId]; ok {
if val, ok := sessionMap[accessToken]; ok { if val, ok := sessionMap[accessToken]; ok {
token = val token = val
} }
} }
c.mu.Unlock()
return token return token
} }
// SetSocialLoginState sets the social login state in the in-memory store.
func (c *InMemoryStore) SetSocialLoginState(key, state string) { func (c *InMemoryStore) SetSocialLoginState(key, state string) {
c.mu.Lock() c.mutex.Lock()
defer c.mutex.Unlock()
c.socialLoginState[key] = state c.socialLoginState[key] = state
c.mu.Unlock()
} }
// GetSocialLoginState gets the social login state from the in-memory store.
func (c *InMemoryStore) GetSocialLoginState(key string) string { func (c *InMemoryStore) GetSocialLoginState(key string) string {
c.mutex.Lock()
defer c.mutex.Unlock()
state := "" state := ""
if stateVal, ok := c.socialLoginState[key]; ok { if stateVal, ok := c.socialLoginState[key]; ok {
state = stateVal state = stateVal
@ -78,8 +90,10 @@ func (c *InMemoryStore) GetSocialLoginState(key string) string {
return state return state
} }
// RemoveSocialLoginState removes the social login state from the in-memory store.
func (c *InMemoryStore) RemoveSocialLoginState(key string) { func (c *InMemoryStore) RemoveSocialLoginState(key string) {
c.mu.Lock() c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.socialLoginState, key) delete(c.socialLoginState, key)
c.mu.Unlock()
} }

View File

@ -13,7 +13,8 @@ type RedisStore struct {
store *redis.Client store *redis.Client
} }
func (c *RedisStore) AddToken(userId, accessToken, refreshToken string) { // AddUserSession adds the user session to redis
func (c *RedisStore) AddUserSession(userId, accessToken, refreshToken string) {
err := c.store.HMSet(c.ctx, "authorizer_"+userId, map[string]string{ err := c.store.HMSet(c.ctx, "authorizer_"+userId, map[string]string{
accessToken: refreshToken, accessToken: refreshToken,
}).Err() }).Err()
@ -22,20 +23,23 @@ func (c *RedisStore) AddToken(userId, accessToken, refreshToken string) {
} }
} }
func (c *RedisStore) DeleteUserSession(userId string) { // DeleteAllUserSession deletes all the user session from redis
func (c *RedisStore) DeleteAllUserSession(userId string) {
err := c.store.Del(c.ctx, "authorizer_"+userId).Err() err := c.store.Del(c.ctx, "authorizer_"+userId).Err()
if err != nil { if err != nil {
log.Fatalln("Error deleting redis token:", err) log.Fatalln("Error deleting redis token:", err)
} }
} }
func (c *RedisStore) DeleteVerificationRequest(userId, accessToken string) { // DeleteUserSession deletes the particular user session from redis
func (c *RedisStore) DeleteUserSession(userId, accessToken string) {
err := c.store.HDel(c.ctx, "authorizer_"+userId, accessToken).Err() err := c.store.HDel(c.ctx, "authorizer_"+userId, accessToken).Err()
if err != nil { if err != nil {
log.Fatalln("Error deleting redis token:", err) log.Fatalln("Error deleting redis token:", err)
} }
} }
// ClearStore clears the redis store for authorizer related tokens
func (c *RedisStore) ClearStore() { func (c *RedisStore) ClearStore() {
err := c.store.Del(c.ctx, "authorizer_*").Err() err := c.store.Del(c.ctx, "authorizer_*").Err()
if err != nil { if err != nil {
@ -43,7 +47,8 @@ func (c *RedisStore) ClearStore() {
} }
} }
func (c *RedisStore) GetToken(userId, accessToken string) string { // GetUserSession returns the user session token from the redis store.
func (c *RedisStore) GetUserSession(userId, accessToken string) string {
token := "" token := ""
res, err := c.store.HMGet(c.ctx, "authorizer_"+userId, accessToken).Result() res, err := c.store.HMGet(c.ctx, "authorizer_"+userId, accessToken).Result()
if err != nil { if err != nil {
@ -55,6 +60,7 @@ func (c *RedisStore) GetToken(userId, accessToken string) string {
return token return token
} }
// SetSocialLoginState sets the social login state in redis store.
func (c *RedisStore) SetSocialLoginState(key, state string) { func (c *RedisStore) SetSocialLoginState(key, state string) {
err := c.store.Set(c.ctx, key, state, 0).Err() err := c.store.Set(c.ctx, key, state, 0).Err()
if err != nil { if err != nil {
@ -62,6 +68,7 @@ func (c *RedisStore) SetSocialLoginState(key, state string) {
} }
} }
// GetSocialLoginState gets the social login state from redis store.
func (c *RedisStore) GetSocialLoginState(key string) string { func (c *RedisStore) GetSocialLoginState(key string) string {
state := "" state := ""
state, err := c.store.Get(c.ctx, key).Result() state, err := c.store.Get(c.ctx, key).Result()
@ -72,6 +79,7 @@ func (c *RedisStore) GetSocialLoginState(key string) string {
return state return state
} }
// RemoveSocialLoginState removes the social login state from redis store.
func (c *RedisStore) RemoveSocialLoginState(key string) { func (c *RedisStore) RemoveSocialLoginState(key string) {
err := c.store.Del(c.ctx, key).Err() err := c.store.Del(c.ctx, key).Err()
if err != nil { if err != nil {

View File

@ -5,57 +5,65 @@ import (
"log" "log"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
) )
// SessionStore is a struct that defines available session stores
// If redis store is available, higher preference is given to that store.
// Else in memory store is used.
type SessionStore struct { type SessionStore struct {
InMemoryStoreObj *InMemoryStore InMemoryStoreObj *InMemoryStore
RedisMemoryStoreObj *RedisStore RedisMemoryStoreObj *RedisStore
} }
// SessionStoreObj is a global variable that holds the
// reference to various session store instances
var SessionStoreObj SessionStore var SessionStoreObj SessionStore
func SetToken(userId, accessToken, refreshToken string) { // SetUserSession sets the user session in the session store
// TODO: Set session information in db for all the sessions that gets generated func SetUserSession(userId, accessToken, refreshToken string) {
// it should async go function
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.AddToken(userId, accessToken, refreshToken) SessionStoreObj.RedisMemoryStoreObj.AddUserSession(userId, accessToken, refreshToken)
} }
if SessionStoreObj.InMemoryStoreObj != nil { if SessionStoreObj.InMemoryStoreObj != nil {
SessionStoreObj.InMemoryStoreObj.AddToken(userId, accessToken, refreshToken) SessionStoreObj.InMemoryStoreObj.AddUserSession(userId, accessToken, refreshToken)
} }
} }
func DeleteVerificationRequest(userId, accessToken string) { // DeleteUserSession deletes the particular user session from the session store
func DeleteUserSession(userId, accessToken string) {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.DeleteVerificationRequest(userId, accessToken) SessionStoreObj.RedisMemoryStoreObj.DeleteUserSession(userId, accessToken)
} }
if SessionStoreObj.InMemoryStoreObj != nil { if SessionStoreObj.InMemoryStoreObj != nil {
SessionStoreObj.InMemoryStoreObj.DeleteVerificationRequest(userId, accessToken) SessionStoreObj.InMemoryStoreObj.DeleteUserSession(userId, accessToken)
} }
} }
func DeleteUserSession(userId string) { // DeleteAllSessions deletes all the sessions from the session store
func DeleteAllUserSession(userId string) {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.DeleteUserSession(userId) SessionStoreObj.RedisMemoryStoreObj.DeleteAllUserSession(userId)
} }
if SessionStoreObj.InMemoryStoreObj != nil { if SessionStoreObj.InMemoryStoreObj != nil {
SessionStoreObj.InMemoryStoreObj.DeleteUserSession(userId) SessionStoreObj.InMemoryStoreObj.DeleteAllUserSession(userId)
} }
} }
func GetToken(userId, accessToken string) string { // GetUserSession returns the user session from the session store
func GetUserSession(userId, accessToken string) string {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
return SessionStoreObj.RedisMemoryStoreObj.GetToken(userId, accessToken) return SessionStoreObj.RedisMemoryStoreObj.GetUserSession(userId, accessToken)
} }
if SessionStoreObj.InMemoryStoreObj != nil { if SessionStoreObj.InMemoryStoreObj != nil {
return SessionStoreObj.InMemoryStoreObj.GetToken(userId, accessToken) return SessionStoreObj.InMemoryStoreObj.GetUserSession(userId, accessToken)
} }
return "" return ""
} }
// ClearStore clears the session store for authorizer tokens
func ClearStore() { func ClearStore() {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.ClearStore() SessionStoreObj.RedisMemoryStoreObj.ClearStore()
@ -65,6 +73,7 @@ func ClearStore() {
} }
} }
// SetSocialLoginState sets the social login state in the session store
func SetSocailLoginState(key, state string) { func SetSocailLoginState(key, state string) {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.SetSocialLoginState(key, state) SessionStoreObj.RedisMemoryStoreObj.SetSocialLoginState(key, state)
@ -74,6 +83,7 @@ func SetSocailLoginState(key, state string) {
} }
} }
// GetSocialLoginState returns the social login state from the session store
func GetSocailLoginState(key string) string { func GetSocailLoginState(key string) string {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
return SessionStoreObj.RedisMemoryStoreObj.GetSocialLoginState(key) return SessionStoreObj.RedisMemoryStoreObj.GetSocialLoginState(key)
@ -85,6 +95,7 @@ func GetSocailLoginState(key string) string {
return "" return ""
} }
// RemoveSocialLoginState removes the social login state from the session store
func RemoveSocialLoginState(key string) { func RemoveSocialLoginState(key string) {
if SessionStoreObj.RedisMemoryStoreObj != nil { if SessionStoreObj.RedisMemoryStoreObj != nil {
SessionStoreObj.RedisMemoryStoreObj.RemoveSocialLoginState(key) SessionStoreObj.RedisMemoryStoreObj.RemoveSocialLoginState(key)
@ -94,10 +105,11 @@ func RemoveSocialLoginState(key string) {
} }
} }
// InitializeSessionStore initializes the SessionStoreObj based on environment variables
func InitSession() { func InitSession() {
if constants.EnvData.REDIS_URL != "" { if envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRedisURL).(string) != "" {
log.Println("using redis store to save sessions") log.Println("using redis store to save sessions")
opt, err := redis.ParseURL(constants.EnvData.REDIS_URL) opt, err := redis.ParseURL(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyRedisURL).(string))
if err != nil { if err != nil {
log.Fatalln("Error parsing redis url:", err) log.Fatalln("Error parsing redis url:", err)
} }

View File

@ -4,12 +4,14 @@ import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func adminLoginTests(s TestSetup, t *testing.T) { func adminLoginTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should complete admin login`, func(t *testing.T) { t.Run(`should complete admin login`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
_, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ _, err := resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{
@ -19,7 +21,7 @@ func adminLoginTests(s TestSetup, t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
_, err = resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{ _, err = resolvers.AdminLoginResolver(ctx, model.AdminLoginInput{
AdminSecret: constants.EnvData.ADMIN_SECRET, AdminSecret: envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string),
}) })
assert.Nil(t, err) assert.Nil(t, err)

View File

@ -0,0 +1,28 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
func adminLogoutTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should get admin session`, func(t *testing.T) {
req, ctx := createContext(s)
_, err := resolvers.AdminLogoutResolver(ctx)
assert.NotNil(t, err)
h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
_, err = resolvers.AdminLogoutResolver(ctx)
assert.Nil(t, err)
})
}

View File

@ -0,0 +1,30 @@
package test
import (
"fmt"
"log"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
func adminSessionTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should get admin session`, func(t *testing.T) {
req, ctx := createContext(s)
_, err := resolvers.AdminSessionResolver(ctx)
log.Println("error:", err)
assert.NotNil(t, err)
h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
_, err = resolvers.AdminSessionResolver(ctx)
assert.Nil(t, err)
})
}

View File

@ -1,26 +1,27 @@
package test package test
import ( import (
"log"
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func adminSignupTests(s TestSetup, t *testing.T) { func adminSignupTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should complete admin login`, func(t *testing.T) { t.Run(`should complete admin login`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
_, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ _, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{
AdminSecret: "admin", AdminSecret: "admin",
}) })
log.Println("err", err)
assert.NotNil(t, err) assert.NotNil(t, err)
// reset env for test to pass // reset env for test to pass
constants.EnvData.ADMIN_SECRET = "" envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyAdminSecret, "")
_, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ _, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{
AdminSecret: uuid.New().String(), AdminSecret: uuid.New().String(),

View File

@ -6,24 +6,26 @@ import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func configTests(s TestSetup, t *testing.T) { func configTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should get config`, func(t *testing.T) { t.Run(`should get config`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
_, err := resolvers.ConfigResolver(ctx) _, err := resolvers.ConfigResolver(ctx)
log.Println("error:", err) log.Println("error:", err)
assert.NotNil(t, err) assert.NotNil(t, err)
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
res, err := resolvers.ConfigResolver(ctx) res, err := resolvers.ConfigResolver(ctx)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, *res.AdminSecret, constants.EnvData.ADMIN_SECRET) assert.Equal(t, *res.AdminSecret, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
}) })
} }

View File

@ -5,32 +5,34 @@ import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func deleteUserTest(s TestSetup, t *testing.T) { func deleteUserTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should delete users with admin secret only`, func(t *testing.T) { t.Run(`should delete users with admin secret only`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "delete_user." + s.TestInfo.Email email := "delete_user." + s.TestInfo.Email
resolvers.Signup(ctx, model.SignUpInput{ resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err := resolvers.DeleteUser(ctx, model.DeleteUserInput{ _, err := resolvers.DeleteUserResolver(ctx, model.DeleteUserInput{
Email: email, Email: email,
}) })
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
_, err = resolvers.DeleteUser(ctx, model.DeleteUserInput{ _, err = resolvers.DeleteUserResolver(ctx, model.DeleteUserInput{
Email: email, Email: email,
}) })
assert.Nil(t, err) assert.Nil(t, err)

29
server/test/env_test.go Normal file
View File

@ -0,0 +1,29 @@
package test
import (
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/env"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/stretchr/testify/assert"
)
func TestEnvs(t *testing.T) {
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyEnvPath, "../../.env.sample")
env.InitEnv()
store := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
assert.Equal(t, store[constants.EnvKeyAdminSecret].(string), "admin")
assert.Equal(t, store[constants.EnvKeyEnv].(string), "production")
assert.False(t, store[constants.EnvKeyDisableEmailVerification].(bool))
assert.False(t, store[constants.EnvKeyDisableMagicLinkLogin].(bool))
assert.False(t, store[constants.EnvKeyDisableBasicAuthentication].(bool))
assert.Equal(t, store[constants.EnvKeyJwtType].(string), "HS256")
assert.Equal(t, store[constants.EnvKeyJwtSecret].(string), "random_string")
assert.Equal(t, store[constants.EnvKeyJwtRoleClaim].(string), "role")
assert.EqualValues(t, store[constants.EnvKeyRoles].([]string), []string{"user"})
assert.EqualValues(t, store[constants.EnvKeyDefaultRoles].([]string), []string{"user"})
assert.EqualValues(t, store[constants.EnvKeyProtectedRoles].([]string), []string{"admin"})
assert.EqualValues(t, store[constants.EnvKeyAllowedOrigins].([]string), []string{"*"})
}

View File

@ -3,32 +3,33 @@ package test
import ( import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func forgotPasswordTest(s TestSetup, t *testing.T) { func forgotPasswordTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should run forgot password`, func(t *testing.T) { t.Run(`should run forgot password`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
email := "forgot_password." + s.TestInfo.Email email := "forgot_password." + s.TestInfo.Email
_, err := resolvers.Signup(ctx, model.SignUpInput{ _, err := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err = resolvers.ForgotPassword(ctx, model.ForgotPasswordInput{ _, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
Email: email, Email: email,
}) })
assert.Nil(t, err, "no errors for forgot password") assert.Nil(t, err, "no errors for forgot password")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, verificationRequest.Identifier, enum.ForgotPassword.String()) assert.Equal(t, verificationRequest.Identifier, constants.VerificationTypeForgotPassword)
cleanData(email) cleanData(email)
}) })

View File

@ -3,49 +3,50 @@ package test
import ( import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func loginTests(s TestSetup, t *testing.T) { func loginTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should login`, func(t *testing.T) { t.Run(`should login`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
email := "login." + s.TestInfo.Email email := "login." + s.TestInfo.Email
_, err := resolvers.Signup(ctx, model.SignUpInput{ _, err := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err = resolvers.Login(ctx, model.LoginInput{ _, err = resolvers.LoginResolver(ctx, model.LoginInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
}) })
assert.NotNil(t, err, "should fail because email is not verified") assert.NotNil(t, err, "should fail because email is not verified")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
_, err = resolvers.Login(ctx, model.LoginInput{ _, err = resolvers.LoginResolver(ctx, model.LoginInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
Roles: []string{"test"}, Roles: []string{"test"},
}) })
assert.NotNil(t, err, "invalid roles") assert.NotNil(t, err, "invalid roles")
_, err = resolvers.Login(ctx, model.LoginInput{ _, err = resolvers.LoginResolver(ctx, model.LoginInput{
Email: email, Email: email,
Password: s.TestInfo.Password + "s", Password: s.TestInfo.Password + "s",
}) })
assert.NotNil(t, err, "invalid password") assert.NotNil(t, err, "invalid password")
loginRes, err := resolvers.Login(ctx, model.LoginInput{ loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
}) })

View File

@ -6,31 +6,32 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func logoutTests(s TestSetup, t *testing.T) { func logoutTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should logout user`, func(t *testing.T) { t.Run(`should logout user`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "logout." + s.TestInfo.Email email := "logout." + s.TestInfo.Email
_, err := resolvers.MagicLinkLogin(ctx, model.MagicLinkLoginInput{ _, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
Email: email, Email: email,
}) })
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.MagicLinkLogin.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
token := *verifyRes.AccessToken token := *verifyRes.AccessToken
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token))
_, err = resolvers.Logout(ctx) _, err = resolvers.LogoutResolver(ctx)
assert.Nil(t, err) assert.Nil(t, err)
_, err = resolvers.Profile(ctx) _, err = resolvers.ProfileResolver(ctx)
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
cleanData(email) cleanData(email)
}) })

View File

@ -6,30 +6,31 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func magicLinkLoginTests(s TestSetup, t *testing.T) { func magicLinkLoginTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should login with magic link`, func(t *testing.T) { t.Run(`should login with magic link`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "magic_link_login." + s.TestInfo.Email email := "magic_link_login." + s.TestInfo.Email
_, err := resolvers.MagicLinkLogin(ctx, model.MagicLinkLoginInput{ _, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
Email: email, Email: email,
}) })
assert.Nil(t, err) assert.Nil(t, err)
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.MagicLinkLogin.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
token := *verifyRes.AccessToken token := *verifyRes.AccessToken
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token))
_, err = resolvers.Profile(ctx) _, err = resolvers.ProfileResolver(ctx)
assert.Nil(t, err) assert.Nil(t, err)
cleanData(email) cleanData(email)

View File

@ -2,18 +2,17 @@ package test
import ( import (
"context" "context"
"log"
"testing" "testing"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func metaTests(s TestSetup, t *testing.T) { func metaTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should get meta information`, func(t *testing.T) { t.Run(`should get meta information`, func(t *testing.T) {
ctx := context.Background() ctx := context.Background()
meta, err := resolvers.Meta(ctx) meta, err := resolvers.MetaResolver(ctx)
log.Println("=> meta:", meta)
assert.Nil(t, err) assert.Nil(t, err)
assert.False(t, meta.IsFacebookLoginEnabled) assert.False(t, meta.IsFacebookLoginEnabled)
assert.False(t, meta.IsGoogleLoginEnabled) assert.False(t, meta.IsGoogleLoginEnabled)

View File

@ -6,34 +6,35 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func profileTests(s TestSetup, t *testing.T) { func profileTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should get profile only with token`, func(t *testing.T) { t.Run(`should get profile only with token`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "profile." + s.TestInfo.Email email := "profile." + s.TestInfo.Email
resolvers.Signup(ctx, model.SignUpInput{ resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err := resolvers.Profile(ctx) _, err := resolvers.ProfileResolver(ctx)
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
token := *verifyRes.AccessToken token := *verifyRes.AccessToken
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token))
profileRes, err := resolvers.Profile(ctx) profileRes, err := resolvers.ProfileResolver(ctx)
assert.Nil(t, err) assert.Nil(t, err)
newEmail := *&profileRes.Email newEmail := *&profileRes.Email

View File

@ -3,25 +3,26 @@ package test
import ( import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func resendVerifyEmailTests(s TestSetup, t *testing.T) { func resendVerifyEmailTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should resend verification email`, func(t *testing.T) { t.Run(`should resend verification email`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
email := "resend_verify_email." + s.TestInfo.Email email := "resend_verify_email." + s.TestInfo.Email
_, err := resolvers.Signup(ctx, model.SignUpInput{ _, err := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err = resolvers.ResendVerifyEmail(ctx, model.ResendVerifyEmailInput{ _, err = resolvers.ResendVerifyEmailResolver(ctx, model.ResendVerifyEmailInput{
Email: email, Email: email,
Identifier: enum.BasicAuthSignup.String(), Identifier: constants.VerificationTypeBasicAuthSignup,
}) })
assert.Nil(t, err) assert.Nil(t, err)

View File

@ -3,32 +3,33 @@ package test
import ( import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func resetPasswordTest(s TestSetup, t *testing.T) { func resetPasswordTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should reset password`, func(t *testing.T) { t.Run(`should reset password`, func(t *testing.T) {
email := "reset_password." + s.TestInfo.Email email := "reset_password." + s.TestInfo.Email
_, ctx := createContext(s) _, ctx := createContext(s)
_, err := resolvers.Signup(ctx, model.SignUpInput{ _, err := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err = resolvers.ForgotPassword(ctx, model.ForgotPasswordInput{ _, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
Email: email, Email: email,
}) })
assert.Nil(t, err, "no errors for forgot password") assert.Nil(t, err, "no errors for forgot password")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword)
assert.Nil(t, err, "should get forgot password request") assert.Nil(t, err, "should get forgot password request")
_, err = resolvers.ResetPassword(ctx, model.ResetPasswordInput{ _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
Password: "test1", Password: "test1",
ConfirmPassword: "test", ConfirmPassword: "test",
@ -36,7 +37,7 @@ func resetPasswordTest(s TestSetup, t *testing.T) {
assert.NotNil(t, err, "passowrds don't match") assert.NotNil(t, err, "passowrds don't match")
_, err = resolvers.ResetPassword(ctx, model.ResetPasswordInput{ _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
Password: "test1", Password: "test1",
ConfirmPassword: "test1", ConfirmPassword: "test1",

View File

@ -0,0 +1,65 @@
package test
import (
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/env"
"github.com/authorizerdev/authorizer/server/envstore"
)
func TestResolvers(t *testing.T) {
databases := map[string]string{
constants.DbTypeSqlite: "../../data.db",
// constants.DbTypeArangodb: "http://localhost:8529",
// constants.DbTypeMongodb: "mongodb://localhost:27017",
}
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyVersion, "test")
for dbType, dbURL := range databases {
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL)
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyDatabaseType, dbType)
env.InitEnv()
db.InitDB()
// clean the persisted config for test to use fresh config
config, err := db.Mgr.GetConfig()
if err == nil {
config.Config = []byte{}
db.Mgr.UpdateConfig(config)
}
env.PersistEnv()
s := testSetup()
defer s.Server.Close()
t.Run("should pass tests for "+dbType, func(t *testing.T) {
// admin tests
adminSignupTests(t, s)
verificationRequestsTest(t, s)
usersTest(t, s)
deleteUserTest(t, s)
updateUserTest(t, s)
adminLoginTests(t, s)
adminLogoutTests(t, s)
adminSessionTests(t, s)
updateConfigTests(t, s)
configTests(t, s)
// user tests
loginTests(t, s)
signupTests(t, s)
forgotPasswordTest(t, s)
resendVerifyEmailTests(t, s)
resetPasswordTest(t, s)
verifyEmailTest(t, s)
sessionTests(t, s)
profileTests(t, s)
updateProfileTests(t, s)
magicLinkLoginTests(t, s)
logoutTests(t, s)
metaTests(t, s)
})
}
}

View File

@ -6,35 +6,36 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func sessionTests(s TestSetup, t *testing.T) { func sessionTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should allow access to profile with session only`, func(t *testing.T) { t.Run(`should allow access to profile with session only`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "session." + s.TestInfo.Email email := "session." + s.TestInfo.Email
resolvers.Signup(ctx, model.SignUpInput{ resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
_, err := resolvers.Session(ctx, []string{}) _, err := resolvers.SessionResolver(ctx, []string{})
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
token := *verifyRes.AccessToken token := *verifyRes.AccessToken
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token))
sessionRes, err := resolvers.Session(ctx, []string{}) sessionRes, err := resolvers.SessionResolver(ctx, []string{})
assert.Nil(t, err) assert.Nil(t, err)
newToken := *sessionRes.AccessToken newToken := *sessionRes.AccessToken

View File

@ -3,25 +3,26 @@ package test
import ( import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func signupTests(s TestSetup, t *testing.T) { func signupTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should complete the signup and check duplicates`, func(t *testing.T) { t.Run(`should complete the signup and check duplicates`, func(t *testing.T) {
_, ctx := createContext(s) _, ctx := createContext(s)
email := "signup." + s.TestInfo.Email email := "signup." + s.TestInfo.Email
res, err := resolvers.Signup(ctx, model.SignUpInput{ res, err := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password + "s", ConfirmPassword: s.TestInfo.Password + "s",
}) })
assert.NotNil(t, err, "invalid password errors") assert.NotNil(t, err, "invalid password errors")
res, err = resolvers.Signup(ctx, model.SignUpInput{ res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
@ -31,7 +32,7 @@ func signupTests(s TestSetup, t *testing.T) {
assert.Equal(t, email, user.Email) assert.Equal(t, email, user.Email)
assert.Nil(t, res.AccessToken, "access token should be nil") assert.Nil(t, res.AccessToken, "access token should be nil")
res, err = resolvers.Signup(ctx, model.SignUpInput{ res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
@ -39,7 +40,7 @@ func signupTests(s TestSetup, t *testing.T) {
assert.NotNil(t, err, "should throw duplicate email error") assert.NotNil(t, err, "should throw duplicate email error")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, email, verificationRequest.Email) assert.Equal(t, email, verificationRequest.Email)
cleanData(email) cleanData(email)

View File

@ -9,8 +9,8 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum"
"github.com/authorizerdev/authorizer/server/env" "github.com/authorizerdev/authorizer/server/env"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/handlers" "github.com/authorizerdev/authorizer/server/handlers"
"github.com/authorizerdev/authorizer/server/middlewares" "github.com/authorizerdev/authorizer/server/middlewares"
"github.com/authorizerdev/authorizer/server/session" "github.com/authorizerdev/authorizer/server/session"
@ -32,17 +32,17 @@ type TestSetup struct {
} }
func cleanData(email string) { func cleanData(email string) {
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
if err == nil { if err == nil {
err = db.Mgr.DeleteVerificationRequest(verificationRequest) err = db.Mgr.DeleteVerificationRequest(verificationRequest)
} }
verificationRequest, err = db.Mgr.GetVerificationByEmail(email, enum.ForgotPassword.String()) verificationRequest, err = db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword)
if err == nil { if err == nil {
err = db.Mgr.DeleteVerificationRequest(verificationRequest) err = db.Mgr.DeleteVerificationRequest(verificationRequest)
} }
verificationRequest, err = db.Mgr.GetVerificationByEmail(email, enum.UpdateEmail.String()) verificationRequest, err = db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeUpdateEmail)
if err == nil { if err == nil {
err = db.Mgr.DeleteVerificationRequest(verificationRequest) err = db.Mgr.DeleteVerificationRequest(verificationRequest)
} }
@ -72,8 +72,7 @@ func testSetup() TestSetup {
Password: "test", Password: "test",
} }
constants.EnvData.ENV_PATH = "../../.env.sample" envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.EnvKeyEnvPath, "../../.env.sample")
env.InitEnv() env.InitEnv()
session.InitSession() session.InitSession()

View File

@ -6,26 +6,27 @@ import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func updateConfigTests(s TestSetup, t *testing.T) { func updateConfigTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should update configs`, func(t *testing.T) { t.Run(`should update configs`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
originalAppURL := constants.EnvData.APP_URL originalAppURL := envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAppURL).(string)
log.Println("=> originalAppURL:", constants.EnvData.APP_URL)
data := model.UpdateConfigInput{} data := model.UpdateConfigInput{}
_, err := resolvers.UpdateConfigResolver(ctx, data) _, err := resolvers.UpdateConfigResolver(ctx, data)
log.Println("error:", err) log.Println("error:", err)
assert.NotNil(t, err) assert.NotNil(t, err)
h, _ := utils.HashPassword(constants.EnvData.ADMIN_SECRET) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h)) assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
newURL := "https://test.com" newURL := "https://test.com"
data = model.UpdateConfigInput{ data = model.UpdateConfigInput{
AppURL: &newURL, AppURL: &newURL,
@ -33,8 +34,7 @@ func updateConfigTests(s TestSetup, t *testing.T) {
_, err = resolvers.UpdateConfigResolver(ctx, data) _, err = resolvers.UpdateConfigResolver(ctx, data)
log.Println("error:", err) log.Println("error:", err)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, constants.EnvData.APP_URL, newURL) assert.Equal(t, envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAppURL).(string), newURL)
assert.NotEqual(t, constants.EnvData.APP_URL, originalAppURL)
data = model.UpdateConfigInput{ data = model.UpdateConfigInput{
AppURL: &originalAppURL, AppURL: &originalAppURL,
} }

View File

@ -6,47 +6,48 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/enum" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func updateProfileTests(s TestSetup, t *testing.T) { func updateProfileTests(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should update the profile with access token only`, func(t *testing.T) { t.Run(`should update the profile with access token only`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "update_profile." + s.TestInfo.Email email := "update_profile." + s.TestInfo.Email
resolvers.Signup(ctx, model.SignUpInput{ resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
fName := "samani" fName := "samani"
_, err := resolvers.UpdateProfile(ctx, model.UpdateProfileInput{ _, err := resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
FamilyName: &fName, FamilyName: &fName,
}) })
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Mgr.GetVerificationByEmail(email, enum.BasicAuthSignup.String()) verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmail(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })
token := *verifyRes.AccessToken token := *verifyRes.AccessToken
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.COOKIE_NAME, token)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyCookieName).(string), token))
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{ _, err = resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
FamilyName: &fName, FamilyName: &fName,
}) })
assert.Nil(t, err) assert.Nil(t, err)
newEmail := "new_" + email newEmail := "new_" + email
_, err = resolvers.UpdateProfile(ctx, model.UpdateProfileInput{ _, err = resolvers.UpdateProfileResolver(ctx, model.UpdateProfileInput{
Email: &newEmail, Email: &newEmail,
}) })
assert.Nil(t, err) assert.Nil(t, err)
_, err = resolvers.Profile(ctx) _, err = resolvers.ProfileResolver(ctx)
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
cleanData(newEmail) cleanData(newEmail)

View File

@ -5,17 +5,19 @@ import (
"testing" "testing"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers" "github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func updateUserTest(s TestSetup, t *testing.T) { func updateUserTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run(`should update the user with admin secret only`, func(t *testing.T) { t.Run(`should update the user with admin secret only`, func(t *testing.T) {
req, ctx := createContext(s) req, ctx := createContext(s)
email := "update_user." + s.TestInfo.Email email := "update_user." + s.TestInfo.Email
signupRes, _ := resolvers.Signup(ctx, model.SignUpInput{ signupRes, _ := resolvers.SignupResolver(ctx, model.SignUpInput{
Email: email, Email: email,
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
@ -25,16 +27,16 @@ func updateUserTest(s TestSetup, t *testing.T) {
adminRole := "admin" adminRole := "admin"
userRole := "user" userRole := "user"
newRoles := []*string{&adminRole, &userRole} newRoles := []*string{&adminRole, &userRole}
_, err := resolvers.UpdateUser(ctx, model.UpdateUserInput{ _, err := resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{
ID: user.ID, ID: user.ID,
Roles: newRoles, Roles: newRoles,
}) })
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
h, err := utils.HashPassword(constants.EnvData.ADMIN_SECRET) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminSecret).(string))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.EnvData.ADMIN_COOKIE_NAME, h)) req.Header.Set("Cookie", fmt.Sprintf("%s=%s", envstore.EnvInMemoryStoreObj.GetEnvVariable(constants.EnvKeyAdminCookieName).(string), h))
_, err = resolvers.UpdateUser(ctx, model.UpdateUserInput{ _, err = resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{
ID: user.ID, ID: user.ID,
Roles: newRoles, Roles: newRoles,
}) })

Some files were not shown because too many files have changed in this diff Show More