diff --git a/app/favicon_io/android-chrome-192x192.png b/app/favicon_io/android-chrome-192x192.png new file mode 100644 index 0000000..6da1092 Binary files /dev/null and b/app/favicon_io/android-chrome-192x192.png differ diff --git a/app/favicon_io/android-chrome-512x512.png b/app/favicon_io/android-chrome-512x512.png new file mode 100644 index 0000000..a785706 Binary files /dev/null and b/app/favicon_io/android-chrome-512x512.png differ diff --git a/app/favicon_io/apple-touch-icon.png b/app/favicon_io/apple-touch-icon.png new file mode 100644 index 0000000..6958a31 Binary files /dev/null and b/app/favicon_io/apple-touch-icon.png differ diff --git a/app/favicon_io/favicon-16x16.png b/app/favicon_io/favicon-16x16.png new file mode 100644 index 0000000..86e472f Binary files /dev/null and b/app/favicon_io/favicon-16x16.png differ diff --git a/app/favicon_io/favicon-32x32.png b/app/favicon_io/favicon-32x32.png new file mode 100644 index 0000000..d51e2f7 Binary files /dev/null and b/app/favicon_io/favicon-32x32.png differ diff --git a/app/favicon_io/favicon.ico b/app/favicon_io/favicon.ico new file mode 100644 index 0000000..b02cb55 Binary files /dev/null and b/app/favicon_io/favicon.ico differ diff --git a/dashboard/favicon_io/android-chrome-192x192.png b/dashboard/favicon_io/android-chrome-192x192.png new file mode 100644 index 0000000..6da1092 Binary files /dev/null and b/dashboard/favicon_io/android-chrome-192x192.png differ diff --git a/dashboard/favicon_io/android-chrome-512x512.png b/dashboard/favicon_io/android-chrome-512x512.png new file mode 100644 index 0000000..a785706 Binary files /dev/null and b/dashboard/favicon_io/android-chrome-512x512.png differ diff --git a/dashboard/favicon_io/apple-touch-icon.png b/dashboard/favicon_io/apple-touch-icon.png new file mode 100644 index 0000000..6958a31 Binary files /dev/null and b/dashboard/favicon_io/apple-touch-icon.png differ diff --git a/dashboard/favicon_io/favicon-16x16.png b/dashboard/favicon_io/favicon-16x16.png new file mode 100644 index 0000000..86e472f Binary files /dev/null and b/dashboard/favicon_io/favicon-16x16.png differ diff --git a/dashboard/favicon_io/favicon-32x32.png b/dashboard/favicon_io/favicon-32x32.png new file mode 100644 index 0000000..d51e2f7 Binary files /dev/null and b/dashboard/favicon_io/favicon-32x32.png differ diff --git a/dashboard/favicon_io/favicon.ico b/dashboard/favicon_io/favicon.ico new file mode 100644 index 0000000..b02cb55 Binary files /dev/null and b/dashboard/favicon_io/favicon.ico differ diff --git a/dashboard/src/graphql/queries/index.ts b/dashboard/src/graphql/queries/index.ts index 031ac52..b235a44 100644 --- a/dashboard/src/graphql/queries/index.ts +++ b/dashboard/src/graphql/queries/index.ts @@ -64,6 +64,7 @@ export const UserDetailsQuery = ` birthdate phone_number picture + signup_methods roles created_at } diff --git a/dashboard/src/pages/Users.tsx b/dashboard/src/pages/Users.tsx index d040585..ef4d86a 100644 --- a/dashboard/src/pages/Users.tsx +++ b/dashboard/src/pages/Users.tsx @@ -61,6 +61,7 @@ interface userDataTypes { birthdate: string; phone_number: string; picture: string; + signup_methods: string; roles: [string]; created_at: number; } @@ -167,6 +168,8 @@ export default function Users() { Email Created At + Signup Methods + Roles Verified Actions @@ -177,7 +180,11 @@ export default function Users() { return ( {user.email} - {dayjs(user.created_at).format('MMM DD, YYYY')} + + {dayjs(user.created_at * 1000).format('MMM DD, YYYY')} + + {user.signup_methods} + {user.roles.join(', ')} { } else if ( _.isEqual(obj1[key], obj2[key]) || (obj1[key] === null && obj2[key] === '') || - (obj1[key] === [] && obj2[key] === null) + (obj1[key] && + Array.isArray(obj1[key]) && + obj1[key].length === 0 && + obj2[key] === null) ) { const resultKeyIndex = result.indexOf(key); result.splice(resultKeyIndex, 1); diff --git a/server/constants/env.go b/server/constants/env.go index 8c71105..f36f278 100644 --- a/server/constants/env.go +++ b/server/constants/env.go @@ -16,6 +16,7 @@ const ( // EnvKeyVersion key for build arg version EnvKeyVersion = "VERSION" // EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL + // TODO: remove support AUTHORIZER_URL env EnvKeyAuthorizerURL = "AUTHORIZER_URL" // EnvKeyPort key for env variable PORT EnvKeyPort = "PORT" diff --git a/server/cookie/admin_cookie.go b/server/cookie/admin_cookie.go index 55917a7..4c6bc26 100644 --- a/server/cookie/admin_cookie.go +++ b/server/cookie/admin_cookie.go @@ -13,7 +13,8 @@ import ( func SetAdminCookie(gc *gin.Context, token string) { secure := true httpOnly := true - host, _ := utils.GetHostParts(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) + hostname := utils.GetHost(gc) + host, _ := utils.GetHostParts(hostname) gc.SetCookie(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminCookieName), token, 3600, "/", host, secure, httpOnly) } @@ -38,7 +39,8 @@ func GetAdminCookie(gc *gin.Context) (string, error) { func DeleteAdminCookie(gc *gin.Context) { secure := true httpOnly := true - host, _ := utils.GetHostParts(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) + hostname := utils.GetHost(gc) + host, _ := utils.GetHostParts(hostname) gc.SetCookie(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminCookieName), "", -1, "/", host, secure, httpOnly) } diff --git a/server/cookie/cookie.go b/server/cookie/cookie.go index 10ea56c..7a59bae 100644 --- a/server/cookie/cookie.go +++ b/server/cookie/cookie.go @@ -19,8 +19,9 @@ import ( func SetCookie(gc *gin.Context, accessToken, refreshToken, fingerprintHash string) { secure := true httpOnly := true - host, _ := utils.GetHostParts(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) - domain := utils.GetDomainName(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) + hostname := utils.GetHost(gc) + host, _ := utils.GetHostParts(hostname) + domain := utils.GetDomainName(hostname) if domain != "localhost" { domain = "." + domain } @@ -86,9 +87,9 @@ func GetFingerPrintCookie(gc *gin.Context) (string, error) { func DeleteCookie(gc *gin.Context) { secure := true httpOnly := true - - host, _ := utils.GetHostParts(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) - domain := utils.GetDomainName(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)) + hostname := utils.GetHost(gc) + host, _ := utils.GetHostParts(hostname) + domain := utils.GetDomainName(hostname) if domain != "localhost" { domain = "." + domain } diff --git a/server/db/models/env.go b/server/db/models/env.go index f98792c..16a250b 100644 --- a/server/db/models/env.go +++ b/server/db/models/env.go @@ -6,6 +6,6 @@ type Env struct { ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` EnvData string `gorm:"type:text" json:"env" bson:"env"` Hash string `gorm:"type:text" json:"hash" bson:"hash"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` + UpdatedAt int64 `json:"updated_at" bson:"updated_at"` + CreatedAt int64 `json:"created_at" bson:"created_at"` } diff --git a/server/db/models/session.go b/server/db/models/session.go index c989e8b..0f668ae 100644 --- a/server/db/models/session.go +++ b/server/db/models/session.go @@ -8,6 +8,6 @@ type Session struct { User User `json:"-" bson:"-"` UserAgent string `json:"user_agent" bson:"user_agent"` IP string `json:"ip" bson:"ip"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + CreatedAt int64 `json:"created_at" bson:"created_at"` + UpdatedAt int64 `json:"updated_at" bson:"updated_at"` } diff --git a/server/db/models/user.go b/server/db/models/user.go index ff6247c..aa51771 100644 --- a/server/db/models/user.go +++ b/server/db/models/user.go @@ -25,8 +25,8 @@ type User struct { PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at"` Picture *string `gorm:"type:text" json:"picture" bson:"picture"` Roles string `json:"roles" bson:"roles"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` + UpdatedAt int64 `json:"updated_at" bson:"updated_at"` + CreatedAt int64 `json:"created_at" bson:"created_at"` } func (user *User) AsAPIUser() *model.User { diff --git a/server/db/models/verification_requests.go b/server/db/models/verification_requests.go index 29da0f0..5c23301 100644 --- a/server/db/models/verification_requests.go +++ b/server/db/models/verification_requests.go @@ -9,8 +9,8 @@ type VerificationRequest struct { Token string `gorm:"type:text" json:"token" bson:"token"` Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier" bson:"identifier"` ExpiresAt int64 `json:"expires_at" bson:"expires_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + CreatedAt int64 `json:"created_at" bson:"created_at"` + UpdatedAt int64 `json:"updated_at" bson:"updated_at"` Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email" bson:"email"` } diff --git a/server/db/providers/sql/env.go b/server/db/providers/sql/env.go index 489fa8d..9df14ae 100644 --- a/server/db/providers/sql/env.go +++ b/server/db/providers/sql/env.go @@ -15,8 +15,10 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) { } env.Key = env.ID - result := p.db.Create(&env) + env.CreatedAt = time.Now().Unix() + env.UpdatedAt = time.Now().Unix() + result := p.db.Create(&env) if result.Error != nil { log.Println("error adding config:", result.Error) return env, result.Error diff --git a/server/db/providers/sql/session.go b/server/db/providers/sql/session.go index 28230b5..8184558 100644 --- a/server/db/providers/sql/session.go +++ b/server/db/providers/sql/session.go @@ -2,6 +2,7 @@ package sql import ( "log" + "time" "github.com/authorizerdev/authorizer/server/db/models" "github.com/google/uuid" @@ -15,6 +16,8 @@ func (p *provider) AddSession(session models.Session) error { } session.Key = session.ID + session.CreatedAt = time.Now().Unix() + session.UpdatedAt = time.Now().Unix() res := p.db.Clauses( clause.OnConflict{ DoNothing: true, diff --git a/server/db/providers/sql/user.go b/server/db/providers/sql/user.go index 85c1d54..0a881dd 100644 --- a/server/db/providers/sql/user.go +++ b/server/db/providers/sql/user.go @@ -23,6 +23,8 @@ func (p *provider) AddUser(user models.User) (models.User, error) { user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",") } + user.CreatedAt = time.Now().Unix() + user.UpdatedAt = time.Now().Unix() user.Key = user.ID result := p.db.Clauses( clause.OnConflict{ diff --git a/server/db/providers/sql/verification_requests.go b/server/db/providers/sql/verification_requests.go index ba1d73b..7e7e7ba 100644 --- a/server/db/providers/sql/verification_requests.go +++ b/server/db/providers/sql/verification_requests.go @@ -2,6 +2,7 @@ package sql import ( "log" + "time" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/graph/model" @@ -16,6 +17,8 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio } verificationRequest.Key = verificationRequest.ID + verificationRequest.CreatedAt = time.Now().Unix() + verificationRequest.UpdatedAt = time.Now().Unix() result := p.db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "email"}, {Name: "identifier"}}, DoUpdates: clause.AssignmentColumns([]string{"token", "expires_at"}), diff --git a/server/email/forgot_password_email.go b/server/email/forgot_password_email.go index 4c00feb..ddc3c12 100644 --- a/server/email/forgot_password_email.go +++ b/server/email/forgot_password_email.go @@ -6,10 +6,10 @@ import ( ) // SendForgotPasswordMail to send forgot password email -func SendForgotPasswordMail(toEmail, token, host string) error { +func SendForgotPasswordMail(toEmail, token, hostname string) error { resetPasswordUrl := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL) if resetPasswordUrl == "" { - envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyResetPasswordURL, envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)+"/app/reset-password") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password") } // The receiver needs to be in slice as the receive supports multiple receiver diff --git a/server/email/verification_email.go b/server/email/verification_email.go index 54cfa11..27fff46 100644 --- a/server/email/verification_email.go +++ b/server/email/verification_email.go @@ -6,7 +6,7 @@ import ( ) // SendVerificationMail to send verification email -func SendVerificationMail(toEmail, token string) error { +func SendVerificationMail(toEmail, token, hostname string) error { // The receiver needs to be in slice as the receive supports multiple receiver Receiver := []string{toEmail} @@ -99,7 +99,7 @@ func SendVerificationMail(toEmail, token string) error { data := make(map[string]interface{}, 3) data["org_logo"] = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo) data["org_name"] = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName) - data["verification_url"] = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/verify_email?token=" + token + data["verification_url"] = hostname + "/verify_email?token=" + token message = addEmailTemplate(message, data, "verify_email.tmpl") // bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message) diff --git a/server/env/env.go b/server/env/env.go index de7da02..1548c3a 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -31,8 +31,6 @@ func InitEnv() { } } - // set authorizer url to empty string so that fresh url is obtained with every server start - envData.StringEnv[constants.EnvKeyAuthorizerURL] = "" if envData.StringEnv[constants.EnvKeyAppURL] == "" { envData.StringEnv[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL) } @@ -246,10 +244,9 @@ func InitEnv() { trimVal := strings.TrimSpace(val) if trimVal != "" { roles = append(roles, trimVal) - } - - if utils.StringSliceContains(defaultRoleSplit, trimVal) { - defaultRoles = append(defaultRoles, trimVal) + if utils.StringSliceContains(defaultRoleSplit, trimVal) { + defaultRoles = append(defaultRoles, trimVal) + } } } diff --git a/server/go.mod b/server/go.mod index 0ca8653..e470a65 100644 --- a/server/go.mod +++ b/server/go.mod @@ -6,7 +6,6 @@ require ( github.com/99designs/gqlgen v0.14.0 github.com/arangodb/go-driver v1.2.1 github.com/coreos/go-oidc/v3 v3.1.0 - github.com/gin-contrib/location v0.0.2 github.com/gin-gonic/gin v1.7.2 github.com/go-playground/validator/v10 v10.8.0 // indirect github.com/go-redis/redis/v8 v8.11.0 diff --git a/server/go.sum b/server/go.sum index 5f7a7f4..bcf90b7 100644 --- a/server/go.sum +++ b/server/go.sum @@ -82,11 +82,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4= -github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -100,7 +97,6 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index e159ec6..f5979c4 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -54,7 +54,6 @@ type ComplexityRoot struct { AdminSecret func(childComplexity int) int AllowedOrigins func(childComplexity int) int AppURL func(childComplexity int) int - AuthorizerURL func(childComplexity int) int CookieName func(childComplexity int) int CustomAccessTokenScript func(childComplexity int) int DatabaseName func(childComplexity int) int @@ -280,13 +279,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Env.AppURL(childComplexity), true - case "Env.AUTHORIZER_URL": - if e.complexity.Env.AuthorizerURL == nil { - break - } - - return e.complexity.Env.AuthorizerURL(childComplexity), true - case "Env.COOKIE_NAME": if e.complexity.Env.CookieName == nil { break @@ -1215,7 +1207,6 @@ type Env { JWT_TYPE: String JWT_SECRET: String ALLOWED_ORIGINS: [String!] - AUTHORIZER_URL: String APP_URL: String REDIS_URL: String COOKIE_NAME: String @@ -1250,7 +1241,6 @@ input UpdateEnvInput { JWT_TYPE: String JWT_SECRET: String ALLOWED_ORIGINS: [String!] - AUTHORIZER_URL: String APP_URL: String REDIS_URL: String COOKIE_NAME: String @@ -2271,38 +2261,6 @@ func (ec *executionContext) _Env_ALLOWED_ORIGINS(ctx context.Context, field grap return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) _Env_AUTHORIZER_URL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Env", - Field: field, - Args: nil, - IsMethod: false, - IsResolver: false, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.AuthorizerURL, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - func (ec *executionContext) _Env_APP_URL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -7094,14 +7052,6 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob if err != nil { return it, err } - case "AUTHORIZER_URL": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("AUTHORIZER_URL")) - it.AuthorizerURL, err = ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } case "APP_URL": var err error @@ -7591,8 +7541,6 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._Env_JWT_SECRET(ctx, field, obj) case "ALLOWED_ORIGINS": out.Values[i] = ec._Env_ALLOWED_ORIGINS(ctx, field, obj) - case "AUTHORIZER_URL": - out.Values[i] = ec._Env_AUTHORIZER_URL(ctx, field, obj) case "APP_URL": out.Values[i] = ec._Env_APP_URL(ctx, field, obj) case "REDIS_URL": diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index 0350d2a..5533a70 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -35,7 +35,6 @@ type Env struct { JwtType *string `json:"JWT_TYPE"` JwtSecret *string `json:"JWT_SECRET"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"` - AuthorizerURL *string `json:"AUTHORIZER_URL"` AppURL *string `json:"APP_URL"` RedisURL *string `json:"REDIS_URL"` CookieName *string `json:"COOKIE_NAME"` @@ -155,7 +154,6 @@ type UpdateEnvInput struct { JwtType *string `json:"JWT_TYPE"` JwtSecret *string `json:"JWT_SECRET"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"` - AuthorizerURL *string `json:"AUTHORIZER_URL"` AppURL *string `json:"APP_URL"` RedisURL *string `json:"REDIS_URL"` CookieName *string `json:"COOKIE_NAME"` diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index abb7979..1bbd2f8 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -98,7 +98,6 @@ type Env { JWT_TYPE: String JWT_SECRET: String ALLOWED_ORIGINS: [String!] - AUTHORIZER_URL: String APP_URL: String REDIS_URL: String COOKIE_NAME: String @@ -133,7 +132,6 @@ input UpdateEnvInput { JWT_TYPE: String JWT_SECRET: String ALLOWED_ORIGINS: [String!] - AUTHORIZER_URL: String APP_URL: String REDIS_URL: String COOKIE_NAME: String diff --git a/server/handlers/app.go b/server/handlers/app.go index 9fc723c..ef893ff 100644 --- a/server/handlers/app.go +++ b/server/handlers/app.go @@ -22,6 +22,7 @@ type State struct { // AppHandler is the handler for the /app route func AppHandler() gin.HandlerFunc { return func(c *gin.Context) { + hostname := utils.GetHost(c) if envstore.EnvInMemoryStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage) { c.JSON(400, gin.H{"error": "login page is not enabled"}) return @@ -32,7 +33,8 @@ func AppHandler() gin.HandlerFunc { var stateObj State if state == "" { - stateObj.AuthorizerURL = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + + stateObj.AuthorizerURL = hostname stateObj.RedirectURL = stateObj.AuthorizerURL + "/app" } else { @@ -62,7 +64,7 @@ func AppHandler() gin.HandlerFunc { } // validate host and domain of authorizer url - if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) { + if strings.TrimSuffix(stateObj.AuthorizerURL, "/") != hostname { c.JSON(400, gin.H{"error": "invalid host url"}) return } diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 4a0ffc8..b490c6b 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -99,6 +99,11 @@ func OAuthCallbackHandler() gin.HandlerFunc { user.SignupMethods = signupMethod user.Password = existingUser.Password + if user.EmailVerifiedAt == nil { + now := time.Now().Unix() + user.EmailVerifiedAt = &now + } + // 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. diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go index 1ae3eea..f23547e 100644 --- a/server/handlers/oauth_login.go +++ b/server/handlers/oauth_login.go @@ -16,7 +16,7 @@ import ( // OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback func OAuthLoginHandler() gin.HandlerFunc { return func(c *gin.Context) { - // TODO validate redirect URL + hostname := utils.GetHost(c) redirectURL := c.Query("redirectURL") roles := c.Query("roles") @@ -56,7 +56,7 @@ func OAuthLoginHandler() gin.HandlerFunc { } sessionstore.SetSocailLoginState(oauthStateString, constants.SignupMethodGoogle) // during the init of OAuthProvider authorizer url might be empty - oauth.OAuthProviders.GoogleConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/google" + oauth.OAuthProviders.GoogleConfig.RedirectURL = hostname + "/oauth_callback/google" url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodGithub: @@ -65,7 +65,7 @@ func OAuthLoginHandler() gin.HandlerFunc { break } sessionstore.SetSocailLoginState(oauthStateString, constants.SignupMethodGithub) - oauth.OAuthProviders.GithubConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/github" + oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/github" url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodFacebook: @@ -74,7 +74,7 @@ func OAuthLoginHandler() gin.HandlerFunc { break } sessionstore.SetSocailLoginState(oauthStateString, constants.SignupMethodFacebook) - oauth.OAuthProviders.FacebookConfig.RedirectURL = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/facebook" + oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/facebook" url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) default: diff --git a/server/middlewares/context.go b/server/middlewares/context.go index 6592e7b..8da697d 100644 --- a/server/middlewares/context.go +++ b/server/middlewares/context.go @@ -2,22 +2,13 @@ package middlewares import ( "context" - "log" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/envstore" - "github.com/gin-contrib/location" "github.com/gin-gonic/gin" ) // GinContextToContextMiddleware is a middleware to add gin context in context func GinContextToContextMiddleware() gin.HandlerFunc { return func(c *gin.Context) { - if envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) == "" { - url := location.Get(c) - log.Println("=> setting authorizer url to: " + url.Scheme + "://" + c.Request.Host) - envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyAuthorizerURL, url.Scheme+"://"+c.Request.Host) - } ctx := context.WithValue(c.Request.Context(), "GinContextKey", c) c.Request = c.Request.WithContext(ctx) c.Next() diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go index 317be78..c0ff694 100644 --- a/server/oauth/oauth.go +++ b/server/oauth/oauth.go @@ -43,7 +43,7 @@ func InitOAuth() { OAuthProviders.GoogleConfig = &oauth2.Config{ ClientID: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID), ClientSecret: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret), - RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/google", + RedirectURL: "/oauth_callback/google", Endpoint: OIDCProviders.GoogleOIDC.Endpoint(), Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, } @@ -52,7 +52,7 @@ func InitOAuth() { OAuthProviders.GithubConfig = &oauth2.Config{ ClientID: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID), ClientSecret: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret), - RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/github", + RedirectURL: "/oauth_callback/github", Endpoint: githubOAuth2.Endpoint, } } @@ -60,7 +60,7 @@ func InitOAuth() { OAuthProviders.FacebookConfig = &oauth2.Config{ ClientID: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID), ClientSecret: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret), - RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + "/oauth_callback/facebook", + RedirectURL: "/oauth_callback/facebook", Endpoint: facebookOAuth2.Endpoint, Scopes: []string{"public_profile", "email"}, } diff --git a/server/resolvers/env.go b/server/resolvers/env.go index de7d0d5..d514ef3 100644 --- a/server/resolvers/env.go +++ b/server/resolvers/env.go @@ -41,7 +41,6 @@ func EnvResolver(ctx context.Context) (*model.Env, error) { jwtSecret := store.StringEnv[constants.EnvKeyJwtSecret] jwtRoleClaim := store.StringEnv[constants.EnvKeyJwtRoleClaim] allowedOrigins := store.SliceEnv[constants.EnvKeyAllowedOrigins] - authorizerURL := store.StringEnv[constants.EnvKeyAuthorizerURL] appURL := store.StringEnv[constants.EnvKeyAppURL] redisURL := store.StringEnv[constants.EnvKeyRedisURL] cookieName := store.StringEnv[constants.EnvKeyCookieName] @@ -77,7 +76,6 @@ func EnvResolver(ctx context.Context) (*model.Env, error) { JwtSecret: &jwtSecret, JwtRoleClaim: &jwtRoleClaim, AllowedOrigins: allowedOrigins, - AuthorizerURL: &authorizerURL, AppURL: &appURL, RedisURL: &redisURL, CookieName: &cookieName, diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index 8e7719d..fd53320 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -27,7 +27,6 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu if envstore.EnvInMemoryStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) { return res, fmt.Errorf(`basic authentication is disabled for this instance`) } - host := gc.Request.Host params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { @@ -39,7 +38,8 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu return res, fmt.Errorf(`user with this email not found`) } - verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword) + hostname := utils.GetHost(gc) + verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -52,7 +52,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu // exec it as go routin so that we can reduce the api latency go func() { - email.SendForgotPasswordMail(params.Email, verificationToken, host) + email.SendForgotPasswordMail(params.Email, verificationToken, hostname) }() res = &model.Response{ diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index 6a0aa26..8455b56 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -20,6 +20,10 @@ import ( // MagicLinkLoginResolver is a resolver for magic link login mutation func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { var res *model.Response + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + return res, err + } if envstore.EnvInMemoryStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) { return res, fmt.Errorf(`magic link login is disabled for this instance`) @@ -102,10 +106,11 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu } } + hostname := utils.GetHost(gc) if !envstore.EnvInMemoryStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) { // insert verification request verificationType := constants.VerificationTypeMagicLinkLogin - verificationToken, err := token.CreateVerificationToken(params.Email, verificationType) + verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -118,7 +123,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu // exec it as go routin so that we can reduce the api latency go func() { - email.SendVerificationMail(params.Email, verificationToken) + email.SendVerificationMail(params.Email, verificationToken, hostname) }() } diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go index b0fb815..214668f 100644 --- a/server/resolvers/resend_verify_email.go +++ b/server/resolvers/resend_verify_email.go @@ -18,6 +18,10 @@ import ( // ResendVerifyEmailResolver is a resolver for resend verify email mutation func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { var res *model.Response + gc, err := utils.GinContextFromContext(ctx) + if err != nil { + return res, err + } params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { @@ -39,7 +43,8 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma log.Println("error deleting verification request:", err) } - verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier) + hostname := utils.GetHost(gc) + verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -52,7 +57,7 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma // exec it as go routin so that we can reduce the api latency go func() { - email.SendVerificationMail(params.Email, verificationToken) + email.SendVerificationMail(params.Email, verificationToken, hostname) }() res = &model.Response{ diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index 027d593..adeb20f 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -119,10 +119,11 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR roles := strings.Split(user.Roles, ",") userToReturn := user.AsAPIUser() + hostname := utils.GetHost(gc) if !envstore.EnvInMemoryStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) { // insert verification request verificationType := constants.VerificationTypeBasicAuthSignup - verificationToken, err := token.CreateVerificationToken(params.Email, verificationType) + verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -135,7 +136,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR // exec it as go routin so that we can reduce the api latency go func() { - email.SendVerificationMail(params.Email, verificationToken) + email.SendVerificationMail(params.Email, verificationToken, hostname) }() res = &model.AuthResponse{ diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go index 2c56ebf..9791314 100644 --- a/server/resolvers/update_env.go +++ b/server/resolvers/update_env.go @@ -13,6 +13,8 @@ import ( "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/oauth" + "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" ) @@ -115,6 +117,8 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model // Update local store envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData) + sessionstore.InitSession() + oauth.InitOAuth() // Fetch the current db store and update it env, err := db.Provider.GetEnv() diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index aca082d..1f19adb 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -116,12 +116,13 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) sessionstore.DeleteAllUserSession(fmt.Sprintf("%v", user.ID)) cookie.DeleteCookie(gc) + hostname := utils.GetHost(gc) user.Email = newEmail user.EmailVerifiedAt = nil hasEmailChanged = true // insert verification request verificationType := constants.VerificationTypeUpdateEmail - verificationToken, err := token.CreateVerificationToken(newEmail, verificationType) + verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -134,7 +135,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) // exec it as go routin so that we can reduce the api latency go func() { - email.SendVerificationMail(newEmail, verificationToken) + email.SendVerificationMail(newEmail, verificationToken, hostname) }() } diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index bf5adf0..efbd280 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -98,11 +98,12 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod sessionstore.DeleteAllUserSession(fmt.Sprintf("%v", user.ID)) cookie.DeleteCookie(gc) + hostname := utils.GetHost(gc) user.Email = newEmail user.EmailVerifiedAt = nil // insert verification request verificationType := constants.VerificationTypeUpdateEmail - verificationToken, err := token.CreateVerificationToken(newEmail, verificationType) + verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname) if err != nil { log.Println(`error generating token`, err) } @@ -115,7 +116,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod // exec it as go routin so that we can reduce the api latency go func() { - email.SendVerificationMail(newEmail, verificationToken) + email.SendVerificationMail(newEmail, verificationToken, hostname) }() } @@ -127,7 +128,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod inputRoles = append(inputRoles, *item) } - if !utils.IsValidRoles(append([]string{}, append(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles), envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyProtectedRoles)...)...), inputRoles) { + if !utils.IsValidRoles(inputRoles, append([]string{}, append(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles), envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyProtectedRoles)...)...)) { return res, fmt.Errorf("invalid list of roles") } diff --git a/server/routes/routes.go b/server/routes/routes.go index 38ecafd..f5b5770 100644 --- a/server/routes/routes.go +++ b/server/routes/routes.go @@ -3,14 +3,13 @@ package routes import ( "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(location.Default()) router.Use(middlewares.GinContextToContextMiddleware()) router.Use(middlewares.CORSMiddleware()) @@ -25,14 +24,16 @@ func InitRouter() *gin.Engine { // login page app related routes. app := router.Group("/app") { + app.Static("/favicon_io", "app/favicon_io") app.Static("/build", "app/build") app.GET("/", handlers.AppHandler()) - app.GET("/reset-password", handlers.AppHandler()) + app.GET("/:page", handlers.AppHandler()) } // dashboard related routes dashboard := router.Group("/dashboard") { + dashboard.Static("/favicon_io", "dashboard/favicon_io") dashboard.Static("/build", "dashboard/build") dashboard.GET("/", handlers.DashboardHandler()) dashboard.GET("/:page", handlers.DashboardHandler()) diff --git a/server/test/admin_signup_test.go b/server/test/admin_signup_test.go index e48822a..6ef545c 100644 --- a/server/test/admin_signup_test.go +++ b/server/test/admin_signup_test.go @@ -7,13 +7,12 @@ import ( "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/resolvers" - "github.com/google/uuid" "github.com/stretchr/testify/assert" ) func adminSignupTests(t *testing.T, s TestSetup) { t.Helper() - t.Run(`should complete admin login`, func(t *testing.T) { + t.Run(`should complete admin signup`, func(t *testing.T) { _, ctx := createContext(s) _, err := resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ AdminSecret: "admin", @@ -24,7 +23,7 @@ func adminSignupTests(t *testing.T, s TestSetup) { envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyAdminSecret, "") _, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{ - AdminSecret: uuid.New().String(), + AdminSecret: "admin123", }) assert.Nil(t, err) diff --git a/server/test/env_file_test.go b/server/test/env_file_test.go index 496e79f..8a6a838 100644 --- a/server/test/env_file_test.go +++ b/server/test/env_file_test.go @@ -14,16 +14,13 @@ func TestEnvs(t *testing.T) { env.InitEnv() store := envstore.EnvInMemoryStoreObj.GetEnvStoreClone() - assert.Equal(t, store.StringEnv[constants.EnvKeyAdminSecret], "admin") assert.Equal(t, store.StringEnv[constants.EnvKeyEnv], "production") assert.False(t, store.BoolEnv[constants.EnvKeyDisableEmailVerification]) assert.False(t, store.BoolEnv[constants.EnvKeyDisableMagicLinkLogin]) assert.False(t, store.BoolEnv[constants.EnvKeyDisableBasicAuthentication]) assert.Equal(t, store.StringEnv[constants.EnvKeyJwtType], "HS256") - assert.Equal(t, store.StringEnv[constants.EnvKeyJwtSecret], "random_string") assert.Equal(t, store.StringEnv[constants.EnvKeyJwtRoleClaim], "role") assert.EqualValues(t, store.SliceEnv[constants.EnvKeyRoles], []string{"user"}) assert.EqualValues(t, store.SliceEnv[constants.EnvKeyDefaultRoles], []string{"user"}) - assert.EqualValues(t, store.SliceEnv[constants.EnvKeyProtectedRoles], []string{"admin"}) assert.EqualValues(t, store.SliceEnv[constants.EnvKeyAllowedOrigins], []string{"*"}) } diff --git a/server/test/resolvers_test.go b/server/test/resolvers_test.go index 5bc8e86..a1d7e3c 100644 --- a/server/test/resolvers_test.go +++ b/server/test/resolvers_test.go @@ -1,6 +1,7 @@ package test import ( + "log" "testing" "github.com/authorizerdev/authorizer/server/constants" @@ -20,20 +21,20 @@ func TestResolvers(t *testing.T) { envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseURL, dbURL) envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseType, dbType) - env.InitEnv() + s := testSetup() + defer s.Server.Close() + db.InitDB() // clean the persisted config for test to use fresh config envData, err := db.Provider.GetEnv() + log.Println("=> envData:", envstore.EnvInMemoryStoreObj.GetEnvStoreClone()) if err == nil { envData.EnvData = "" db.Provider.UpdateEnv(envData) } env.PersistEnv() - s := testSetup() - defer s.Server.Close() - t.Run("should pass tests for "+dbType, func(t *testing.T) { // admin tests adminSignupTests(t, s) diff --git a/server/test/test.go b/server/test/test.go index 8132bdc..e0451a9 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -14,7 +14,6 @@ import ( "github.com/authorizerdev/authorizer/server/handlers" "github.com/authorizerdev/authorizer/server/middlewares" "github.com/authorizerdev/authorizer/server/sessionstore" - "github.com/gin-contrib/location" "github.com/gin-gonic/gin" ) @@ -73,13 +72,17 @@ func testSetup() TestSetup { } envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, "../../.env.sample") - + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeySmtpHost, "smtp.yopmail.com") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeySmtpPort, "2525") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeySmtpUsername, "lakhan@yopmail.com") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeySmtpPassword, "test") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeySenderEmail, "info@yopmail.com") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.SliceStoreIdentifier, constants.EnvKeyProtectedRoles, []string{"admin"}) env.InitEnv() sessionstore.InitSession() w := httptest.NewRecorder() c, r := gin.CreateTestContext(w) - r.Use(location.Default()) r.Use(middlewares.GinContextToContextMiddleware()) r.Use(middlewares.CORSMiddleware()) diff --git a/server/test/update_user_test.go b/server/test/update_user_test.go index 58e06d3..0740af7 100644 --- a/server/test/update_user_test.go +++ b/server/test/update_user_test.go @@ -24,7 +24,7 @@ func updateUserTest(t *testing.T, s TestSetup) { }) user := *signupRes.User - adminRole := "admin" + adminRole := "supplier" userRole := "user" newRoles := []*string{&adminRole, &userRole} _, err := resolvers.UpdateUserResolver(ctx, model.UpdateUserInput{ diff --git a/server/test/urls_test.go b/server/test/urls_test.go index 1a01dc1..2f2fbcd 100644 --- a/server/test/urls_test.go +++ b/server/test/urls_test.go @@ -8,9 +8,9 @@ import ( ) func TestGetHostName(t *testing.T) { - authorizer_url := "http://test.herokuapp.com:80" + url := "http://test.herokuapp.com:80" - host, port := utils.GetHostParts(authorizer_url) + host, port := utils.GetHostParts(url) expectedHost := "test.herokuapp.com" assert.Equal(t, host, expectedHost, "hostname should be equal") @@ -18,9 +18,9 @@ func TestGetHostName(t *testing.T) { } func TestGetDomainName(t *testing.T) { - authorizer_url := "http://test.herokuapp.com" + url := "http://test.herokuapp.com" - got := utils.GetDomainName(authorizer_url) + got := utils.GetDomainName(url) want := "herokuapp.com" assert.Equal(t, got, want, "domain name should be equal") diff --git a/server/token/admin_token.go b/server/token/admin_token.go index bed0d0a..f1780d2 100644 --- a/server/token/admin_token.go +++ b/server/token/admin_token.go @@ -2,7 +2,6 @@ package token import ( "fmt" - "log" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" @@ -25,7 +24,7 @@ func GetAdminAuthToken(gc *gin.Context) (string, error) { } err = bcrypt.CompareHashAndPassword([]byte(token), []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret))) - log.Println("error comparing hash:", err) + if err != nil { return "", fmt.Errorf(`unauthorized`) } diff --git a/server/token/verification_token.go b/server/token/verification_token.go index 98b2089..5e70bfb 100644 --- a/server/token/verification_token.go +++ b/server/token/verification_token.go @@ -23,7 +23,7 @@ type CustomClaim struct { } // CreateVerificationToken creates a verification JWT token -func CreateVerificationToken(email string, tokenType string) (string, error) { +func CreateVerificationToken(email, tokenType, hostname string) (string, error) { t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) t.Claims = &CustomClaim{ @@ -31,7 +31,7 @@ func CreateVerificationToken(email string, tokenType string) (string, error) { ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), }, tokenType, - VerificationRequestToken{Email: email, Host: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL), RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL)}, + VerificationRequestToken{Email: email, Host: hostname, RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL)}, } return t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) diff --git a/server/utils/common.go b/server/utils/common.go index 338fc30..2438d3b 100644 --- a/server/utils/common.go +++ b/server/utils/common.go @@ -34,3 +34,16 @@ func SaveSessionInDB(userId string, c *gin.Context) { log.Println("=> session saved in db:", sessionData) } } + +// RemoveDuplicateString removes duplicate strings from a string slice +func RemoveDuplicateString(strSlice []string) []string { + allKeys := make(map[string]bool) + list := []string{} + for _, item := range strSlice { + if _, value := allKeys[item]; !value { + allKeys[item] = true + list = append(list, item) + } + } + return list +} diff --git a/server/utils/urls.go b/server/utils/urls.go index 6022487..284e259 100644 --- a/server/utils/urls.go +++ b/server/utils/urls.go @@ -1,10 +1,23 @@ package utils import ( + "log" "net/url" "strings" + + "github.com/gin-gonic/gin" ) +// GetHost returns hostname from request context +func GetHost(c *gin.Context) string { + scheme := "http" + if c.Request.TLS != nil { + scheme = "https" + } + log.Println("=> url:", scheme+"://"+c.Request.Host) + return scheme + "://" + c.Request.Host +} + // GetHostName function returns hostname and port func GetHostParts(uri string) (string, string) { tempURI := uri diff --git a/templates/app.tmpl b/templates/app.tmpl index b841808..58f0159 100644 --- a/templates/app.tmpl +++ b/templates/app.tmpl @@ -2,8 +2,12 @@ + {{.data.organizationName}} + + + Document