This commit is contained in:
Untone 2023-12-04 16:26:57 +03:00
commit a3b240c571
15 changed files with 298 additions and 102 deletions

25
app/package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "^1.1.15", "@authorizerdev/authorizer-react": "^1.1.19",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",
@ -27,9 +27,9 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-js": { "node_modules/@authorizerdev/authorizer-js": {
"version": "1.2.17", "version": "1.2.18",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.17.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.18.tgz",
"integrity": "sha512-aF/lu9wZR7TBRaRMAes/hy1q8cZzz5Zo60QLU9Iu09sqnhliHJCp5wSkjsVH+V4ER9i7bmJ2HNABTmOdluxj3A==", "integrity": "sha512-9j5U/4lqaaEcG78Zli+TtLJ0migSKhFwnXXunulAGTZOzQSTCJ/CSSPip5wWNa/Mkr6gdEMwk1HYfhIdk2A9Mg==",
"dependencies": { "dependencies": {
"cross-fetch": "^3.1.5" "cross-fetch": "^3.1.5"
}, },
@ -41,11 +41,12 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-react": { "node_modules/@authorizerdev/authorizer-react": {
"version": "1.1.15", "version": "1.1.19",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.15.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.19.tgz",
"integrity": "sha512-Y71qC4GUAHL0QCNj5mVv0Jwv1cIg4Y0yXRiOeYV21C1NMleyLRXgw4qzJ/Vk8rmXsxqSHmr8SGrwOLcSKA2oMA==", "integrity": "sha512-hbId4mtzeWke1uUFAZrPwT45UmxgTp0QHAAsQvl/I0+mgoCJlJdAnUBCiJD6d5lVHJk41nx/ePYG4rw2Aj6HTw==",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-js": "^1.2.17" "@authorizerdev/authorizer-js": "^1.2.18",
"validator": "^13.11.0"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
@ -847,6 +848,14 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"node_modules/validator": {
"version": "13.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/value-equal": { "node_modules/value-equal": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",

View File

@ -12,7 +12,7 @@
"author": "Lakhan Samani", "author": "Lakhan Samani",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "^1.1.15", "@authorizerdev/authorizer-react": "^1.1.19",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",

View File

@ -32,6 +32,7 @@ const FooterContent = styled.div`
export default function Login({ urlProps }: { urlProps: Record<string, any> }) { export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
const { config } = useAuthorizer(); const { config } = useAuthorizer();
const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN); const [view, setView] = useState<VIEW_TYPES>(VIEW_TYPES.LOGIN);
const isBasicAuth = config.is_basic_authentication_enabled;
return ( return (
<Fragment> <Fragment>
{view === VIEW_TYPES.LOGIN && ( {view === VIEW_TYPES.LOGIN && (
@ -39,22 +40,26 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
<h1 style={{ textAlign: 'center' }}>Login</h1> <h1 style={{ textAlign: 'center' }}>Login</h1>
<AuthorizerSocialLogin urlProps={urlProps} /> <AuthorizerSocialLogin urlProps={urlProps} />
<br /> <br />
{config.is_basic_authentication_enabled && {(config.is_basic_authentication_enabled ||
config.is_mobile_basic_authentication_enabled) &&
!config.is_magic_link_login_enabled && ( !config.is_magic_link_login_enabled && (
<AuthorizerBasicAuthLogin urlProps={urlProps} /> <AuthorizerBasicAuthLogin urlProps={urlProps} />
)} )}
{config.is_magic_link_login_enabled && ( {config.is_magic_link_login_enabled && (
<AuthorizerMagicLinkLogin urlProps={urlProps} /> <AuthorizerMagicLinkLogin urlProps={urlProps} />
)} )}
<Footer> {(config.is_basic_authentication_enabled ||
<Link config.is_mobile_basic_authentication_enabled) && (
to="#" <Footer>
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)} <Link
style={{ marginBottom: 10 }} to="#"
> onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
Forgot Password? style={{ marginBottom: 10 }}
</Link> >
</Footer> Forgot Password?
</Link>
</Footer>
)}
</Fragment> </Fragment>
)} )}
{view === VIEW_TYPES.FORGOT_PASSWORD && ( {view === VIEW_TYPES.FORGOT_PASSWORD && (
@ -81,7 +86,7 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
!config.is_magic_link_login_enabled && !config.is_magic_link_login_enabled &&
config.is_sign_up_enabled && ( config.is_sign_up_enabled && (
<FooterContent> <FooterContent>
Don't have an account? <Link to="/app/signup"> Sign Up</Link> Don't have an account? &nbsp; <Link to="/app/signup"> Sign Up</Link>
</FooterContent> </FooterContent>
)} )}
</Fragment> </Fragment>

View File

@ -2,19 +2,20 @@
# yarn lockfile v1 # yarn lockfile v1
"@authorizerdev/authorizer-js@^1.2.17": "@authorizerdev/authorizer-js@^1.2.18":
version "1.2.17" version "1.2.18"
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.17.tgz" resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.18.tgz"
integrity sha512-aF/lu9wZR7TBRaRMAes/hy1q8cZzz5Zo60QLU9Iu09sqnhliHJCp5wSkjsVH+V4ER9i7bmJ2HNABTmOdluxj3A== integrity sha512-9j5U/4lqaaEcG78Zli+TtLJ0migSKhFwnXXunulAGTZOzQSTCJ/CSSPip5wWNa/Mkr6gdEMwk1HYfhIdk2A9Mg==
dependencies: dependencies:
cross-fetch "^3.1.5" cross-fetch "^3.1.5"
"@authorizerdev/authorizer-react@^1.1.15": "@authorizerdev/authorizer-react@^1.1.19":
version "1.1.15" version "1.1.19"
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.15.tgz" resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.19.tgz"
integrity sha512-Y71qC4GUAHL0QCNj5mVv0Jwv1cIg4Y0yXRiOeYV21C1NMleyLRXgw4qzJ/Vk8rmXsxqSHmr8SGrwOLcSKA2oMA== integrity sha512-hbId4mtzeWke1uUFAZrPwT45UmxgTp0QHAAsQvl/I0+mgoCJlJdAnUBCiJD6d5lVHJk41nx/ePYG4rw2Aj6HTw==
dependencies: dependencies:
"@authorizerdev/authorizer-js" "^1.2.17" "@authorizerdev/authorizer-js" "^1.2.18"
validator "^13.11.0"
"@babel/code-frame@^7.22.13": "@babel/code-frame@^7.22.13":
version "7.22.13" version "7.22.13"
@ -594,6 +595,11 @@ typescript@^4.3.5:
resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz" resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz"
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
validator@^13.11.0:
version "13.11.0"
resolved "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz"
integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
value-equal@^1.0.1: value-equal@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz" resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"

View File

@ -108,11 +108,10 @@ const Features = ({ variables, setVariables }: any) => {
/> />
</Flex> </Flex>
</Flex> </Flex>
{/** TODO enable after final release */} {!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
{/* {!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
<Flex alignItems="center"> <Flex alignItems="center">
<Flex w="100%" alignItems="baseline" flexDir="column"> <Flex w="100%" alignItems="baseline" flexDir="column">
<Text fontSize="sm">TOTP:</Text> <Text fontSize="sm">Time Based OTP (TOTP):</Text>
<Text fontSize="x-small">Note: to enable totp mfa</Text> <Text fontSize="x-small">Note: to enable totp mfa</Text>
</Flex> </Flex>
@ -125,7 +124,7 @@ const Features = ({ variables, setVariables }: any) => {
/> />
</Flex> </Flex>
</Flex> </Flex>
)} */} )}
{!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && ( {!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION && (
<Flex alignItems="center"> <Flex alignItems="center">
<Flex w="100%" alignItems="baseline" flexDir="column"> <Flex w="100%" alignItems="baseline" flexDir="column">

View File

@ -162,22 +162,24 @@ type ComplexityRoot struct {
} }
Meta struct { Meta struct {
ClientID func(childComplexity int) int ClientID func(childComplexity int) int
IsAppleLoginEnabled func(childComplexity int) int IsAppleLoginEnabled func(childComplexity int) int
IsBasicAuthenticationEnabled func(childComplexity int) int IsBasicAuthenticationEnabled func(childComplexity int) int
IsEmailVerificationEnabled func(childComplexity int) int IsEmailVerificationEnabled func(childComplexity int) int
IsFacebookLoginEnabled func(childComplexity int) int IsFacebookLoginEnabled func(childComplexity int) int
IsGithubLoginEnabled func(childComplexity int) int IsGithubLoginEnabled func(childComplexity int) int
IsGoogleLoginEnabled func(childComplexity int) int IsGoogleLoginEnabled func(childComplexity int) int
IsLinkedinLoginEnabled func(childComplexity int) int IsLinkedinLoginEnabled func(childComplexity int) int
IsMagicLinkLoginEnabled func(childComplexity int) int IsMagicLinkLoginEnabled func(childComplexity int) int
IsMicrosoftLoginEnabled func(childComplexity int) int IsMicrosoftLoginEnabled func(childComplexity int) int
IsMultiFactorAuthEnabled func(childComplexity int) int IsMobileBasicAuthenticationEnabled func(childComplexity int) int
IsSignUpEnabled func(childComplexity int) int IsMultiFactorAuthEnabled func(childComplexity int) int
IsStrongPasswordEnabled func(childComplexity int) int IsPhoneVerificationEnabled func(childComplexity int) int
IsTwitchLoginEnabled func(childComplexity int) int IsSignUpEnabled func(childComplexity int) int
IsTwitterLoginEnabled func(childComplexity int) int IsStrongPasswordEnabled func(childComplexity int) int
Version func(childComplexity int) int IsTwitchLoginEnabled func(childComplexity int) int
IsTwitterLoginEnabled func(childComplexity int) int
Version func(childComplexity int) int
} }
Mutation struct { Mutation struct {
@ -1142,6 +1144,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Meta.IsMicrosoftLoginEnabled(childComplexity), true return e.complexity.Meta.IsMicrosoftLoginEnabled(childComplexity), true
case "Meta.is_mobile_basic_authentication_enabled":
if e.complexity.Meta.IsMobileBasicAuthenticationEnabled == nil {
break
}
return e.complexity.Meta.IsMobileBasicAuthenticationEnabled(childComplexity), true
case "Meta.is_multi_factor_auth_enabled": case "Meta.is_multi_factor_auth_enabled":
if e.complexity.Meta.IsMultiFactorAuthEnabled == nil { if e.complexity.Meta.IsMultiFactorAuthEnabled == nil {
break break
@ -1149,6 +1158,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Meta.IsMultiFactorAuthEnabled(childComplexity), true return e.complexity.Meta.IsMultiFactorAuthEnabled(childComplexity), true
case "Meta.is_phone_verification_enabled":
if e.complexity.Meta.IsPhoneVerificationEnabled == nil {
break
}
return e.complexity.Meta.IsPhoneVerificationEnabled(childComplexity), true
case "Meta.is_sign_up_enabled": case "Meta.is_sign_up_enabled":
if e.complexity.Meta.IsSignUpEnabled == nil { if e.complexity.Meta.IsSignUpEnabled == nil {
break break
@ -2355,6 +2371,8 @@ type Meta {
is_sign_up_enabled: Boolean! is_sign_up_enabled: Boolean!
is_strong_password_enabled: Boolean! is_strong_password_enabled: Boolean!
is_multi_factor_auth_enabled: Boolean! is_multi_factor_auth_enabled: Boolean!
is_mobile_basic_authentication_enabled: Boolean!
is_phone_verification_enabled: Boolean!
} }
type User { type User {
@ -8373,6 +8391,94 @@ func (ec *executionContext) fieldContext_Meta_is_multi_factor_auth_enabled(ctx c
return fc, nil return fc, nil
} }
func (ec *executionContext) _Meta_is_mobile_basic_authentication_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Meta_is_mobile_basic_authentication_enabled(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.IsMobileBasicAuthenticationEnabled, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Meta_is_mobile_basic_authentication_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Meta",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Boolean does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Meta_is_phone_verification_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Meta_is_phone_verification_enabled(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.IsPhoneVerificationEnabled, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Meta_is_phone_verification_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Meta",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Boolean does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_signup(ctx, field) fc, err := ec.fieldContext_Mutation_signup(ctx, field)
if err != nil { if err != nil {
@ -10653,6 +10759,10 @@ func (ec *executionContext) fieldContext_Query_meta(ctx context.Context, field g
return ec.fieldContext_Meta_is_strong_password_enabled(ctx, field) return ec.fieldContext_Meta_is_strong_password_enabled(ctx, field)
case "is_multi_factor_auth_enabled": case "is_multi_factor_auth_enabled":
return ec.fieldContext_Meta_is_multi_factor_auth_enabled(ctx, field) return ec.fieldContext_Meta_is_multi_factor_auth_enabled(ctx, field)
case "is_mobile_basic_authentication_enabled":
return ec.fieldContext_Meta_is_mobile_basic_authentication_enabled(ctx, field)
case "is_phone_verification_enabled":
return ec.fieldContext_Meta_is_phone_verification_enabled(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type Meta", field.Name) return nil, fmt.Errorf("no field named %q was found under type Meta", field.Name)
}, },
@ -19594,6 +19704,16 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ out.Invalids++
} }
case "is_mobile_basic_authentication_enabled":
out.Values[i] = ec._Meta_is_mobile_basic_authentication_enabled(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "is_phone_verification_enabled":
out.Values[i] = ec._Meta_is_phone_verification_enabled(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }

View File

@ -191,22 +191,24 @@ type MagicLinkLoginInput struct {
} }
type Meta struct { type Meta struct {
Version string `json:"version"` Version string `json:"version"`
ClientID string `json:"client_id"` ClientID string `json:"client_id"`
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"` IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"` IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
IsGithubLoginEnabled bool `json:"is_github_login_enabled"` IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"` IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"` IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"` IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"` IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"` IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"`
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"` IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"` IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"` IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
IsSignUpEnabled bool `json:"is_sign_up_enabled"` IsSignUpEnabled bool `json:"is_sign_up_enabled"`
IsStrongPasswordEnabled bool `json:"is_strong_password_enabled"` IsStrongPasswordEnabled bool `json:"is_strong_password_enabled"`
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"` IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
IsMobileBasicAuthenticationEnabled bool `json:"is_mobile_basic_authentication_enabled"`
IsPhoneVerificationEnabled bool `json:"is_phone_verification_enabled"`
} }
type MobileLoginInput struct { type MobileLoginInput struct {

View File

@ -29,6 +29,8 @@ type Meta {
is_sign_up_enabled: Boolean! is_sign_up_enabled: Boolean!
is_strong_password_enabled: Boolean! is_strong_password_enabled: Boolean!
is_multi_factor_auth_enabled: Boolean! is_multi_factor_auth_enabled: Boolean!
is_mobile_basic_authentication_enabled: Boolean!
is_phone_verification_enabled: Boolean!
} }
type User { type User {

View File

@ -74,7 +74,13 @@ func VerifyEmailHandler() gin.HandlerFunc {
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
isSignUp = true isSignUp = true
db.Provider.UpdateUser(c, user) user, err = db.Provider.UpdateUser(c, user)
if err != nil {
log.Debug("Error updating user: ", err)
errorRes["error"] = err.Error()
utils.HandleRedirectORJsonResponse(c, http.StatusBadRequest, errorRes, generateRedirectURL(redirectURL, errorRes))
return
}
} }
// delete from verification table // delete from verification table
db.Provider.DeleteVerificationRequest(c, verificationRequest) db.Provider.DeleteVerificationRequest(c, verificationRequest)

View File

@ -78,7 +78,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
} }
if err != nil { if err != nil {
log.Debug("Failed to get user: ", err) log.Debug("Failed to get user: ", err)
return res, fmt.Errorf(`bad user credentials`) return res, fmt.Errorf(`user not found`)
} }
if user.RevokedTimestamp != nil { if user.RevokedTimestamp != nil {
log.Debug("User access is revoked") log.Debug("User access is revoked")

View File

@ -106,6 +106,16 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
log.Debug("Failed to get Disable Basic Authentication from environment variable", err) log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
isBasicAuthDisabled = true isBasicAuthDisabled = true
} }
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
if err != nil {
log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
isMobileBasicAuthDisabled = true
}
isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
if err != nil {
log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
isMobileVerificationDisabled = true
}
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
if err != nil { if err != nil {
@ -138,21 +148,23 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
} }
metaInfo := model.Meta{ metaInfo := model.Meta{
Version: constants.VERSION, Version: constants.VERSION,
ClientID: clientID, ClientID: clientID,
IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "", IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "",
IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "", IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "",
IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "", IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "",
IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "", IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "",
IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "", IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "",
IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "", IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "",
IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "", IsMicrosoftLoginEnabled: microsoftClientID != "" && microsoftClientSecret != "",
IsBasicAuthenticationEnabled: !isBasicAuthDisabled, IsBasicAuthenticationEnabled: !isBasicAuthDisabled,
IsEmailVerificationEnabled: !isEmailVerificationDisabled, IsEmailVerificationEnabled: !isEmailVerificationDisabled,
IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled, IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled,
IsSignUpEnabled: !isSignUpDisabled, IsSignUpEnabled: !isSignUpDisabled,
IsStrongPasswordEnabled: !isStrongPasswordDisabled, IsStrongPasswordEnabled: !isStrongPasswordDisabled,
IsMultiFactorAuthEnabled: !isMultiFactorAuthenticationEnabled, IsMultiFactorAuthEnabled: !isMultiFactorAuthenticationEnabled,
IsMobileBasicAuthenticationEnabled: !isMobileBasicAuthDisabled,
IsPhoneVerificationEnabled: !isMobileVerificationDisabled,
} }
return &metaInfo, nil return &metaInfo, nil
} }

