diff --git a/server/utils/cli.go b/server/cli/cli.go similarity index 95% rename from server/utils/cli.go rename to server/cli/cli.go index 650df39..7f6f250 100644 --- a/server/utils/cli.go +++ b/server/cli/cli.go @@ -1,4 +1,4 @@ -package utils +package cli var ( // ARG_DB_URL is the cli arg variable for the database url diff --git a/server/cookie/admin_cookie.go b/server/cookie/admin_cookie.go index 22b87f7..6b64767 100644 --- a/server/cookie/admin_cookie.go +++ b/server/cookie/admin_cookie.go @@ -4,7 +4,7 @@ import ( "net/url" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/gin-gonic/gin" ) @@ -12,8 +12,8 @@ import ( func SetAdminCookie(gc *gin.Context, token string) { secure := true httpOnly := true - hostname := utils.GetHost(gc) - host, _ := utils.GetHostParts(hostname) + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) gc.SetCookie(constants.AdminCookieName, token, 3600, "/", host, secure, httpOnly) } @@ -37,7 +37,7 @@ func GetAdminCookie(gc *gin.Context) (string, error) { func DeleteAdminCookie(gc *gin.Context) { secure := true httpOnly := true - hostname := utils.GetHost(gc) - host, _ := utils.GetHostParts(hostname) + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) gc.SetCookie(constants.AdminCookieName, "", -1, "/", host, secure, httpOnly) } diff --git a/server/cookie/cookie.go b/server/cookie/cookie.go index 562b886..73c60ea 100644 --- a/server/cookie/cookie.go +++ b/server/cookie/cookie.go @@ -5,7 +5,7 @@ import ( "net/url" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/gin-gonic/gin" ) @@ -13,9 +13,9 @@ import ( func SetSession(gc *gin.Context, sessionID string) { secure := true httpOnly := true - hostname := utils.GetHost(gc) - host, _ := utils.GetHostParts(hostname) - domain := utils.GetDomainName(hostname) + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) + domain := parsers.GetDomainName(hostname) if domain != "localhost" { domain = "." + domain } @@ -32,9 +32,9 @@ func SetSession(gc *gin.Context, sessionID string) { func DeleteSession(gc *gin.Context) { secure := true httpOnly := true - hostname := utils.GetHost(gc) - host, _ := utils.GetHostParts(hostname) - domain := utils.GetDomainName(hostname) + hostname := parsers.GetHost(gc) + host, _ := parsers.GetHostParts(hostname) + domain := parsers.GetDomainName(hostname) if domain != "localhost" { domain = "." + domain } diff --git a/server/env/env.go b/server/env/env.go index ac652cf..8b47746 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -11,6 +11,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/utils" ) @@ -251,7 +252,7 @@ func InitAllEnv() error { trimVal := strings.TrimSpace(val) if trimVal != "" { if trimVal != "*" { - host, port := utils.GetHostParts(trimVal) + host, port := parsers.GetHostParts(trimVal) allowedOrigins = append(allowedOrigins, host+":"+port) } else { hasWildCard = true diff --git a/server/env/persist_env.go b/server/env/persist_env.go index 134aca6..64b366f 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -15,6 +15,7 @@ import ( "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // GetEnvData returns the env data from database @@ -138,7 +139,7 @@ func PersistEnv() error { case constants.EnvKeyRoles, constants.EnvKeyDefaultRoles, constants.EnvKeyProtectedRoles: envStringArr := strings.Split(envValue, ",") originalValue := utils.ConvertInterfaceToStringSlice(value) - if !utils.IsStringArrayEqual(originalValue, envStringArr) { + if !validators.IsStringArrayEqual(originalValue, envStringArr) { storeData[key] = envStringArr hasChanged = true } diff --git a/server/handlers/app.go b/server/handlers/app.go index 1827d54..5b34fb6 100644 --- a/server/handlers/app.go +++ b/server/handlers/app.go @@ -9,7 +9,8 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/parsers" + "github.com/authorizerdev/authorizer/server/validators" ) // State is the struct that holds authorizer url and redirect url @@ -22,7 +23,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) + hostname := parsers.GetHost(c) if isLoginPageDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage); err != nil || isLoginPageDisabled { log.Debug("Login page is disabled") c.JSON(400, gin.H{"error": "login page is not enabled"}) @@ -44,7 +45,7 @@ func AppHandler() gin.HandlerFunc { redirect_uri = hostname + "/app" } else { // validate redirect url with allowed origins - if !utils.IsValidOrigin(redirect_uri) { + if !validators.IsValidOrigin(redirect_uri) { log.Debug("Invalid redirect_uri") c.JSON(400, gin.H{"error": "invalid redirect url"}) return diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go index cf7c640..7f3e948 100644 --- a/server/handlers/oauth_login.go +++ b/server/handlers/oauth_login.go @@ -10,13 +10,14 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/oauth" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/parsers" + "github.com/authorizerdev/authorizer/server/validators" ) // OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback func OAuthLoginHandler() gin.HandlerFunc { return func(c *gin.Context) { - hostname := utils.GetHost(c) + hostname := parsers.GetHost(c) // deprecating redirectURL instead use redirect_uri redirectURI := strings.TrimSpace(c.Query("redirectURL")) if redirectURI == "" { @@ -64,7 +65,7 @@ func OAuthLoginHandler() gin.HandlerFunc { log.Debug("Error getting protected roles: ", err) } - if !utils.IsValidRoles(rolesSplit, append([]string{}, append(roles, protectedRoles...)...)) { + if !validators.IsValidRoles(rolesSplit, append([]string{}, append(roles, protectedRoles...)...)) { log.Debug("Invalid roles: ", roles) c.JSON(400, gin.H{ "error": "invalid role", diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index a7b4f8c..781caf1 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -5,13 +5,13 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/parsers" ) // OpenIDConfigurationHandler handler for open-id configurations func OpenIDConfigurationHandler() gin.HandlerFunc { return func(c *gin.Context) { - issuer := utils.GetHost(c) + issuer := parsers.GetHost(c) jwtType, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType) c.JSON(200, gin.H{ diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index d9abe50..7adb672 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -13,6 +13,7 @@ import ( "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" ) @@ -40,7 +41,7 @@ func VerifyEmailHandler() gin.HandlerFunc { } // verify if token exists in db - hostname := utils.GetHost(c) + hostname := parsers.GetHost(c) claim, err := token.ParseJWTToken(tokenInQuery, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { log.Debug("Error parsing token: ", err) diff --git a/server/main.go b/server/main.go index 4071a11..e2ee442 100644 --- a/server/main.go +++ b/server/main.go @@ -6,13 +6,13 @@ import ( "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cli" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/env" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/routes" - "github.com/authorizerdev/authorizer/server/utils" ) var VERSION string @@ -27,10 +27,10 @@ func (u LogUTCFormatter) Format(e *log.Entry) ([]byte, error) { } func main() { - utils.ARG_DB_URL = flag.String("database_url", "", "Database connection string") - utils.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") - utils.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") - utils.ARG_LOG_LEVEL = flag.String("log_level", "info", "Log level, possible values are debug,info,warn,error,fatal,panic") + cli.ARG_DB_URL = flag.String("database_url", "", "Database connection string") + cli.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") + cli.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") + cli.ARG_LOG_LEVEL = flag.String("log_level", "info", "Log level, possible values are debug,info,warn,error,fatal,panic") flag.Parse() // global log level @@ -41,7 +41,7 @@ func main() { log.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}}) var logLevel logrus.Level - switch *utils.ARG_LOG_LEVEL { + switch *cli.ARG_LOG_LEVEL { case "debug": logLevel = logrus.DebugLevel case "info": @@ -107,5 +107,11 @@ func main() { router := routes.InitRouter(log) log.Info("Starting Authorizer: ", VERSION) - router.Run(":" + memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyPort)) + port, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyPort) + if err != nil { + log.Info("Error while getting port from env using default port 8080: ", err) + port = "8080" + } + + router.Run(":" + port) } diff --git a/server/memorystore/providers/inmemory/store.go b/server/memorystore/providers/inmemory/store.go index f935f84..ebb48cf 100644 --- a/server/memorystore/providers/inmemory/store.go +++ b/server/memorystore/providers/inmemory/store.go @@ -2,8 +2,6 @@ package inmemory import ( "strings" - - "github.com/authorizerdev/authorizer/server/utils" ) // ClearStore clears the in-memory store. @@ -105,6 +103,12 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) { // GetSliceStoreEnvVariable to get the env variable from slice store object func (c *provider) GetSliceStoreEnvVariable(key string) ([]string, error) { res := c.envStore.Get(key) - resSlice := utils.ConvertInterfaceToStringSlice(res) + data := res.([]interface{}) + var resSlice []string + + for _, v := range data { + resSlice = append(resSlice, v.(string)) + } + return resSlice, nil } diff --git a/server/memorystore/required_env_store.go b/server/memorystore/required_env_store.go index a6c44c7..68dc85c 100644 --- a/server/memorystore/required_env_store.go +++ b/server/memorystore/required_env_store.go @@ -9,8 +9,8 @@ import ( "github.com/joho/godotenv" log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cli" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/utils" ) // RequiredEnv holds information about required envs @@ -62,8 +62,8 @@ func InitRequiredEnv() error { } } - if utils.ARG_ENV_FILE != nil && *utils.ARG_ENV_FILE != "" { - envPath = *utils.ARG_ENV_FILE + if cli.ARG_ENV_FILE != nil && *cli.ARG_ENV_FILE != "" { + envPath = *cli.ARG_ENV_FILE } log.Info("env path: ", envPath) @@ -85,8 +85,8 @@ func InitRequiredEnv() error { redisURL := os.Getenv(constants.EnvKeyRedisURL) if strings.TrimSpace(dbType) == "" { - if utils.ARG_DB_TYPE != nil && *utils.ARG_DB_TYPE != "" { - dbType = strings.TrimSpace(*utils.ARG_DB_TYPE) + if cli.ARG_DB_TYPE != nil && *cli.ARG_DB_TYPE != "" { + dbType = strings.TrimSpace(*cli.ARG_DB_TYPE) } if dbType == "" { @@ -96,8 +96,8 @@ func InitRequiredEnv() error { } if strings.TrimSpace(dbURL) == "" { - if utils.ARG_DB_URL != nil && *utils.ARG_DB_URL != "" { - dbURL = strings.TrimSpace(*utils.ARG_DB_URL) + if cli.ARG_DB_URL != nil && *cli.ARG_DB_URL != "" { + dbURL = strings.TrimSpace(*cli.ARG_DB_URL) } if dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" { diff --git a/server/middlewares/cors.go b/server/middlewares/cors.go index ca06721..ee3b9c3 100644 --- a/server/middlewares/cors.go +++ b/server/middlewares/cors.go @@ -1,7 +1,7 @@ package middlewares import ( - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" "github.com/gin-gonic/gin" ) @@ -10,7 +10,7 @@ func CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { origin := c.Request.Header.Get("Origin") - if utils.IsValidOrigin(origin) { + if validators.IsValidOrigin(origin) { c.Writer.Header().Set("Access-Control-Allow-Origin", origin) } diff --git a/server/utils/urls.go b/server/parsers/url.go similarity index 87% rename from server/utils/urls.go rename to server/parsers/url.go index bf56017..19202c1 100644 --- a/server/utils/urls.go +++ b/server/parsers/url.go @@ -1,4 +1,4 @@ -package utils +package parsers import ( "net/url" @@ -19,7 +19,10 @@ func GetHost(c *gin.Context) string { return authorizerURL } - authorizerURL = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + authorizerURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL) + if err == nil { + authorizerURL = "" + } if authorizerURL != "" { return authorizerURL } @@ -89,8 +92,8 @@ func GetDomainName(uri string) string { // GetAppURL to get /app/ url if not configured by user func GetAppURL(gc *gin.Context) string { - envAppURL := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) - if envAppURL == "" { + envAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) + if envAppURL == "" || err != nil { envAppURL = GetHost(gc) + "/app" } return envAppURL diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index c5ba25a..4bcf107 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -14,8 +14,10 @@ import ( "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // ForgotPasswordResolver is a resolver for forgot password mutation @@ -39,7 +41,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu } params.Email = strings.ToLower(params.Email) - if !utils.IsValidEmail(params.Email) { + if !validators.IsValidEmail(params.Email) { log.Debug("Invalid email address: ", params.Email) return res, fmt.Errorf("invalid email") } @@ -53,13 +55,13 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu return res, fmt.Errorf(`user with this email not found`) } - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) _, nonceHash, err := utils.GenerateNonce() if err != nil { log.Debug("Failed to generate nonce: ", err) return res, err } - redirectURL := utils.GetAppURL(gc) + "/reset-password" + redirectURL := parsers.GetAppURL(gc) + "/reset-password" if params.RedirectURI != nil { redirectURL = *params.RedirectURI } diff --git a/server/resolvers/invite_members.go b/server/resolvers/invite_members.go index 87579ae..959f164 100644 --- a/server/resolvers/invite_members.go +++ b/server/resolvers/invite_members.go @@ -15,8 +15,10 @@ import ( emailservice "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // InviteMembersResolver resolver to invite members @@ -54,7 +56,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) // filter valid emails emails := []string{} for _, email := range params.Emails { - if utils.IsValidEmail(email) { + if validators.IsValidEmail(email) { emails = append(emails, email) } } @@ -93,9 +95,9 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) Email: email, Roles: strings.Join(defaultRoles, ","), } - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) verifyEmailURL := hostname + "/verify_email" - appURL := utils.GetAppURL(gc) + appURL := parsers.GetAppURL(gc) redirectURL := appURL if params.RedirectURI != nil { diff --git a/server/resolvers/login.go b/server/resolvers/login.go index 7dc47ac..45ea318 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -17,6 +17,7 @@ import ( "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // LoginResolver is a resolver for login mutation @@ -78,7 +79,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes } currentRoles := strings.Split(user.Roles, ",") if len(params.Roles) > 0 { - if !utils.IsValidRoles(params.Roles, currentRoles) { + if !validators.IsValidRoles(params.Roles, currentRoles) { log.Debug("Invalid roles: ", params.Roles) return res, fmt.Errorf(`invalid roles`) } diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index 53b2f0e..e44386c 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -14,8 +14,10 @@ import ( "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // MagicLinkLoginResolver is a resolver for magic link login mutation @@ -41,7 +43,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu params.Email = strings.ToLower(params.Email) - if !utils.IsValidEmail(params.Email) { + if !validators.IsValidEmail(params.Email) { log.Debug("Invalid email") return res, fmt.Errorf(`invalid email address`) } @@ -77,7 +79,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu log.Debug("Error getting roles: ", err) return res, err } - if !utils.IsValidRoles(params.Roles, roles) { + if !validators.IsValidRoles(params.Roles, roles) { log.Debug("Invalid roles: ", params.Roles) return res, fmt.Errorf(`invalid roles`) } else { @@ -158,7 +160,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu } } - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) if err != nil { log.Debug("Error getting email verification disabled: ", err) @@ -178,7 +180,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu if params.Scope != nil && len(params.Scope) > 0 { redirectURLParams = redirectURLParams + "&scope=" + strings.Join(params.Scope, " ") } - redirectURL := utils.GetAppURL(gc) + redirectURL := parsers.GetAppURL(gc) if params.RedirectURI != nil { redirectURL = *params.RedirectURI } diff --git a/server/resolvers/meta.go b/server/resolvers/meta.go index eab3846..18fe561 100644 --- a/server/resolvers/meta.go +++ b/server/resolvers/meta.go @@ -3,12 +3,90 @@ package resolvers import ( "context" + log "github.com/sirupsen/logrus" + + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/memorystore" ) // MetaResolver is a resolver for meta query func MetaResolver(ctx context.Context) (*model.Meta, error) { - metaInfo := utils.GetMetaInfo() + clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID) + if err != nil { + return nil, err + } + + googleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) + if err != nil { + log.Debug("Failed to get Google Client ID from environment variable", err) + googleClientID = "" + } + + googleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) + if err != nil { + log.Debug("Failed to get Google Client Secret from environment variable", err) + googleClientSecret = "" + } + + facebookClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) + if err != nil { + log.Debug("Failed to get Facebook Client ID from environment variable", err) + facebookClientID = "" + } + + facebookClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) + if err != nil { + log.Debug("Failed to get Facebook Client Secret from environment variable", err) + facebookClientSecret = "" + } + + githubClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) + if err != nil { + log.Debug("Failed to get Github Client ID from environment variable", err) + githubClientID = "" + } + + githubClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) + if err != nil { + log.Debug("Failed to get Github Client Secret from environment variable", err) + githubClientSecret = "" + } + + isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) + if err != nil { + log.Debug("Failed to get Disable Basic Authentication from environment variable", err) + isBasicAuthDisabled = true + } + + isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) + if err != nil { + log.Debug("Failed to get Disable Email Verification from environment variable", err) + isEmailVerificationDisabled = true + } + + isMagicLinkLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) + if err != nil { + log.Debug("Failed to get Disable Magic Link Login from environment variable", err) + isMagicLinkLoginDisabled = true + } + + isSignUpDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) + if err != nil { + log.Debug("Failed to get Disable Signup from environment variable", err) + isSignUpDisabled = true + } + + metaInfo := model.Meta{ + Version: constants.VERSION, + ClientID: clientID, + IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "", + IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "", + IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "", + IsBasicAuthenticationEnabled: !isBasicAuthDisabled, + IsEmailVerificationEnabled: !isEmailVerificationDisabled, + IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled, + IsSignUpEnabled: !isSignUpDisabled, + } return &metaInfo, nil } diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go index 6ae6f34..79abb4b 100644 --- a/server/resolvers/resend_verify_email.go +++ b/server/resolvers/resend_verify_email.go @@ -12,8 +12,10 @@ import ( "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // ResendVerifyEmailResolver is a resolver for resend verify email mutation @@ -27,12 +29,12 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma } params.Email = strings.ToLower(params.Email) - if !utils.IsValidEmail(params.Email) { + if !validators.IsValidEmail(params.Email) { log.Debug("Invalid email: ", params.Email) return res, fmt.Errorf("invalid email") } - if !utils.IsValidVerificationIdentifier(params.Identifier) { + if !validators.IsValidVerificationIdentifier(params.Identifier) { log.Debug("Invalid verification identifier: ", params.Identifier) return res, fmt.Errorf("invalid identifier") } @@ -49,7 +51,7 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma log.Debug("Failed to delete verification request: ", err) } - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) _, nonceHash, err := utils.GenerateNonce() if err != nil { log.Debug("Failed to generate nonce: ", err) diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go index b31af17..9defd06 100644 --- a/server/resolvers/reset_password.go +++ b/server/resolvers/reset_password.go @@ -13,8 +13,10 @@ import ( "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // ResetPasswordResolver is a resolver for reset password mutation @@ -48,13 +50,13 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) return res, fmt.Errorf(`passwords don't match`) } - if !utils.IsValidPassword(params.Password) { + if !validators.IsValidPassword(params.Password) { log.Debug("Invalid password") return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`) } // verify if token exists in db - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { log.Debug("Failed to parse token: ", err) diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index fc3d94f..f820fb6 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -16,8 +16,10 @@ import ( "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // SignupResolver is a resolver for signup mutation @@ -56,14 +58,14 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR return res, fmt.Errorf(`password and confirm password does not match`) } - if !utils.IsValidPassword(params.Password) { + if !validators.IsValidPassword(params.Password) { log.Debug("Invalid password") return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`) } params.Email = strings.ToLower(params.Email) - if !utils.IsValidEmail(params.Email) { + if !validators.IsValidEmail(params.Email) { log.Debug("Invalid email: ", params.Email) return res, fmt.Errorf(`invalid email address`) } @@ -95,7 +97,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR log.Debug("Error getting roles: ", err) return res, err } - if !utils.IsValidRoles(roles, params.Roles) { + if !validators.IsValidRoles(roles, params.Roles) { log.Debug("Invalid roles: ", params.Roles) return res, fmt.Errorf(`invalid roles`) } else { @@ -168,7 +170,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR roles := strings.Split(user.Roles, ",") userToReturn := user.AsAPIUser() - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) if !isEmailVerificationDisabled { // insert verification request _, nonceHash, err := utils.GenerateNonce() @@ -177,7 +179,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR return res, err } verificationType := constants.VerificationTypeBasicAuthSignup - redirectURL := utils.GetAppURL(gc) + redirectURL := parsers.GetAppURL(gc) if params.RedirectURI != nil { redirectURL = *params.RedirectURI } diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index 6d17be3..9a00276 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -16,8 +16,10 @@ import ( "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" "golang.org/x/crypto/bcrypt" ) @@ -121,14 +123,14 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.Email != nil && user.Email != *params.Email { // check if valid email - if !utils.IsValidEmail(*params.Email) { + if !validators.IsValidEmail(*params.Email) { log.Debug("Failed to validate email: ", *params.Email) return res, fmt.Errorf("invalid email address") } newEmail := strings.ToLower(*params.Email) // check if valid email - if !utils.IsValidEmail(newEmail) { + if !validators.IsValidEmail(newEmail) { log.Debug("Failed to validate new email: ", newEmail) return res, fmt.Errorf("invalid new email address") } @@ -150,7 +152,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) return res, err } if !isEmailVerificationDisabled { - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) user.EmailVerifiedAt = nil hasEmailChanged = true // insert verification request @@ -160,7 +162,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) return res, err } verificationType := constants.VerificationTypeUpdateEmail - redirectURL := utils.GetAppURL(gc) + redirectURL := parsers.GetAppURL(gc) verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) if err != nil { log.Debug("Failed to create verification token: ", err) diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index 246d38a..5b90ddf 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -14,8 +14,10 @@ import ( "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" ) // UpdateUserResolver is a resolver for update user mutation @@ -97,7 +99,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod if params.Email != nil && user.Email != *params.Email { // check if valid email - if !utils.IsValidEmail(*params.Email) { + if !validators.IsValidEmail(*params.Email) { log.Debug("Invalid email: ", *params.Email) return res, fmt.Errorf("invalid email address") } @@ -113,7 +115,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod // TODO figure out how to do this go memorystore.Provider.DeleteAllUserSession(user.ID) - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) user.Email = newEmail user.EmailVerifiedAt = nil // insert verification request @@ -123,7 +125,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod return res, err } verificationType := constants.VerificationTypeUpdateEmail - redirectURL := utils.GetAppURL(gc) + redirectURL := parsers.GetAppURL(gc) verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) if err != nil { log.Debug("Failed to create verification token: ", err) @@ -163,12 +165,12 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod log.Debug("Error getting protected roles: ", err) } - if !utils.IsValidRoles(inputRoles, append([]string{}, append(roles, protectedRoles...)...)) { + if !validators.IsValidRoles(inputRoles, append([]string{}, append(roles, protectedRoles...)...)) { log.Debug("Invalid roles: ", params.Roles) return res, fmt.Errorf("invalid list of roles") } - if !utils.IsStringArrayEqual(inputRoles, currentRoles) { + if !validators.IsStringArrayEqual(inputRoles, currentRoles) { rolesToSave = strings.Join(inputRoles, ",") } diff --git a/server/resolvers/validate_jwt_token.go b/server/resolvers/validate_jwt_token.go index eda7918..1efdad5 100644 --- a/server/resolvers/validate_jwt_token.go +++ b/server/resolvers/validate_jwt_token.go @@ -11,6 +11,7 @@ import ( "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" ) @@ -49,7 +50,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken userID = savedSessionSplit[1] } - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) var claimRoles []string var claims jwt.MapClaims diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index e44b7dd..3c1d9d6 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -13,6 +13,7 @@ import ( "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" ) @@ -34,7 +35,7 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m } // verify if token exists in db - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { log.Debug("Failed to parse token: ", err) diff --git a/server/test/urls_test.go b/server/test/urls_test.go index 2f2fbcd..9ec5119 100644 --- a/server/test/urls_test.go +++ b/server/test/urls_test.go @@ -3,6 +3,7 @@ package test import ( "testing" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/utils" "github.com/stretchr/testify/assert" ) @@ -10,7 +11,7 @@ import ( func TestGetHostName(t *testing.T) { url := "http://test.herokuapp.com:80" - host, port := utils.GetHostParts(url) + host, port := parsers.GetHostParts(url) expectedHost := "test.herokuapp.com" assert.Equal(t, host, expectedHost, "hostname should be equal") diff --git a/server/test/validator_test.go b/server/test/validator_test.go index f24faf9..037673b 100644 --- a/server/test/validator_test.go +++ b/server/test/validator_test.go @@ -6,6 +6,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/utils" + "github.com/authorizerdev/authorizer/server/validators" "github.com/stretchr/testify/assert" ) @@ -14,24 +15,24 @@ func TestIsValidEmail(t *testing.T) { invalidEmail1 := "lakhan" invalidEmail2 := "lakhan.me" - assert.True(t, utils.IsValidEmail(validEmail), "it should be valid email") - assert.False(t, utils.IsValidEmail(invalidEmail1), "it should be invalid email") - assert.False(t, utils.IsValidEmail(invalidEmail2), "it should be invalid email") + assert.True(t, validators.IsValidEmail(validEmail), "it should be valid email") + assert.False(t, validators.IsValidEmail(invalidEmail1), "it should be invalid email") + assert.False(t, validators.IsValidEmail(invalidEmail2), "it should be invalid email") } func TestIsValidOrigin(t *testing.T) { // don't use portocal(http/https) for ALLOWED_ORIGINS while testing, // as we trim them off while running the main function memorystore.Provider.UpdateEnvVariable(constants.SliceStoreIdentifier, constants.EnvKeyAllowedOrigins, []string{"localhost:8080", "*.google.com", "*.google.in", "*abc.*"}) - assert.False(t, utils.IsValidOrigin("http://myapp.com"), "it should be invalid origin") - assert.False(t, utils.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin") - assert.True(t, utils.IsValidOrigin("http://app.google.com"), "it should be valid origin") - assert.False(t, utils.IsValidOrigin("http://app.google.ind"), "it should be invalid origin") - assert.True(t, utils.IsValidOrigin("http://app.google.in"), "it should be valid origin") - assert.True(t, utils.IsValidOrigin("http://xyx.abc.com"), "it should be valid origin") - assert.True(t, utils.IsValidOrigin("http://xyx.abc.in"), "it should be valid origin") - assert.True(t, utils.IsValidOrigin("http://xyxabc.in"), "it should be valid origin") - assert.True(t, utils.IsValidOrigin("http://localhost:8080"), "it should be valid origin") + assert.False(t, validators.IsValidOrigin("http://myapp.com"), "it should be invalid origin") + assert.False(t, validators.IsValidOrigin("http://appgoogle.com"), "it should be invalid origin") + assert.True(t, validators.IsValidOrigin("http://app.google.com"), "it should be valid origin") + assert.False(t, validators.IsValidOrigin("http://app.google.ind"), "it should be invalid origin") + assert.True(t, validators.IsValidOrigin("http://app.google.in"), "it should be valid origin") + assert.True(t, validators.IsValidOrigin("http://xyx.abc.com"), "it should be valid origin") + assert.True(t, validators.IsValidOrigin("http://xyx.abc.in"), "it should be valid origin") + assert.True(t, validators.IsValidOrigin("http://xyxabc.in"), "it should be valid origin") + assert.True(t, validators.IsValidOrigin("http://localhost:8080"), "it should be valid origin") memorystore.Provider.UpdateEnvVariable(constants.SliceStoreIdentifier, constants.EnvKeyAllowedOrigins, []string{"*"}) } diff --git a/server/token/auth_token.go b/server/token/auth_token.go index aea5af2..a977c41 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -17,6 +17,7 @@ import ( "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/utils" ) @@ -66,7 +67,7 @@ func CreateSessionToken(user models.User, nonce string, roles, scope []string) ( // CreateAuthToken creates a new auth token when userlogs in func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string) (*Token, error) { - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) nonce := uuid.New().String() _, fingerPrintHash, err := CreateSessionToken(user, nonce, roles, scope) if err != nil { @@ -206,7 +207,7 @@ func ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interf nonce := savedSessionSplit[0] userID := savedSessionSplit[1] - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) res, err = ParseJWTToken(accessToken, hostname, nonce, userID) if err != nil { return res, err @@ -236,7 +237,7 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte nonce := savedSessionSplit[0] userID := savedSessionSplit[1] - hostname := utils.GetHost(gc) + hostname := parsers.GetHost(gc) res, err = ParseJWTToken(refreshToken, hostname, nonce, userID) if err != nil { return res, err diff --git a/server/utils/meta.go b/server/utils/meta.go deleted file mode 100644 index 760c126..0000000 --- a/server/utils/meta.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/graph/model" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// GetMeta helps in getting the meta data about the deployment from EnvData -func GetMetaInfo() model.Meta { - return model.Meta{ - Version: constants.VERSION, - ClientID: memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID), - IsGoogleLoginEnabled: memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) != "" && memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) != "", - IsGithubLoginEnabled: memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) != "" && memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) != "", - IsFacebookLoginEnabled: memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) != "" && memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) != "", - IsBasicAuthenticationEnabled: !memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication), - IsEmailVerificationEnabled: !memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification), - IsMagicLinkLoginEnabled: !memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin), - IsSignUpEnabled: !memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp), - } -} diff --git a/server/utils/validator.go b/server/utils/validator.go deleted file mode 100644 index ec6258a..0000000 --- a/server/utils/validator.go +++ /dev/null @@ -1,120 +0,0 @@ -package utils - -import ( - "net/mail" - "regexp" - "strings" - - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/memorystore" -) - -// IsValidEmail validates email -func IsValidEmail(email string) bool { - _, err := mail.ParseAddress(email) - return err == nil -} - -// IsValidOrigin validates origin based on ALLOWED_ORIGINS -func IsValidOrigin(url string) bool { - allowedOrigins := memorystore.Provider.GetSliceStoreEnvVariable(constants.EnvKeyAllowedOrigins) - if len(allowedOrigins) == 1 && allowedOrigins[0] == "*" { - return true - } - - hasValidURL := false - hostName, port := GetHostParts(url) - currentOrigin := hostName + ":" + port - - for _, origin := range allowedOrigins { - replacedString := origin - // if has regex whitelisted domains - if strings.Contains(origin, "*") { - replacedString = strings.Replace(origin, ".", "\\.", -1) - replacedString = strings.Replace(replacedString, "*", ".*", -1) - - if strings.HasPrefix(replacedString, ".*") { - replacedString += "\\b" - } - - if strings.HasSuffix(replacedString, ".*") { - replacedString = "\\b" + replacedString - } - } - - if matched, _ := regexp.MatchString(replacedString, currentOrigin); matched { - hasValidURL = true - break - } - } - - return hasValidURL -} - -// IsValidRoles validates roles -func IsValidRoles(userRoles []string, roles []string) bool { - valid := true - for _, userRole := range userRoles { - if !StringSliceContains(roles, userRole) { - valid = false - break - } - } - - return valid -} - -// IsValidVerificationIdentifier validates verification identifier that is used to identify -// the type of verification request -func IsValidVerificationIdentifier(identifier string) bool { - if identifier != constants.VerificationTypeBasicAuthSignup && identifier != constants.VerificationTypeForgotPassword && identifier != constants.VerificationTypeUpdateEmail { - return false - } - return true -} - -// IsStringArrayEqual validates if string array are equal. -// This does check if the order is same -func IsStringArrayEqual(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -// ValidatePassword to validate the password against the following policy -// min char length: 6 -// max char length: 36 -// at least one upper case letter -// at least one lower case letter -// at least one digit -// at least one special character -func IsValidPassword(password string) bool { - if len(password) < 6 || len(password) > 36 { - return false - } - - hasUpperCase := false - hasLowerCase := false - hasDigit := false - hasSpecialChar := false - - for _, char := range password { - if char >= 'A' && char <= 'Z' { - hasUpperCase = true - } else if char >= 'a' && char <= 'z' { - hasLowerCase = true - } else if char >= '0' && char <= '9' { - hasDigit = true - } else { - hasSpecialChar = true - } - } - - return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar -} diff --git a/server/validators/common.go b/server/validators/common.go new file mode 100644 index 0000000..348df00 --- /dev/null +++ b/server/validators/common.go @@ -0,0 +1,15 @@ +package validators + +// IsStringArrayEqual validates if string array are equal. +// This does check if the order is same +func IsStringArrayEqual(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} diff --git a/server/validators/email.go b/server/validators/email.go new file mode 100644 index 0000000..deb98ed --- /dev/null +++ b/server/validators/email.go @@ -0,0 +1,9 @@ +package validators + +import "net/mail" + +// IsValidEmail validates email +func IsValidEmail(email string) bool { + _, err := mail.ParseAddress(email) + return err == nil +} diff --git a/server/validators/password.go b/server/validators/password.go new file mode 100644 index 0000000..7925dab --- /dev/null +++ b/server/validators/password.go @@ -0,0 +1,33 @@ +package validators + +// ValidatePassword to validate the password against the following policy +// min char length: 6 +// max char length: 36 +// at least one upper case letter +// at least one lower case letter +// at least one digit +// at least one special character +func IsValidPassword(password string) bool { + if len(password) < 6 || len(password) > 36 { + return false + } + + hasUpperCase := false + hasLowerCase := false + hasDigit := false + hasSpecialChar := false + + for _, char := range password { + if char >= 'A' && char <= 'Z' { + hasUpperCase = true + } else if char >= 'a' && char <= 'z' { + hasLowerCase = true + } else if char >= '0' && char <= '9' { + hasDigit = true + } else { + hasSpecialChar = true + } + } + + return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar +} diff --git a/server/validators/roles.go b/server/validators/roles.go new file mode 100644 index 0000000..9a43a51 --- /dev/null +++ b/server/validators/roles.go @@ -0,0 +1,16 @@ +package validators + +import "github.com/authorizerdev/authorizer/server/utils" + +// IsValidRoles validates roles +func IsValidRoles(userRoles []string, roles []string) bool { + valid := true + for _, userRole := range userRoles { + if !utils.StringSliceContains(roles, userRole) { + valid = false + break + } + } + + return valid +} diff --git a/server/validators/url.go b/server/validators/url.go new file mode 100644 index 0000000..bf434e3 --- /dev/null +++ b/server/validators/url.go @@ -0,0 +1,49 @@ +package validators + +import ( + "regexp" + "strings" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" +) + +// IsValidOrigin validates origin based on ALLOWED_ORIGINS +func IsValidOrigin(url string) bool { + allowedOrigins, err := memorystore.Provider.GetSliceStoreEnvVariable(constants.EnvKeyAllowedOrigins) + if err != nil { + allowedOrigins = []string{"*"} + } + if len(allowedOrigins) == 1 && allowedOrigins[0] == "*" { + return true + } + + hasValidURL := false + hostName, port := parsers.GetHostParts(url) + currentOrigin := hostName + ":" + port + + for _, origin := range allowedOrigins { + replacedString := origin + // if has regex whitelisted domains + if strings.Contains(origin, "*") { + replacedString = strings.Replace(origin, ".", "\\.", -1) + replacedString = strings.Replace(replacedString, "*", ".*", -1) + + if strings.HasPrefix(replacedString, ".*") { + replacedString += "\\b" + } + + if strings.HasSuffix(replacedString, ".*") { + replacedString = "\\b" + replacedString + } + } + + if matched, _ := regexp.MatchString(replacedString, currentOrigin); matched { + hasValidURL = true + break + } + } + + return hasValidURL +} diff --git a/server/validators/verification_requests.go b/server/validators/verification_requests.go new file mode 100644 index 0000000..48c9183 --- /dev/null +++ b/server/validators/verification_requests.go @@ -0,0 +1,12 @@ +package validators + +import "github.com/authorizerdev/authorizer/server/constants" + +// IsValidVerificationIdentifier validates verification identifier that is used to identify +// the type of verification request +func IsValidVerificationIdentifier(identifier string) bool { + if identifier != constants.VerificationTypeBasicAuthSignup && identifier != constants.VerificationTypeForgotPassword && identifier != constants.VerificationTypeUpdateEmail { + return false + } + return true +}