Merge branch 'main' into fix/role-deletion
This commit is contained in:
commit
e52164665f
16
app/package-lock.json
generated
16
app/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.19",
|
"@authorizerdev/authorizer-react": "^1.2.0",
|
||||||
"@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.18",
|
"version": "2.0.0-beta.3",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.18.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0-beta.3.tgz",
|
||||||
"integrity": "sha512-9j5U/4lqaaEcG78Zli+TtLJ0migSKhFwnXXunulAGTZOzQSTCJ/CSSPip5wWNa/Mkr6gdEMwk1HYfhIdk2A9Mg==",
|
"integrity": "sha512-cEzEVe7AewvOwOwoettiKRCq1e5Y33k9g8fJjqAoe3B/36iNN8wnZ5qgsPPZkqhv+Cvn6huj+YWtRimfVJ6d0w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-fetch": "^3.1.5"
|
"cross-fetch": "^3.1.5"
|
||||||
},
|
},
|
||||||
|
@ -41,11 +41,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "1.1.19",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.19.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.2.0.tgz",
|
||||||
"integrity": "sha512-hbId4mtzeWke1uUFAZrPwT45UmxgTp0QHAAsQvl/I0+mgoCJlJdAnUBCiJD6d5lVHJk41nx/ePYG4rw2Aj6HTw==",
|
"integrity": "sha512-MtunZgh30rzY9jSADVP1DRC4sOBC82zx/yhK8O/1ufOAi7vTDZwPjDHIMrG/xWPNUYTCeFPEKpZlKyB+TH/M1w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^1.2.18",
|
"@authorizerdev/authorizer-js": "^2.0.0-beta.3",
|
||||||
"validator": "^13.11.0"
|
"validator": "^13.11.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.19",
|
"@authorizerdev/authorizer-react": "^1.2.0",
|
||||||
"@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,13 +27,13 @@ export default function App() {
|
||||||
if (redirectURL) {
|
if (redirectURL) {
|
||||||
urlProps.redirectURL = redirectURL;
|
urlProps.redirectURL = redirectURL;
|
||||||
} else {
|
} else {
|
||||||
urlProps.redirectURL = window.location.origin + '/app';
|
urlProps.redirectURL = window.location.href;
|
||||||
}
|
}
|
||||||
const globalState: Record<string, string> = {
|
const globalState: Record<string, string> = {
|
||||||
...window['__authorizer__'],
|
...window['__authorizer__'],
|
||||||
...urlProps,
|
...urlProps,
|
||||||
};
|
};
|
||||||
|
console.log({ globalState });
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -59,7 +59,9 @@ export default function Root({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
let redirectURL = config.redirectURL || '/app';
|
let redirectURL = config.redirectURL || '/app';
|
||||||
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
|
// let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
|
||||||
|
// Note: If OIDC breaks in the future, use the above params
|
||||||
|
let params = `state=${globalState.state}`;
|
||||||
|
|
||||||
if (code !== '') {
|
if (code !== '') {
|
||||||
params += `&code=${code}`;
|
params += `&code=${code}`;
|
||||||
|
|
|
@ -49,17 +49,18 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
<AuthorizerMagicLinkLogin urlProps={urlProps} />
|
||||||
)}
|
)}
|
||||||
{(config.is_basic_authentication_enabled ||
|
{(config.is_basic_authentication_enabled ||
|
||||||
config.is_mobile_basic_authentication_enabled) && (
|
config.is_mobile_basic_authentication_enabled) &&
|
||||||
<Footer>
|
!config.is_magic_link_login_enabled && (
|
||||||
<Link
|
<Footer>
|
||||||
to="#"
|
<Link
|
||||||
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
|
to="#"
|
||||||
style={{ marginBottom: 10 }}
|
onClick={() => setView(VIEW_TYPES.FORGOT_PASSWORD)}
|
||||||
>
|
style={{ marginBottom: 10 }}
|
||||||
Forgot Password?
|
>
|
||||||
</Link>
|
Forgot Password?
|
||||||
</Footer>
|
</Link>
|
||||||
)}
|
</Footer>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
||||||
|
@ -70,6 +71,9 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
...urlProps,
|
...urlProps,
|
||||||
redirect_uri: `${window.location.origin}/app/reset-password`,
|
redirect_uri: `${window.location.origin}/app/reset-password`,
|
||||||
}}
|
}}
|
||||||
|
onPasswordReset={() => {
|
||||||
|
setView(VIEW_TYPES.LOGIN);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Footer>
|
<Footer>
|
||||||
<Link
|
<Link
|
||||||
|
|
786
app/yarn.lock
786
app/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -17,7 +17,7 @@ import {
|
||||||
FaApple,
|
FaApple,
|
||||||
FaTwitter,
|
FaTwitter,
|
||||||
FaMicrosoft,
|
FaMicrosoft,
|
||||||
FaTwitch,
|
FaTwitch, FaDiscord,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import {
|
import {
|
||||||
TextInputType,
|
TextInputType,
|
||||||
|
@ -309,6 +309,44 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaDiscord style={{ color: '#7289da' }} />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.DISCORD_CLIENT_ID}
|
||||||
|
placeholder="Discord Client ID"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
fieldVisibility={fieldVisibility}
|
||||||
|
setFieldVisibility={setFieldVisibility}
|
||||||
|
inputType={HiddenInputType.DISCORD_CLIENT_SECRET}
|
||||||
|
placeholder="Discord Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
<Center
|
<Center
|
||||||
w={isNotSmallerScreen ? '55px' : '35px'}
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
|
|
@ -9,6 +9,7 @@ export const TextInputType = {
|
||||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||||
|
DISCORD_CLIENT_ID: 'DISCORD_CLIENT_ID',
|
||||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||||
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
||||||
|
@ -41,6 +42,7 @@ export const HiddenInputType = {
|
||||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||||
|
DISCORD_CLIENT_SECRET: 'DISCORD_CLIENT_SECRET',
|
||||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||||
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
||||||
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
||||||
|
@ -129,6 +131,8 @@ export interface envVarTypes {
|
||||||
LINKEDIN_CLIENT_SECRET: string;
|
LINKEDIN_CLIENT_SECRET: string;
|
||||||
APPLE_CLIENT_ID: string;
|
APPLE_CLIENT_ID: string;
|
||||||
APPLE_CLIENT_SECRET: string;
|
APPLE_CLIENT_SECRET: string;
|
||||||
|
DISCORD_CLIENT_ID: string;
|
||||||
|
DISCORD_CLIENT_SECRET: string;
|
||||||
TWITTER_CLIENT_ID: string;
|
TWITTER_CLIENT_ID: string;
|
||||||
TWITTER_CLIENT_SECRET: string;
|
TWITTER_CLIENT_SECRET: string;
|
||||||
MICROSOFT_CLIENT_ID: string;
|
MICROSOFT_CLIENT_ID: string;
|
||||||
|
|
|
@ -30,6 +30,8 @@ export const EnvVariablesQuery = `
|
||||||
LINKEDIN_CLIENT_SECRET
|
LINKEDIN_CLIENT_SECRET
|
||||||
APPLE_CLIENT_ID
|
APPLE_CLIENT_ID
|
||||||
APPLE_CLIENT_SECRET
|
APPLE_CLIENT_SECRET
|
||||||
|
DISCORD_CLIENT_ID
|
||||||
|
DISCORD_CLIENT_SECRET
|
||||||
TWITTER_CLIENT_ID
|
TWITTER_CLIENT_ID
|
||||||
TWITTER_CLIENT_SECRET
|
TWITTER_CLIENT_SECRET
|
||||||
MICROSOFT_CLIENT_ID
|
MICROSOFT_CLIENT_ID
|
||||||
|
|
|
@ -50,6 +50,8 @@ const Environment = () => {
|
||||||
LINKEDIN_CLIENT_SECRET: '',
|
LINKEDIN_CLIENT_SECRET: '',
|
||||||
APPLE_CLIENT_ID: '',
|
APPLE_CLIENT_ID: '',
|
||||||
APPLE_CLIENT_SECRET: '',
|
APPLE_CLIENT_SECRET: '',
|
||||||
|
DISCORD_CLIENT_ID: '',
|
||||||
|
DISCORD_CLIENT_SECRET: '',
|
||||||
TWITTER_CLIENT_ID: '',
|
TWITTER_CLIENT_ID: '',
|
||||||
TWITTER_CLIENT_SECRET: '',
|
TWITTER_CLIENT_SECRET: '',
|
||||||
MICROSOFT_CLIENT_ID: '',
|
MICROSOFT_CLIENT_ID: '',
|
||||||
|
@ -108,6 +110,7 @@ const Environment = () => {
|
||||||
FACEBOOK_CLIENT_SECRET: false,
|
FACEBOOK_CLIENT_SECRET: false,
|
||||||
LINKEDIN_CLIENT_SECRET: false,
|
LINKEDIN_CLIENT_SECRET: false,
|
||||||
APPLE_CLIENT_SECRET: false,
|
APPLE_CLIENT_SECRET: false,
|
||||||
|
DISCORD_CLIENT_SECRET: false,
|
||||||
TWITTER_CLIENT_SECRET: false,
|
TWITTER_CLIENT_SECRET: false,
|
||||||
TWITCH_CLIENT_SECRET: false,
|
TWITCH_CLIENT_SECRET: false,
|
||||||
JWT_SECRET: false,
|
JWT_SECRET: false,
|
||||||
|
|
2114
dashboard/yarn.lock
2114
dashboard/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -19,6 +19,8 @@ const (
|
||||||
AuthRecipeMethodLinkedIn = "linkedin"
|
AuthRecipeMethodLinkedIn = "linkedin"
|
||||||
// AuthRecipeMethodApple is the apple auth method
|
// AuthRecipeMethodApple is the apple auth method
|
||||||
AuthRecipeMethodApple = "apple"
|
AuthRecipeMethodApple = "apple"
|
||||||
|
// AuthRecipeMethodDiscord is the discord auth method
|
||||||
|
AuthRecipeMethodDiscord = "discord"
|
||||||
// AuthRecipeMethodTwitter is the twitter auth method
|
// AuthRecipeMethodTwitter is the twitter auth method
|
||||||
AuthRecipeMethodTwitter = "twitter"
|
AuthRecipeMethodTwitter = "twitter"
|
||||||
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
||||||
|
|
|
@ -108,6 +108,10 @@ const (
|
||||||
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
||||||
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
||||||
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
||||||
|
// EnvKeyDiscordClientID key for env variable DISCORD_CLIENT_ID
|
||||||
|
EnvKeyDiscordClientID = "DISCORD_CLIENT_ID"
|
||||||
|
// EnvKeyDiscordClientSecret key for env variable DISCORD_CLIENT_SECRET
|
||||||
|
EnvKeyDiscordClientSecret = "DISCORD_CLIENT_SECRET"
|
||||||
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
|
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
|
||||||
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
|
||||||
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
|
||||||
|
|
|
@ -17,6 +17,7 @@ const (
|
||||||
|
|
||||||
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
TwitterUserInfoURL = "https://api.twitter.com/2/users/me?user.fields=id,name,profile_image_url,username"
|
||||||
|
|
||||||
|
DiscordUserInfoURL = "https://discord.com/api/oauth2/@me"
|
||||||
// Get microsoft user info.
|
// Get microsoft user info.
|
||||||
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
// Ref: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
|
||||||
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
MicrosoftUserInfoURL = "https://graph.microsoft.com/oidc/userinfo"
|
||||||
|
|
|
@ -109,6 +109,8 @@ type ComplexityRoot struct {
|
||||||
DisableSignUp func(childComplexity int) int
|
DisableSignUp func(childComplexity int) int
|
||||||
DisableStrongPassword func(childComplexity int) int
|
DisableStrongPassword func(childComplexity int) int
|
||||||
DisableTotpLogin func(childComplexity int) int
|
DisableTotpLogin func(childComplexity int) int
|
||||||
|
DiscordClientID func(childComplexity int) int
|
||||||
|
DiscordClientSecret func(childComplexity int) int
|
||||||
EnforceMultiFactorAuthentication func(childComplexity int) int
|
EnforceMultiFactorAuthentication func(childComplexity int) int
|
||||||
FacebookClientID func(childComplexity int) int
|
FacebookClientID func(childComplexity int) int
|
||||||
FacebookClientSecret func(childComplexity int) int
|
FacebookClientSecret func(childComplexity int) int
|
||||||
|
@ -150,6 +152,11 @@ type ComplexityRoot struct {
|
||||||
Reason func(childComplexity int) int
|
Reason func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForgotPasswordResponse struct {
|
||||||
|
Message func(childComplexity int) int
|
||||||
|
ShouldShowMobileOtpScreen func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
GenerateJWTKeysResponse struct {
|
GenerateJWTKeysResponse struct {
|
||||||
PrivateKey func(childComplexity int) int
|
PrivateKey func(childComplexity int) int
|
||||||
PublicKey func(childComplexity int) int
|
PublicKey func(childComplexity int) int
|
||||||
|
@ -165,6 +172,7 @@ type ComplexityRoot 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
|
||||||
|
IsDiscordLoginEnabled 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
|
||||||
|
@ -356,7 +364,7 @@ type MutationResolver interface {
|
||||||
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error)
|
||||||
VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error)
|
VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error)
|
||||||
ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error)
|
ResendVerifyEmail(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error)
|
||||||
ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error)
|
ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error)
|
||||||
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error)
|
ResetPassword(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error)
|
||||||
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
|
Revoke(ctx context.Context, params model.OAuthRevokeInput) (*model.Response, error)
|
||||||
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
|
VerifyOtp(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error)
|
||||||
|
@ -787,6 +795,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Env.DisableTotpLogin(childComplexity), true
|
return e.complexity.Env.DisableTotpLogin(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.DISCORD_CLIENT_ID":
|
||||||
|
if e.complexity.Env.DiscordClientID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.DiscordClientID(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.DISCORD_CLIENT_SECRET":
|
||||||
|
if e.complexity.Env.DiscordClientSecret == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.DiscordClientSecret(childComplexity), true
|
||||||
|
|
||||||
case "Env.ENFORCE_MULTI_FACTOR_AUTHENTICATION":
|
case "Env.ENFORCE_MULTI_FACTOR_AUTHENTICATION":
|
||||||
if e.complexity.Env.EnforceMultiFactorAuthentication == nil {
|
if e.complexity.Env.EnforceMultiFactorAuthentication == nil {
|
||||||
break
|
break
|
||||||
|
@ -1039,6 +1061,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Error.Reason(childComplexity), true
|
return e.complexity.Error.Reason(childComplexity), true
|
||||||
|
|
||||||
|
case "ForgotPasswordResponse.message":
|
||||||
|
if e.complexity.ForgotPasswordResponse.Message == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ForgotPasswordResponse.Message(childComplexity), true
|
||||||
|
|
||||||
|
case "ForgotPasswordResponse.should_show_mobile_otp_screen":
|
||||||
|
if e.complexity.ForgotPasswordResponse.ShouldShowMobileOtpScreen == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ForgotPasswordResponse.ShouldShowMobileOtpScreen(childComplexity), true
|
||||||
|
|
||||||
case "GenerateJWTKeysResponse.private_key":
|
case "GenerateJWTKeysResponse.private_key":
|
||||||
if e.complexity.GenerateJWTKeysResponse.PrivateKey == nil {
|
if e.complexity.GenerateJWTKeysResponse.PrivateKey == nil {
|
||||||
break
|
break
|
||||||
|
@ -1095,6 +1131,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Meta.IsBasicAuthenticationEnabled(childComplexity), true
|
return e.complexity.Meta.IsBasicAuthenticationEnabled(childComplexity), true
|
||||||
|
|
||||||
|
case "Meta.is_discord_login_enabled":
|
||||||
|
if e.complexity.Meta.IsDiscordLoginEnabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Meta.IsDiscordLoginEnabled(childComplexity), true
|
||||||
|
|
||||||
case "Meta.is_email_verification_enabled":
|
case "Meta.is_email_verification_enabled":
|
||||||
if e.complexity.Meta.IsEmailVerificationEnabled == nil {
|
if e.complexity.Meta.IsEmailVerificationEnabled == nil {
|
||||||
break
|
break
|
||||||
|
@ -2362,6 +2405,7 @@ type Meta {
|
||||||
is_github_login_enabled: Boolean!
|
is_github_login_enabled: Boolean!
|
||||||
is_linkedin_login_enabled: Boolean!
|
is_linkedin_login_enabled: Boolean!
|
||||||
is_apple_login_enabled: Boolean!
|
is_apple_login_enabled: Boolean!
|
||||||
|
is_discord_login_enabled: Boolean!
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_microsoft_login_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
is_twitch_login_enabled: Boolean!
|
is_twitch_login_enabled: Boolean!
|
||||||
|
@ -2459,6 +2503,11 @@ type Response {
|
||||||
message: String!
|
message: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForgotPasswordResponse {
|
||||||
|
message: String!
|
||||||
|
should_show_mobile_otp_screen: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type InviteMembersResponse {
|
type InviteMembersResponse {
|
||||||
message: String!
|
message: String!
|
||||||
Users: [User!]!
|
Users: [User!]!
|
||||||
|
@ -2515,6 +2564,8 @@ type Env {
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
|
DISCORD_CLIENT_ID: String
|
||||||
|
DISCORD_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
|
@ -2644,6 +2695,8 @@ input UpdateEnvInput {
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
|
DISCORD_CLIENT_ID: String
|
||||||
|
DISCORD_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
|
@ -2791,13 +2844,16 @@ input UpdateUserInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
email: String!
|
email: String
|
||||||
|
phone_number: String
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResetPasswordInput {
|
input ResetPasswordInput {
|
||||||
token: String!
|
token: String
|
||||||
|
otp: String
|
||||||
|
phone_number: String
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
}
|
}
|
||||||
|
@ -2950,7 +3006,7 @@ type Mutation {
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||||
forgot_password(params: ForgotPasswordInput!): Response!
|
forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse!
|
||||||
reset_password(params: ResetPasswordInput!): Response!
|
reset_password(params: ResetPasswordInput!): Response!
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
|
@ -6675,6 +6731,88 @@ func (ec *executionContext) fieldContext_Env_APPLE_CLIENT_SECRET(ctx context.Con
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_DISCORD_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_DISCORD_CLIENT_ID(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.DiscordClientID, 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) fieldContext_Env_DISCORD_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_DISCORD_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_DISCORD_CLIENT_SECRET(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.DiscordClientSecret, 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) fieldContext_Env_DISCORD_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Env_TWITTER_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Env_TWITTER_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field)
|
fc, err := ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7434,6 +7572,91 @@ func (ec *executionContext) fieldContext_Error_reason(ctx context.Context, field
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ForgotPasswordResponse_message(ctx context.Context, field graphql.CollectedField, obj *model.ForgotPasswordResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_ForgotPasswordResponse_message(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.Message, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_ForgotPasswordResponse_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "ForgotPasswordResponse",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ForgotPasswordResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField, obj *model.ForgotPasswordResponse) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(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.ShouldShowMobileOtpScreen, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "ForgotPasswordResponse",
|
||||||
|
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) _GenerateJWTKeysResponse_secret(ctx context.Context, field graphql.CollectedField, obj *model.GenerateJWTKeysResponse) (ret graphql.Marshaler) {
|
func (ec *executionContext) _GenerateJWTKeysResponse_secret(ctx context.Context, field graphql.CollectedField, obj *model.GenerateJWTKeysResponse) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_GenerateJWTKeysResponse_secret(ctx, field)
|
fc, err := ec.fieldContext_GenerateJWTKeysResponse_secret(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7995,6 +8218,50 @@ func (ec *executionContext) fieldContext_Meta_is_apple_login_enabled(ctx context
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Meta_is_discord_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Meta_is_discord_login_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.IsDiscordLoginEnabled, 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_discord_login_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_twitter_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Meta_is_twitter_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
fc, err := ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9135,9 +9402,9 @@ func (ec *executionContext) _Mutation_forgot_password(ctx context.Context, field
|
||||||
}
|
}
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
res := resTmp.(*model.Response)
|
res := resTmp.(*model.ForgotPasswordResponse)
|
||||||
fc.Result = res
|
fc.Result = res
|
||||||
return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res)
|
return ec.marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
@ -9149,9 +9416,11 @@ func (ec *executionContext) fieldContext_Mutation_forgot_password(ctx context.Co
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "message":
|
case "message":
|
||||||
return ec.fieldContext_Response_message(ctx, field)
|
return ec.fieldContext_ForgotPasswordResponse_message(ctx, field)
|
||||||
|
case "should_show_mobile_otp_screen":
|
||||||
|
return ec.fieldContext_ForgotPasswordResponse_should_show_mobile_otp_screen(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type Response", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type ForgotPasswordResponse", field.Name)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -10741,6 +11010,8 @@ func (ec *executionContext) fieldContext_Query_meta(ctx context.Context, field g
|
||||||
return ec.fieldContext_Meta_is_linkedin_login_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_linkedin_login_enabled(ctx, field)
|
||||||
case "is_apple_login_enabled":
|
case "is_apple_login_enabled":
|
||||||
return ec.fieldContext_Meta_is_apple_login_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_apple_login_enabled(ctx, field)
|
||||||
|
case "is_discord_login_enabled":
|
||||||
|
return ec.fieldContext_Meta_is_discord_login_enabled(ctx, field)
|
||||||
case "is_twitter_login_enabled":
|
case "is_twitter_login_enabled":
|
||||||
return ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
||||||
case "is_microsoft_login_enabled":
|
case "is_microsoft_login_enabled":
|
||||||
|
@ -11465,6 +11736,10 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
||||||
return ec.fieldContext_Env_APPLE_CLIENT_ID(ctx, field)
|
return ec.fieldContext_Env_APPLE_CLIENT_ID(ctx, field)
|
||||||
case "APPLE_CLIENT_SECRET":
|
case "APPLE_CLIENT_SECRET":
|
||||||
return ec.fieldContext_Env_APPLE_CLIENT_SECRET(ctx, field)
|
return ec.fieldContext_Env_APPLE_CLIENT_SECRET(ctx, field)
|
||||||
|
case "DISCORD_CLIENT_ID":
|
||||||
|
return ec.fieldContext_Env_DISCORD_CLIENT_ID(ctx, field)
|
||||||
|
case "DISCORD_CLIENT_SECRET":
|
||||||
|
return ec.fieldContext_Env_DISCORD_CLIENT_SECRET(ctx, field)
|
||||||
case "TWITTER_CLIENT_ID":
|
case "TWITTER_CLIENT_ID":
|
||||||
return ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field)
|
return ec.fieldContext_Env_TWITTER_CLIENT_ID(ctx, field)
|
||||||
case "TWITTER_CLIENT_SECRET":
|
case "TWITTER_CLIENT_SECRET":
|
||||||
|
@ -16821,7 +17096,7 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"email", "state", "redirect_uri"}
|
fieldsInOrder := [...]string{"email", "phone_number", "state", "redirect_uri"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -16832,11 +17107,20 @@ func (ec *executionContext) unmarshalInputForgotPasswordInput(ctx context.Contex
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
|
||||||
data, err := ec.unmarshalNString2string(ctx, v)
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Email = data
|
it.Email = data
|
||||||
|
case "phone_number":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.PhoneNumber = data
|
||||||
case "state":
|
case "state":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -17578,7 +17862,7 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"token", "password", "confirm_password"}
|
fieldsInOrder := [...]string{"token", "otp", "phone_number", "password", "confirm_password"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -17589,11 +17873,29 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token"))
|
||||||
data, err := ec.unmarshalNString2string(ctx, v)
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Token = data
|
it.Token = data
|
||||||
|
case "otp":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("otp"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.Otp = data
|
||||||
|
case "phone_number":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.PhoneNumber = data
|
||||||
case "password":
|
case "password":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -17986,7 +18288,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -18380,6 +18682,24 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.AppleClientSecret = data
|
it.AppleClientSecret = data
|
||||||
|
case "DISCORD_CLIENT_ID":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISCORD_CLIENT_ID"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.DiscordClientID = data
|
||||||
|
case "DISCORD_CLIENT_SECRET":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISCORD_CLIENT_SECRET"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.DiscordClientSecret = data
|
||||||
case "TWITTER_CLIENT_ID":
|
case "TWITTER_CLIENT_ID":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -19415,6 +19735,10 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
||||||
out.Values[i] = ec._Env_APPLE_CLIENT_ID(ctx, field, obj)
|
out.Values[i] = ec._Env_APPLE_CLIENT_ID(ctx, field, obj)
|
||||||
case "APPLE_CLIENT_SECRET":
|
case "APPLE_CLIENT_SECRET":
|
||||||
out.Values[i] = ec._Env_APPLE_CLIENT_SECRET(ctx, field, obj)
|
out.Values[i] = ec._Env_APPLE_CLIENT_SECRET(ctx, field, obj)
|
||||||
|
case "DISCORD_CLIENT_ID":
|
||||||
|
out.Values[i] = ec._Env_DISCORD_CLIENT_ID(ctx, field, obj)
|
||||||
|
case "DISCORD_CLIENT_SECRET":
|
||||||
|
out.Values[i] = ec._Env_DISCORD_CLIENT_SECRET(ctx, field, obj)
|
||||||
case "TWITTER_CLIENT_ID":
|
case "TWITTER_CLIENT_ID":
|
||||||
out.Values[i] = ec._Env_TWITTER_CLIENT_ID(ctx, field, obj)
|
out.Values[i] = ec._Env_TWITTER_CLIENT_ID(ctx, field, obj)
|
||||||
case "TWITTER_CLIENT_SECRET":
|
case "TWITTER_CLIENT_SECRET":
|
||||||
|
@ -19529,6 +19853,47 @@ func (ec *executionContext) _Error(ctx context.Context, sel ast.SelectionSet, ob
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var forgotPasswordResponseImplementors = []string{"ForgotPasswordResponse"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ForgotPasswordResponse) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, forgotPasswordResponseImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
deferred := make(map[string]*graphql.FieldSet)
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("ForgotPasswordResponse")
|
||||||
|
case "message":
|
||||||
|
out.Values[i] = ec._ForgotPasswordResponse_message(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
case "should_show_mobile_otp_screen":
|
||||||
|
out.Values[i] = ec._ForgotPasswordResponse_should_show_mobile_otp_screen(ctx, field, obj)
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch(ctx)
|
||||||
|
if out.Invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||||
|
|
||||||
|
for label, dfs := range deferred {
|
||||||
|
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||||
|
Label: label,
|
||||||
|
Path: graphql.GetPath(ctx),
|
||||||
|
FieldSet: dfs,
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var generateJWTKeysResponseImplementors = []string{"GenerateJWTKeysResponse"}
|
var generateJWTKeysResponseImplementors = []string{"GenerateJWTKeysResponse"}
|
||||||
|
|
||||||
func (ec *executionContext) _GenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, obj *model.GenerateJWTKeysResponse) graphql.Marshaler {
|
func (ec *executionContext) _GenerateJWTKeysResponse(ctx context.Context, sel ast.SelectionSet, obj *model.GenerateJWTKeysResponse) graphql.Marshaler {
|
||||||
|
@ -19659,6 +20024,11 @@ 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_discord_login_enabled":
|
||||||
|
out.Values[i] = ec._Meta_is_discord_login_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
case "is_twitter_login_enabled":
|
case "is_twitter_login_enabled":
|
||||||
out.Values[i] = ec._Meta_is_twitter_login_enabled(ctx, field, obj)
|
out.Values[i] = ec._Meta_is_twitter_login_enabled(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
@ -21531,6 +21901,20 @@ func (ec *executionContext) unmarshalNForgotPasswordInput2githubᚗcomᚋauthori
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNForgotPasswordResponse2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v model.ForgotPasswordResponse) graphql.Marshaler {
|
||||||
|
return ec._ForgotPasswordResponse(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNForgotPasswordResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐForgotPasswordResponse(ctx context.Context, sel ast.SelectionSet, v *model.ForgotPasswordResponse) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._ForgotPasswordResponse(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNGenerateJWTKeysInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysInput(ctx context.Context, v interface{}) (model.GenerateJWTKeysInput, error) {
|
func (ec *executionContext) unmarshalNGenerateJWTKeysInput2githubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐGenerateJWTKeysInput(ctx context.Context, v interface{}) (model.GenerateJWTKeysInput, error) {
|
||||||
res, err := ec.unmarshalInputGenerateJWTKeysInput(ctx, v)
|
res, err := ec.unmarshalInputGenerateJWTKeysInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
|
|
@ -114,6 +114,8 @@ type Env struct {
|
||||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
||||||
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
||||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
||||||
|
DiscordClientID *string `json:"DISCORD_CLIENT_ID,omitempty"`
|
||||||
|
DiscordClientSecret *string `json:"DISCORD_CLIENT_SECRET,omitempty"`
|
||||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
||||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
||||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||||
|
@ -138,11 +140,17 @@ type Error struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForgotPasswordInput struct {
|
type ForgotPasswordInput struct {
|
||||||
Email string `json:"email"`
|
Email *string `json:"email,omitempty"`
|
||||||
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
State *string `json:"state,omitempty"`
|
State *string `json:"state,omitempty"`
|
||||||
RedirectURI *string `json:"redirect_uri,omitempty"`
|
RedirectURI *string `json:"redirect_uri,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForgotPasswordResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
ShouldShowMobileOtpScreen *bool `json:"should_show_mobile_otp_screen,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type GenerateJWTKeysInput struct {
|
type GenerateJWTKeysInput struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
@ -198,6 +206,7 @@ type Meta struct {
|
||||||
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"`
|
||||||
|
IsDiscordLoginEnabled bool `json:"is_discord_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"`
|
||||||
|
@ -272,9 +281,11 @@ type ResendVerifyEmailInput struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResetPasswordInput struct {
|
type ResetPasswordInput struct {
|
||||||
Token string `json:"token"`
|
Token *string `json:"token,omitempty"`
|
||||||
Password string `json:"password"`
|
Otp *string `json:"otp,omitempty"`
|
||||||
ConfirmPassword string `json:"confirm_password"`
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConfirmPassword string `json:"confirm_password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
@ -383,6 +394,8 @@ type UpdateEnvInput struct {
|
||||||
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET,omitempty"`
|
||||||
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
AppleClientID *string `json:"APPLE_CLIENT_ID,omitempty"`
|
||||||
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET,omitempty"`
|
||||||
|
DiscordClientID *string `json:"DISCORD_CLIENT_ID,omitempty"`
|
||||||
|
DiscordClientSecret *string `json:"DISCORD_CLIENT_SECRET,omitempty"`
|
||||||
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
TwitterClientID *string `json:"TWITTER_CLIENT_ID,omitempty"`
|
||||||
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET,omitempty"`
|
||||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||||
|
|
|
@ -20,6 +20,7 @@ type Meta {
|
||||||
is_github_login_enabled: Boolean!
|
is_github_login_enabled: Boolean!
|
||||||
is_linkedin_login_enabled: Boolean!
|
is_linkedin_login_enabled: Boolean!
|
||||||
is_apple_login_enabled: Boolean!
|
is_apple_login_enabled: Boolean!
|
||||||
|
is_discord_login_enabled: Boolean!
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_microsoft_login_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
is_twitch_login_enabled: Boolean!
|
is_twitch_login_enabled: Boolean!
|
||||||
|
@ -117,6 +118,11 @@ type Response {
|
||||||
message: String!
|
message: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForgotPasswordResponse {
|
||||||
|
message: String!
|
||||||
|
should_show_mobile_otp_screen: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type InviteMembersResponse {
|
type InviteMembersResponse {
|
||||||
message: String!
|
message: String!
|
||||||
Users: [User!]!
|
Users: [User!]!
|
||||||
|
@ -173,6 +179,8 @@ type Env {
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
|
DISCORD_CLIENT_ID: String
|
||||||
|
DISCORD_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
|
@ -302,6 +310,8 @@ input UpdateEnvInput {
|
||||||
LINKEDIN_CLIENT_SECRET: String
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
APPLE_CLIENT_ID: String
|
APPLE_CLIENT_ID: String
|
||||||
APPLE_CLIENT_SECRET: String
|
APPLE_CLIENT_SECRET: String
|
||||||
|
DISCORD_CLIENT_ID: String
|
||||||
|
DISCORD_CLIENT_SECRET: String
|
||||||
TWITTER_CLIENT_ID: String
|
TWITTER_CLIENT_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
|
@ -449,13 +459,16 @@ input UpdateUserInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
email: String!
|
email: String
|
||||||
|
phone_number: String
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResetPasswordInput {
|
input ResetPasswordInput {
|
||||||
token: String!
|
token: String
|
||||||
|
otp: String
|
||||||
|
phone_number: String
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
}
|
}
|
||||||
|
@ -608,7 +621,7 @@ type Mutation {
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||||
forgot_password(params: ForgotPasswordInput!): Response!
|
forgot_password(params: ForgotPasswordInput!): ForgotPasswordResponse!
|
||||||
reset_password(params: ResetPasswordInput!): Response!
|
reset_password(params: ResetPasswordInput!): Response!
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
|
|
|
@ -58,7 +58,7 @@ func (r *mutationResolver) ResendVerifyEmail(ctx context.Context, params model.R
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForgotPassword is the resolver for the forgot_password field.
|
// ForgotPassword is the resolver for the forgot_password field.
|
||||||
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
|
func (r *mutationResolver) ForgotPassword(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) {
|
||||||
return resolvers.ForgotPasswordResolver(ctx, params)
|
return resolvers.ForgotPasswordResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
// TODO add state with timeout
|
// TODO add state with timeout
|
||||||
// used for response mode query or fragment
|
// used for response mode query or fragment
|
||||||
authState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI
|
authState := "state=" + state + "&scope=" + scopeString + "&redirect_uri=" + redirectURI
|
||||||
if responseType == constants.ResponseTypeCode {
|
if responseType == constants.ResponseTypeCode {
|
||||||
authState += "&code=" + code
|
authState += "&code=" + code
|
||||||
if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil {
|
if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil {
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -54,7 +53,16 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
stateValue := sessionSplit[0]
|
stateValue := sessionSplit[0]
|
||||||
redirectURL := sessionSplit[1]
|
redirectURL := sessionSplit[1]
|
||||||
inputRoles := strings.Split(sessionSplit[2], ",")
|
inputRoles := strings.Split(sessionSplit[2], ",")
|
||||||
scopes := strings.Split(sessionSplit[3], ",")
|
scopeString := sessionSplit[3]
|
||||||
|
scopes := []string{}
|
||||||
|
if scopeString != "" {
|
||||||
|
if strings.Contains(scopeString, ",") {
|
||||||
|
scopes = strings.Split(scopeString, ",")
|
||||||
|
}
|
||||||
|
if strings.Contains(scopeString, " ") {
|
||||||
|
scopes = strings.Split(scopeString, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
var user *models.User
|
var user *models.User
|
||||||
oauthCode := ctx.Request.FormValue("code")
|
oauthCode := ctx.Request.FormValue("code")
|
||||||
if oauthCode == "" {
|
if oauthCode == "" {
|
||||||
|
@ -73,6 +81,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
user, err = processLinkedInUserInfo(ctx, oauthCode)
|
user, err = processLinkedInUserInfo(ctx, oauthCode)
|
||||||
case constants.AuthRecipeMethodApple:
|
case constants.AuthRecipeMethodApple:
|
||||||
user, err = processAppleUserInfo(ctx, oauthCode)
|
user, err = processAppleUserInfo(ctx, oauthCode)
|
||||||
|
case constants.AuthRecipeMethodDiscord:
|
||||||
|
user, err = processDiscordUserInfo(ctx, oauthCode)
|
||||||
case constants.AuthRecipeMethodTwitter:
|
case constants.AuthRecipeMethodTwitter:
|
||||||
user, err = processTwitterUserInfo(ctx, oauthCode, sessionState)
|
user, err = processTwitterUserInfo(ctx, oauthCode, sessionState)
|
||||||
case constants.AuthRecipeMethodMicrosoft:
|
case constants.AuthRecipeMethodMicrosoft:
|
||||||
|
@ -248,8 +258,9 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
expiresIn = 1
|
expiresIn = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token + "&nonce=" + nonce
|
// params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token + "&nonce=" + nonce
|
||||||
|
// Note: If OIDC breaks in the future, use the above params
|
||||||
|
params := "state=" + stateValue + "&nonce=" + nonce
|
||||||
if code != "" {
|
if code != "" {
|
||||||
params += "&code=" + code
|
params += "&code=" + code
|
||||||
}
|
}
|
||||||
|
@ -609,6 +620,71 @@ func processAppleUserInfo(ctx context.Context, code string) (*models.User, error
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||||
|
oauth2Token, err := oauth.OAuthProviders.DiscordConfig.Exchange(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
|
return nil, fmt.Errorf("invalid discord exchange code: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
client := http.Client{}
|
||||||
|
req, err := http.NewRequest("GET", constants.DiscordUserInfoURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create Discord user info request: ", err)
|
||||||
|
return nil, fmt.Errorf("error creating Discord user info request: %s", err.Error())
|
||||||
|
}
|
||||||
|
req.Header = http.Header{
|
||||||
|
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to request Discord user info: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to read Discord user info response body: ", err)
|
||||||
|
return nil, fmt.Errorf("failed to read Discord response body: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
log.Debug("Failed to request Discord user info: ", string(body))
|
||||||
|
return nil, fmt.Errorf("failed to request Discord user info: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal the response body into a map
|
||||||
|
responseRawData := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(body, &responseRawData); err != nil {
|
||||||
|
log.Debug("Failed to unmarshal Discord response: ", err)
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal Discord response: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safely extract the user data
|
||||||
|
userRawData, ok := responseRawData["user"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Debug("User data is not in expected format or missing in response")
|
||||||
|
return nil, fmt.Errorf("user data is not in expected format or missing in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the username
|
||||||
|
firstName, ok := userRawData["username"].(string)
|
||||||
|
if !ok {
|
||||||
|
log.Debug("Username is not in expected format or missing in user data")
|
||||||
|
return nil, fmt.Errorf("username is not in expected format or missing in user data")
|
||||||
|
}
|
||||||
|
profilePicture := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s.png", userRawData["id"].(string), userRawData["avatar"].(string))
|
||||||
|
|
||||||
|
user := &models.User{
|
||||||
|
GivenName: &firstName,
|
||||||
|
Picture: &profilePicture,
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models.User, error) {
|
func processTwitterUserInfo(ctx context.Context, code, verifier string) (*models.User, error) {
|
||||||
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", verifier))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -192,6 +192,24 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter
|
oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter
|
||||||
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("code_challenge", challenge), oauth2.SetAuthURLParam("code_challenge_method", "S256"))
|
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("code_challenge", challenge), oauth2.SetAuthURLParam("code_challenge_method", "S256"))
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
|
||||||
|
case constants.AuthRecipeMethodDiscord:
|
||||||
|
if oauth.OAuthProviders.DiscordConfig == nil {
|
||||||
|
log.Debug("Discord OAuth provider is not configured")
|
||||||
|
isProviderConfigured = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodDiscord)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error setting state: ", err)
|
||||||
|
c.JSON(500, gin.H{
|
||||||
|
"error": "internal server error",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauth.OAuthProviders.DiscordConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodDiscord
|
||||||
|
url := oauth.OAuthProviders.DiscordConfig.AuthCodeURL(oauthStateString)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
case constants.AuthRecipeMethodApple:
|
case constants.AuthRecipeMethodApple:
|
||||||
if oauth.OAuthProviders.AppleConfig == nil {
|
if oauth.OAuthProviders.AppleConfig == nil {
|
||||||
log.Debug("Apple OAuth provider is not configured")
|
log.Debug("Apple OAuth provider is not configured")
|
||||||
|
|
|
@ -105,7 +105,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
if codeVerifier == "" && clientSecret == "" {
|
if codeVerifier == "" && clientSecret == "" {
|
||||||
gc.JSON(http.StatusBadRequest, gin.H{
|
gc.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": "invalid_dat",
|
"error": "invalid_data",
|
||||||
"error_description": "The code verifier or client secret is required",
|
"error_description": "The code verifier or client secret is required",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -263,12 +263,10 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
"expires_in": expiresIn,
|
"expires_in": expiresIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, res)
|
gc.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type OAuthProvider struct {
|
||||||
FacebookConfig *oauth2.Config
|
FacebookConfig *oauth2.Config
|
||||||
LinkedInConfig *oauth2.Config
|
LinkedInConfig *oauth2.Config
|
||||||
AppleConfig *oauth2.Config
|
AppleConfig *oauth2.Config
|
||||||
|
DiscordConfig *oauth2.Config
|
||||||
TwitterConfig *oauth2.Config
|
TwitterConfig *oauth2.Config
|
||||||
MicrosoftConfig *oauth2.Config
|
MicrosoftConfig *oauth2.Config
|
||||||
TwitchConfig *oauth2.Config
|
TwitchConfig *oauth2.Config
|
||||||
|
@ -149,6 +150,27 @@ func InitOAuth() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
discordClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDiscordClientID)
|
||||||
|
if err != nil {
|
||||||
|
discordClientID = ""
|
||||||
|
}
|
||||||
|
discordClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDiscordClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
discordClientSecret = ""
|
||||||
|
}
|
||||||
|
if discordClientID != "" && discordClientSecret != "" {
|
||||||
|
OAuthProviders.DiscordConfig = &oauth2.Config{
|
||||||
|
ClientID: discordClientID,
|
||||||
|
ClientSecret: discordClientSecret,
|
||||||
|
RedirectURL: "/oauth_callback/discord",
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://discord.com/oauth2/authorize",
|
||||||
|
TokenURL: "https://discord.com/api/oauth2/token",
|
||||||
|
},
|
||||||
|
Scopes: []string{"identify", "email"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
twitterClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientID)
|
twitterClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
twitterClientID = ""
|
twitterClientID = ""
|
||||||
|
|
|
@ -21,15 +21,15 @@ func DeactivateAccountResolver(ctx context.Context) (*model.Response, error) {
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
userID, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"user_id": userID,
|
"user_id": tokenData.UserID,
|
||||||
})
|
})
|
||||||
user, err := db.Provider.GetUserByID(ctx, userID)
|
user, err := db.Provider.GetUserByID(ctx, tokenData.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get user by id: ", err)
|
log.Debug("Failed to get user by id: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -149,6 +149,12 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||||
if val, ok := store[constants.EnvKeyAppleClientSecret]; ok {
|
if val, ok := store[constants.EnvKeyAppleClientSecret]; ok {
|
||||||
res.AppleClientSecret = refs.NewStringRef(val.(string))
|
res.AppleClientSecret = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyDiscordClientID]; ok {
|
||||||
|
res.DiscordClientID = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyDiscordClientSecret]; ok {
|
||||||
|
res.DiscordClientSecret = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
if val, ok := store[constants.EnvKeyTwitterClientID]; ok {
|
if val, ok := store[constants.EnvKeyTwitterClientID]; ok {
|
||||||
res.TwitterClientID = refs.NewStringRef(val.(string))
|
res.TwitterClientID = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,29 +6,29 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/email"
|
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/parsers"
|
"github.com/authorizerdev/authorizer/server/parsers"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/smsproviders"
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/authorizerdev/authorizer/server/validators"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForgotPasswordResolver is a resolver for forgot password mutation
|
// ForgotPasswordResolver is a resolver for forgot password mutation
|
||||||
func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) {
|
func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.ForgotPasswordResponse, error) {
|
||||||
var res *model.Response
|
|
||||||
|
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
||||||
|
@ -36,74 +36,134 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||||
log.Debug("Error getting basic auth disabled: ", err)
|
log.Debug("Error getting basic auth disabled: ", err)
|
||||||
isBasicAuthDisabled = true
|
isBasicAuthDisabled = true
|
||||||
}
|
}
|
||||||
if isBasicAuthDisabled {
|
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
||||||
log.Debug("Basic authentication is disabled")
|
|
||||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
|
||||||
}
|
|
||||||
params.Email = strings.ToLower(params.Email)
|
|
||||||
|
|
||||||
if !validators.IsValidEmail(params.Email) {
|
|
||||||
log.Debug("Invalid email address: ", params.Email)
|
|
||||||
return res, fmt.Errorf("invalid email")
|
|
||||||
}
|
|
||||||
|
|
||||||
log := log.WithFields(log.Fields{
|
|
||||||
"email": params.Email,
|
|
||||||
})
|
|
||||||
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("User not found: ", err)
|
log.Debug("Error getting email verification disabled: ", err)
|
||||||
return res, fmt.Errorf(`user with this email not found`)
|
isEmailVerificationDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isMobileBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
isMobileVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisablePhoneVerification)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile verification disabled: ", err)
|
||||||
|
isMobileVerificationDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
email := refs.StringValue(params.Email)
|
||||||
|
phoneNumber := refs.StringValue(params.PhoneNumber)
|
||||||
|
if email == "" && phoneNumber == "" {
|
||||||
|
log.Debug("Email or phone number is required")
|
||||||
|
return nil, fmt.Errorf(`email or phone number is required`)
|
||||||
|
}
|
||||||
|
log := log.WithFields(log.Fields{
|
||||||
|
"email": refs.StringValue(params.Email),
|
||||||
|
"phone_number": refs.StringValue(params.PhoneNumber),
|
||||||
|
})
|
||||||
|
isEmailLogin := email != ""
|
||||||
|
isMobileLogin := phoneNumber != ""
|
||||||
|
if isBasicAuthDisabled && isEmailLogin && !isEmailVerificationDisabled {
|
||||||
|
log.Debug("Basic authentication is disabled.")
|
||||||
|
return nil, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
if isMobileBasicAuthDisabled && isMobileLogin && !isMobileVerificationDisabled {
|
||||||
|
log.Debug("Mobile basic authentication is disabled.")
|
||||||
|
return nil, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
var user *models.User
|
||||||
|
if isEmailLogin {
|
||||||
|
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||||
|
} else {
|
||||||
|
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user: ", err)
|
||||||
|
return nil, fmt.Errorf(`bad user credentials`)
|
||||||
|
}
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
_, nonceHash, err := utils.GenerateNonce()
|
_, nonceHash, err := utils.GenerateNonce()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to generate nonce: ", err)
|
log.Debug("Failed to generate nonce: ", err)
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
redirectURI := ""
|
log.Debug("User access is revoked")
|
||||||
// give higher preference to params redirect uri
|
return nil, fmt.Errorf(`user access has been revoked`)
|
||||||
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
|
}
|
||||||
redirectURI = refs.StringValue(params.RedirectURI)
|
if isEmailLogin {
|
||||||
} else {
|
redirectURI := ""
|
||||||
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
// give higher preference to params redirect uri
|
||||||
if err != nil {
|
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
|
||||||
log.Debug("ResetPasswordURL not found using default app url: ", err)
|
redirectURI = refs.StringValue(params.RedirectURI)
|
||||||
redirectURI = hostname + "/app/reset-password"
|
} else {
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
|
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("ResetPasswordURL not found using default app url: ", err)
|
||||||
|
redirectURI = hostname + "/app/reset-password"
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create verification token", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{
|
||||||
|
Token: verificationToken,
|
||||||
|
Identifier: constants.VerificationTypeForgotPassword,
|
||||||
|
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||||
|
Email: email,
|
||||||
|
Nonce: nonceHash,
|
||||||
|
RedirectURI: redirectURI,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add verification request", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// execute it as go routine so that we can reduce the api latency
|
||||||
|
go mailService.SendEmail([]string{email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI),
|
||||||
|
})
|
||||||
|
return &model.ForgotPasswordResponse{
|
||||||
|
Message: `Please check your inbox! We have sent a password reset link.`,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
if isMobileLogin {
|
||||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||||
if err != nil {
|
otp := utils.GenerateOTP()
|
||||||
log.Debug("Failed to create verification token", err)
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
return res, err
|
Email: refs.StringValue(user.Email),
|
||||||
|
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||||
|
Otp: otp,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add mfasession: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cookie.SetMfaSession(gc, mfaSession)
|
||||||
|
smsBody := strings.Builder{}
|
||||||
|
smsBody.WriteString("Your verification code is: ")
|
||||||
|
smsBody.WriteString(otpData.Otp)
|
||||||
|
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||||
|
log.Debug("Failed to send sms: ", err)
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
return &model.ForgotPasswordResponse{
|
||||||
|
Message: "Please enter the OTP sent to your phone number and change your password.",
|
||||||
|
ShouldShowMobileOtpScreen: refs.NewBoolRef(true),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
_, err = db.Provider.AddVerificationRequest(ctx, &models.VerificationRequest{
|
return nil, fmt.Errorf(`email or phone number verification needs to be enabled`)
|
||||||
Token: verificationToken,
|
|
||||||
Identifier: constants.VerificationTypeForgotPassword,
|
|
||||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
|
||||||
Email: params.Email,
|
|
||||||
Nonce: nonceHash,
|
|
||||||
RedirectURI: redirectURI,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to add verification request", err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute it as go routine so that we can reduce the api latency
|
|
||||||
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
|
||||||
"user": user.ToMap(),
|
|
||||||
"organization": utils.GetOrganization(),
|
|
||||||
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI),
|
|
||||||
})
|
|
||||||
|
|
||||||
res = &model.Response{
|
|
||||||
Message: `Please check your inbox! We have sent a password reset link.`,
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
@ -23,8 +24,6 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/authorizerdev/authorizer/server/validators"
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
|
||||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoginResolver is a resolver for login mutation
|
// LoginResolver is a resolver for login mutation
|
||||||
|
@ -172,9 +171,10 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||||
otp := utils.GenerateOTP()
|
otp := utils.GenerateOTP()
|
||||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
Email: refs.StringValue(user.Email),
|
Email: refs.StringValue(user.Email),
|
||||||
Otp: otp,
|
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||||
ExpiresAt: expiresAt,
|
Otp: otp,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to add otp: ", err)
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
|
|
@ -2,12 +2,10 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/token"
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
@ -22,31 +20,18 @@ func LogoutResolver(ctx context.Context) (*model.Response, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get fingerprint hash
|
tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
||||||
fingerprintHash, err := cookie.GetSession(gc)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get fingerprint hash: ", err)
|
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash)
|
sessionKey := tokenData.UserID
|
||||||
if err != nil {
|
if tokenData.LoginMethod != "" {
|
||||||
log.Debug("Failed to decrypt fingerprint hash: ", err)
|
sessionKey = tokenData.LoginMethod + ":" + tokenData.UserID
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionData token.SessionData
|
memorystore.Provider.DeleteUserSession(sessionKey, tokenData.Nonce)
|
||||||
err = json.Unmarshal([]byte(decryptedFingerPrint), &sessionData)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionKey := sessionData.Subject
|
|
||||||
if sessionData.LoginMethod != "" {
|
|
||||||
sessionKey = sessionData.LoginMethod + ":" + sessionData.Subject
|
|
||||||
}
|
|
||||||
|
|
||||||
memorystore.Provider.DeleteUserSession(sessionKey, sessionData.Nonce)
|
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
res := &model.Response{
|
res := &model.Response{
|
||||||
|
|
|
@ -20,15 +20,15 @@ func ProfileResolver(ctx context.Context) (*model.User, error) {
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
userID, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"user_id": userID,
|
"user_id": tokenData.UserID,
|
||||||
})
|
})
|
||||||
user, err := db.Provider.GetUserByID(ctx, userID)
|
user, err := db.Provider.GetUserByID(ctx, tokenData.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get user: ", err)
|
log.Debug("Failed to get user: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -9,8 +9,10 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/parsers"
|
"github.com/authorizerdev/authorizer/server/parsers"
|
||||||
|
@ -29,97 +31,155 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
verifyingToken := refs.StringValue(params.Token)
|
||||||
|
otp := refs.StringValue(params.Otp)
|
||||||
|
if verifyingToken == "" && otp == "" {
|
||||||
|
log.Debug("Token or OTP is required")
|
||||||
|
return res, fmt.Errorf(`token or otp is required`)
|
||||||
|
}
|
||||||
|
isTokenVerification := verifyingToken != ""
|
||||||
|
isOtpVerification := otp != ""
|
||||||
|
if isOtpVerification && refs.StringValue(params.PhoneNumber) == "" {
|
||||||
|
log.Debug("Phone number is required")
|
||||||
|
return res, fmt.Errorf(`phone number is required`)
|
||||||
|
}
|
||||||
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting basic auth disabled: ", err)
|
log.Debug("Error getting basic auth disabled: ", err)
|
||||||
isBasicAuthDisabled = true
|
isBasicAuthDisabled = true
|
||||||
}
|
}
|
||||||
if isBasicAuthDisabled {
|
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
if isTokenVerification && isBasicAuthDisabled {
|
||||||
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`)
|
||||||
}
|
}
|
||||||
|
if isOtpVerification && isMobileBasicAuthDisabled {
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByToken(ctx, params.Token)
|
log.Debug("Mobile basic authentication is disabled")
|
||||||
if err != nil {
|
return res, fmt.Errorf(`mobile basic authentication is disabled for this instance`)
|
||||||
log.Debug("Failed to get verification request: ", err)
|
|
||||||
return res, fmt.Errorf(`invalid token`)
|
|
||||||
}
|
}
|
||||||
|
email := ""
|
||||||
|
phoneNumber := refs.StringValue(params.PhoneNumber)
|
||||||
|
var user *models.User
|
||||||
|
var verificationRequest *models.VerificationRequest
|
||||||
|
var otpRequest *models.OTP
|
||||||
|
if isTokenVerification {
|
||||||
|
verificationRequest, err = db.Provider.GetVerificationRequestByToken(ctx, verifyingToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get verification request: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid token`)
|
||||||
|
}
|
||||||
|
// verify if token exists in db
|
||||||
|
hostname := parsers.GetHost(gc)
|
||||||
|
claim, err := token.ParseJWTToken(verifyingToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to parse token: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid token`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||||
|
log.Debug("Failed to validate jwt claims: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid token`)
|
||||||
|
}
|
||||||
|
email = claim["sub"].(string)
|
||||||
|
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isOtpVerification {
|
||||||
|
mfaSession, err := cookie.GetMfaSession(gc)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get otp request by email: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid session: %s`, err.Error())
|
||||||
|
}
|
||||||
|
// Get user by phone number
|
||||||
|
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by phone number: ", err)
|
||||||
|
return res, fmt.Errorf(`user not found`)
|
||||||
|
}
|
||||||
|
if _, err := memorystore.Provider.GetMfaSession(user.ID, mfaSession); err != nil {
|
||||||
|
log.Debug("Failed to get mfa session: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid session: %s`, err.Error())
|
||||||
|
}
|
||||||
|
otpRequest, err = db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get otp request by phone number: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid otp`)
|
||||||
|
}
|
||||||
|
if otpRequest.Otp != otp {
|
||||||
|
log.Debug("Failed to verify otp request: Incorrect value")
|
||||||
|
return res, fmt.Errorf(`invalid otp`)
|
||||||
|
}
|
||||||
|
}
|
||||||
if params.Password != params.ConfirmPassword {
|
if params.Password != params.ConfirmPassword {
|
||||||
log.Debug("Passwords do not match")
|
log.Debug("Passwords do not match")
|
||||||
return res, fmt.Errorf(`passwords don't match`)
|
return res, fmt.Errorf(`passwords don't match`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validators.IsValidPassword(params.Password); err != nil {
|
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||||
log.Debug("Invalid password")
|
log.Debug("Invalid password")
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify if token exists in db
|
|
||||||
hostname := parsers.GetHost(gc)
|
|
||||||
claim, err := token.ParseJWTToken(params.Token)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to parse token: ", err)
|
|
||||||
return res, fmt.Errorf(`invalid token`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
|
||||||
log.Debug("Failed to validate jwt claims: ", err)
|
|
||||||
return res, fmt.Errorf(`invalid token`)
|
|
||||||
}
|
|
||||||
|
|
||||||
email := claim["sub"].(string)
|
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"email": email,
|
"email": email,
|
||||||
|
"phone": phoneNumber,
|
||||||
})
|
})
|
||||||
user, err := db.Provider.GetUserByEmail(ctx, email)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to get user: ", err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
password, _ := crypto.EncryptPassword(params.Password)
|
password, _ := crypto.EncryptPassword(params.Password)
|
||||||
user.Password = &password
|
user.Password = &password
|
||||||
|
|
||||||
signupMethod := user.SignupMethods
|
signupMethod := user.SignupMethods
|
||||||
if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) {
|
if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) && isTokenVerification {
|
||||||
signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth
|
signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth
|
||||||
|
// helpful if user has not signed up with basic auth
|
||||||
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
if user.EmailVerifiedAt == nil {
|
||||||
if err != nil {
|
now := time.Now().Unix()
|
||||||
log.Debug("MFA service not enabled: ", err)
|
user.EmailVerifiedAt = &now
|
||||||
isMFAEnforced = false
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if isMFAEnforced {
|
if !strings.Contains(signupMethod, constants.AuthRecipeMethodMobileOTP) && isOtpVerification {
|
||||||
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
signupMethod = signupMethod + "," + constants.AuthRecipeMethodMobileOTP
|
||||||
|
// helpful if user has not signed up with basic auth
|
||||||
|
if user.PhoneNumberVerifiedAt == nil {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
user.PhoneNumberVerifiedAt = &now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.SignupMethods = signupMethod
|
user.SignupMethods = signupMethod
|
||||||
|
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
// helpful if user has not signed up with basic auth
|
|
||||||
if user.EmailVerifiedAt == nil {
|
|
||||||
now := time.Now().Unix()
|
|
||||||
user.EmailVerifiedAt = &now
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete from verification table
|
|
||||||
err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to delete verification request: ", err)
|
log.Debug("MFA service not enabled: ", err)
|
||||||
return res, err
|
isMFAEnforced = false
|
||||||
|
}
|
||||||
|
if isMFAEnforced {
|
||||||
|
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Provider.UpdateUser(ctx, user)
|
_, err = db.Provider.UpdateUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to update user: ", err)
|
log.Debug("Failed to update user: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
if isTokenVerification {
|
||||||
|
// delete from verification table
|
||||||
|
err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to delete verification request: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isOtpVerification {
|
||||||
|
// delete from otp table
|
||||||
|
err = db.Provider.DeleteOTP(ctx, otpRequest)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to delete otp request: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
Message: `Password updated successfully.`,
|
Message: `Password updated successfully.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||||
// get session from cookie
|
// get session from cookie
|
||||||
claims, err := token.ValidateBrowserSession(gc, sessionToken)
|
claims, err := token.ValidateBrowserSession(gc, sessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to validate session token", err)
|
log.Debug("Failed to validate session token: ", err)
|
||||||
return res, errors.New("unauthorized")
|
return res, errors.New("unauthorized")
|
||||||
}
|
}
|
||||||
userID := claims.Subject
|
userID := claims.Subject
|
||||||
|
|
|
@ -36,7 +36,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
userID, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
tokenData, err := token.GetUserIDFromSessionOrAccessToken(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
log.Debug("Failed GetUserIDFromSessionOrAccessToken: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -48,9 +48,9 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
return res, fmt.Errorf("please enter at least one param to update")
|
return res, fmt.Errorf("please enter at least one param to update")
|
||||||
}
|
}
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"user_id": userID,
|
"user_id": tokenData.UserID,
|
||||||
})
|
})
|
||||||
user, err := db.Provider.GetUserByID(ctx, userID)
|
user, err := db.Provider.GetUserByID(ctx, tokenData.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get user by id: ", err)
|
log.Debug("Failed to get user by id: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
|
|
61
server/test/forgot_password_mobile_test.go
Normal file
61
server/test/forgot_password_mobile_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func forgotPasswordMobileTest(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should run forgot password for mobile`, func(t *testing.T) {
|
||||||
|
req, ctx := createContext(s)
|
||||||
|
phoneNumber := "6240345678"
|
||||||
|
res, err := resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||||
|
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res)
|
||||||
|
forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||||
|
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||||
|
})
|
||||||
|
assert.Nil(t, err, "no errors for forgot password")
|
||||||
|
assert.NotNil(t, forgotPasswordRes)
|
||||||
|
assert.True(t, *forgotPasswordRes.ShouldShowMobileOtpScreen)
|
||||||
|
otpReq, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
mfaSession := uuid.NewString()
|
||||||
|
memorystore.Provider.SetMfaSession(res.User.ID, mfaSession, time.Now().Add(1*time.Minute).Unix())
|
||||||
|
cookie := fmt.Sprintf("%s=%s;", constants.MfaCookieName+"_session", mfaSession)
|
||||||
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
// Reset password
|
||||||
|
resetPasswordRes, err := resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||||
|
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||||
|
Otp: refs.NewStringRef(otpReq.Otp),
|
||||||
|
Password: s.TestInfo.Password + "test",
|
||||||
|
ConfirmPassword: s.TestInfo.Password + "test",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, resetPasswordRes)
|
||||||
|
// Test login
|
||||||
|
loginRes, err := resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||||
|
Password: s.TestInfo.Password + "test",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, loginRes)
|
||||||
|
})
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ func forgotPasswordTest(t *testing.T, s TestSetup) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
forgotPasswordRes, err := resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||||
Email: email,
|
Email: refs.NewStringRef(email),
|
||||||
})
|
})
|
||||||
assert.Nil(t, err, "no errors for forgot password")
|
assert.Nil(t, err, "no errors for forgot password")
|
||||||
assert.NotNil(t, forgotPasswordRes)
|
assert.NotNil(t, forgotPasswordRes)
|
||||||
|
|
|
@ -131,6 +131,7 @@ func TestResolvers(t *testing.T) {
|
||||||
mobileLoginTests(t, s)
|
mobileLoginTests(t, s)
|
||||||
totpLoginTest(t, s)
|
totpLoginTest(t, s)
|
||||||
forgotPasswordTest(t, s)
|
forgotPasswordTest(t, s)
|
||||||
|
forgotPasswordMobileTest(t, s)
|
||||||
resendVerifyEmailTests(t, s)
|
resendVerifyEmailTests(t, s)
|
||||||
resetPasswordTest(t, s)
|
resetPasswordTest(t, s)
|
||||||
verifyEmailTest(t, s)
|
verifyEmailTest(t, s)
|
||||||
|
|
|
@ -35,6 +35,30 @@ func logoutTests(t *testing.T, s TestSetup) {
|
||||||
assert.NotNil(t, verifyRes)
|
assert.NotNil(t, verifyRes)
|
||||||
accessToken := *verifyRes.AccessToken
|
accessToken := *verifyRes.AccessToken
|
||||||
assert.NotEmpty(t, accessToken)
|
assert.NotEmpty(t, accessToken)
|
||||||
|
// Test logout with access token
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||||
|
logoutRes, err := resolvers.LogoutResolver(ctx)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, logoutRes)
|
||||||
|
assert.NotEmpty(t, logoutRes.Message)
|
||||||
|
req.Header.Set("Authorization", "")
|
||||||
|
|
||||||
|
// Test logout with session cookie
|
||||||
|
magicLoginRes, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
|
||||||
|
Email: email,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, magicLoginRes)
|
||||||
|
verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, verificationRequest)
|
||||||
|
verifyRes, err = resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
|
||||||
|
Token: verificationRequest.Token,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, verifyRes)
|
||||||
|
accessToken = *verifyRes.AccessToken
|
||||||
|
assert.NotEmpty(t, accessToken)
|
||||||
claims, err := token.ParseJWTToken(accessToken)
|
claims, err := token.ParseJWTToken(accessToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, claims)
|
assert.NotEmpty(t, claims)
|
||||||
|
|
|
@ -23,37 +23,30 @@ func resetPasswordTest(t *testing.T, s TestSetup) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
_, err = resolvers.ForgotPasswordResolver(ctx, model.ForgotPasswordInput{
|
||||||
Email: email,
|
Email: refs.NewStringRef(email),
|
||||||
})
|
})
|
||||||
assert.Nil(t, err, "no errors for forgot password")
|
assert.Nil(t, err, "no errors for forgot password")
|
||||||
|
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
|
||||||
assert.Nil(t, err, "should get forgot password request")
|
assert.Nil(t, err, "should get forgot password request")
|
||||||
assert.NotNil(t, verificationRequest)
|
assert.NotNil(t, verificationRequest)
|
||||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||||
Token: verificationRequest.Token,
|
Token: refs.NewStringRef(verificationRequest.Token),
|
||||||
Password: "test1",
|
Password: "test1",
|
||||||
ConfirmPassword: "test",
|
ConfirmPassword: "test",
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NotNil(t, err, "passwords don't match")
|
assert.NotNil(t, err, "passwords don't match")
|
||||||
|
|
||||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||||
Token: verificationRequest.Token,
|
Token: refs.NewStringRef(verificationRequest.Token),
|
||||||
Password: "test1",
|
Password: "test1",
|
||||||
ConfirmPassword: "test1",
|
ConfirmPassword: "test1",
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NotNil(t, err, "invalid password")
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||||
Token: verificationRequest.Token,
|
Token: refs.NewStringRef(verificationRequest.Token),
|
||||||
Password: "Test@1234",
|
Password: "Test@1234",
|
||||||
ConfirmPassword: "Test@1234",
|
ConfirmPassword: "Test@1234",
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.Nil(t, err, "password changed successfully")
|
assert.Nil(t, err, "password changed successfully")
|
||||||
|
|
||||||
cleanData(email)
|
cleanData(email)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,6 @@ func CreateAuthToken(gc *gin.Context, user *models.User, roles, scope []string,
|
||||||
AccessToken: &JWTToken{Token: accessToken, ExpiresAt: accessTokenExpiresAt},
|
AccessToken: &JWTToken{Token: accessToken, ExpiresAt: accessTokenExpiresAt},
|
||||||
IDToken: &JWTToken{Token: idToken, ExpiresAt: idTokenExpiresAt},
|
IDToken: &JWTToken{Token: idToken, ExpiresAt: idTokenExpiresAt},
|
||||||
}
|
}
|
||||||
|
|
||||||
if utils.StringSliceContains(scope, "offline_access") {
|
if utils.StringSliceContains(scope, "offline_access") {
|
||||||
refreshToken, refreshTokenExpiresAt, err := CreateRefreshToken(user, roles, scope, hostname, nonce, loginMethod)
|
refreshToken, refreshTokenExpiresAt, err := CreateRefreshToken(user, roles, scope, hostname, nonce, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -354,7 +353,7 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD
|
||||||
}
|
}
|
||||||
token, err := memorystore.Provider.GetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+res.Nonce)
|
token, err := memorystore.Provider.GetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+res.Nonce)
|
||||||
if token == "" || err != nil {
|
if token == "" || err != nil {
|
||||||
log.Debug("invalid browser session:", err)
|
log.Debugf("invalid browser session: %v, key: %s", err, sessionStoreKey+":"+constants.TokenTypeSessionToken+"_"+res.Nonce)
|
||||||
return nil, fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,8 +481,15 @@ func GetIDToken(gc *gin.Context) (string, error) {
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SessionOrAccessTokenData is a struct to hold session or access token data
|
||||||
|
type SessionOrAccessTokenData struct {
|
||||||
|
UserID string
|
||||||
|
LoginMethod string
|
||||||
|
Nonce string
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserIDFromSessionOrAccessToken returns the user id from the session or access token
|
// GetUserIDFromSessionOrAccessToken returns the user id from the session or access token
|
||||||
func GetUserIDFromSessionOrAccessToken(gc *gin.Context) (string, error) {
|
func GetUserIDFromSessionOrAccessToken(gc *gin.Context) (*SessionOrAccessTokenData, error) {
|
||||||
// First try to get the user id from the session
|
// First try to get the user id from the session
|
||||||
isSession := true
|
isSession := true
|
||||||
token, err := cookie.GetSession(gc)
|
token, err := cookie.GetSession(gc)
|
||||||
|
@ -493,22 +499,30 @@ func GetUserIDFromSessionOrAccessToken(gc *gin.Context) (string, error) {
|
||||||
token, err = GetAccessToken(gc)
|
token, err = GetAccessToken(gc)
|
||||||
if err != nil || token == "" {
|
if err != nil || token == "" {
|
||||||
log.Debug("Failed to get access token: ", err)
|
log.Debug("Failed to get access token: ", err)
|
||||||
return "", fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isSession {
|
if isSession {
|
||||||
claims, err := ValidateBrowserSession(gc, token)
|
claims, err := ValidateBrowserSession(gc, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to validate session token: ", err)
|
log.Debug("Failed to validate session token: ", err)
|
||||||
return "", fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
return claims.Subject, nil
|
return &SessionOrAccessTokenData{
|
||||||
|
UserID: claims.Subject,
|
||||||
|
LoginMethod: claims.LoginMethod,
|
||||||
|
Nonce: claims.Nonce,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
// If not session, then validate the access token
|
// If not session, then validate the access token
|
||||||
claims, err := ValidateAccessToken(gc, token)
|
claims, err := ValidateAccessToken(gc, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to validate access token: ", err)
|
log.Debug("Failed to validate access token: ", err)
|
||||||
return "", fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
return claims["sub"].(string), nil
|
return &SessionOrAccessTokenData{
|
||||||
|
UserID: claims["sub"].(string),
|
||||||
|
LoginMethod: claims["login_method"].(string),
|
||||||
|
Nonce: claims["nonce"].(string),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user