View File

@ -73,7 +73,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
} }
isEmailSignup := email != "" isEmailSignup := email != ""
isMobileSignup := phoneNumber != "" isMobileSignup := phoneNumber != ""
if isBasicAuthDisabled { if isBasicAuthDisabled && isEmailSignup {
log.Debug("Basic authentication is disabled") log.Debug("Basic authentication is disabled")
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
@ -222,12 +222,12 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
log.Debug("Error getting email verification disabled: ", err) log.Debug("Error getting email verification disabled: ", err)
isEmailVerificationDisabled = true isEmailVerificationDisabled = true
} }
if isEmailVerificationDisabled { if isEmailVerificationDisabled && isEmailSignup {
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
} }
disablePhoneVerification, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification) disablePhoneVerification, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
if disablePhoneVerification { if disablePhoneVerification && isMobileSignup {
now := time.Now().Unix() now := time.Now().Unix()
user.PhoneNumberVerifiedAt = &now user.PhoneNumberVerifiedAt = &now
} }

View File

@ -36,24 +36,29 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
return res, fmt.Errorf(`invalid session: %s`, err.Error()) return res, fmt.Errorf(`invalid session: %s`, err.Error())
} }
if refs.StringValue(params.Email) == "" && refs.StringValue(params.PhoneNumber) == "" { email := strings.TrimSpace(refs.StringValue(params.Email))
phoneNumber := strings.TrimSpace(refs.StringValue(params.PhoneNumber))
if email == "" && phoneNumber == "" {
log.Debug("Email or phone number is required") log.Debug("Email or phone number is required")
return res, fmt.Errorf(`email or phone_number is required`) return res, fmt.Errorf(`email or phone number is required`)
}
currentField := models.FieldNameEmail
if refs.StringValue(params.Email) == "" {
currentField = models.FieldNamePhoneNumber
} }
isEmailVerification := email != ""
isMobileVerification := phoneNumber != ""
// Get user by email or phone number // Get user by email or phone number
var user *models.User var user *models.User
if currentField == models.FieldNameEmail { if isEmailVerification {
user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email)) user, err = db.Provider.GetUserByEmail(ctx, refs.StringValue(params.Email))
if err != nil {
log.Debug("Failed to get user by email: ", err)
}
} else { } else {
user, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) user, err = db.Provider.GetUserByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
if err != nil {
log.Debug("Failed to get user by phone number: ", err)
}
} }
if user == nil || err != nil { if user == nil || err != nil {
log.Debug("Failed to get user by email or phone number: ", err) return res, fmt.Errorf(`user not found`)
return res, err
} }
// Verify OTP based on TOPT or OTP // Verify OTP based on TOPT or OTP
if refs.BoolValue(params.IsTotp) { if refs.BoolValue(params.IsTotp) {
@ -78,14 +83,19 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
} }
} else { } else {
var otp *models.OTP var otp *models.OTP
if currentField == models.FieldNameEmail { if isEmailVerification {
otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email)) otp, err = db.Provider.GetOTPByEmail(ctx, refs.StringValue(params.Email))
if err != nil {
log.Debug(`Failed to get otp request for email: `, err.Error())
}
} else { } else {
otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber)) otp, err = db.Provider.GetOTPByPhoneNumber(ctx, refs.StringValue(params.PhoneNumber))
if err != nil {
log.Debug(`Failed to get otp request for phone number: `, err.Error())
}
} }
if otp == nil && err != nil { if otp == nil && err != nil {
log.Debugf("Failed to get otp request for %s: %s", currentField, err.Error()) return res, fmt.Errorf(`OTP not found`)
return res, fmt.Errorf(`invalid %s: %s`, currentField, err.Error())
} }
if params.Otp != otp.Otp { if params.Otp != otp.Otp {
log.Debug("Failed to verify otp request: Incorrect value") log.Debug("Failed to verify otp request: Incorrect value")
@ -104,10 +114,26 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
return res, fmt.Errorf(`invalid session: %s`, err.Error()) return res, fmt.Errorf(`invalid session: %s`, err.Error())
} }
isSignUp := user.EmailVerifiedAt == nil && user.PhoneNumberVerifiedAt == nil isSignUp := false
// TODO - Add Login method in DB when we introduce OTP for social media login if user.EmailVerifiedAt == nil && isEmailVerification {
isSignUp = true
now := time.Now().Unix()
user.EmailVerifiedAt = &now
}
if user.PhoneNumberVerifiedAt == nil && isMobileVerification {
isSignUp = true
now := time.Now().Unix()
user.PhoneNumberVerifiedAt = &now
}
if isSignUp {
user, err = db.Provider.UpdateUser(ctx, user)
if err != nil {
log.Debug("Failed to update user: ", err)
return res, err
}
}
loginMethod := constants.AuthRecipeMethodBasicAuth loginMethod := constants.AuthRecipeMethodBasicAuth
if currentField == models.FieldNamePhoneNumber { if isMobileVerification {
loginMethod = constants.AuthRecipeMethodMobileOTP loginMethod = constants.AuthRecipeMethodMobileOTP
} }
roles := strings.Split(user.Roles, ",") roles := strings.Split(user.Roles, ",")

View File

@ -98,12 +98,17 @@ func mobileSingupTest(t *testing.T, s TestSetup) {
}) })
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEmpty(t, otpRes.Message) assert.NotEmpty(t, otpRes.Message)
// Check if phone number is verified
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
assert.NoError(t, err)
assert.NotNil(t, user)
assert.NotNil(t, user.PhoneNumberVerifiedAt)
res, err = resolvers.SignupResolver(ctx, model.SignUpInput{ res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
PhoneNumber: refs.NewStringRef(phoneNumber), PhoneNumber: refs.NewStringRef(phoneNumber),
Password: s.TestInfo.Password, Password: s.TestInfo.Password,
ConfirmPassword: s.TestInfo.Password, ConfirmPassword: s.TestInfo.Password,
}) })
assert.Error(t, err) assert.Error(t, err, "should throw duplicate error")
assert.Nil(t, res) assert.Nil(t, res)
cleanData("1234567890@authorizer.dev") cleanData("1234567890@authorizer.dev")
}) })

View File

@ -35,7 +35,11 @@ func verifyEmailTest(t *testing.T, s TestSetup) {
}) })
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty") assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty")
// Check if phone number is verified
user1, err := db.Provider.GetUserByEmail(ctx, email)
assert.NoError(t, err)
assert.NotNil(t, user1)
assert.NotNil(t, user1.EmailVerifiedAt)
cleanData(email) cleanData(email)
}) })
} }