fix(email-verification): prevent double email validation (#12250)
Fix #12177 Fix #12171 --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -812,17 +812,6 @@ export enum HealthIndicatorId {
|
||||
worker = 'worker'
|
||||
}
|
||||
|
||||
export type IdFilter = {
|
||||
eq?: InputMaybe<Scalars['ID']['input']>;
|
||||
gt?: InputMaybe<Scalars['ID']['input']>;
|
||||
gte?: InputMaybe<Scalars['ID']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['ID']['input']>>;
|
||||
is?: InputMaybe<FilterIs>;
|
||||
lt?: InputMaybe<Scalars['ID']['input']>;
|
||||
lte?: InputMaybe<Scalars['ID']['input']>;
|
||||
neq?: InputMaybe<Scalars['ID']['input']>;
|
||||
};
|
||||
|
||||
export enum IdentityProviderType {
|
||||
OIDC = 'OIDC',
|
||||
SAML = 'SAML'
|
||||
@ -1254,6 +1243,7 @@ export type MutationGetLoginTokenFromCredentialsArgs = {
|
||||
|
||||
export type MutationGetLoginTokenFromEmailVerificationTokenArgs = {
|
||||
captchaToken?: InputMaybe<Scalars['String']['input']>;
|
||||
email: Scalars['String']['input'];
|
||||
emailVerificationToken: Scalars['String']['input'];
|
||||
origin: Scalars['String']['input'];
|
||||
};
|
||||
@ -1552,7 +1542,7 @@ export type ObjectRecordFilterInput = {
|
||||
and?: InputMaybe<Array<ObjectRecordFilterInput>>;
|
||||
createdAt?: InputMaybe<DateFilter>;
|
||||
deletedAt?: InputMaybe<DateFilter>;
|
||||
id?: InputMaybe<IdFilter>;
|
||||
id?: InputMaybe<UuidFilter>;
|
||||
not?: InputMaybe<ObjectRecordFilterInput>;
|
||||
or?: InputMaybe<Array<ObjectRecordFilterInput>>;
|
||||
updatedAt?: InputMaybe<DateFilter>;
|
||||
@ -2317,6 +2307,17 @@ export type TransientToken = {
|
||||
transientToken: AuthToken;
|
||||
};
|
||||
|
||||
export type UuidFilter = {
|
||||
eq?: InputMaybe<Scalars['UUID']['input']>;
|
||||
gt?: InputMaybe<Scalars['UUID']['input']>;
|
||||
gte?: InputMaybe<Scalars['UUID']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['UUID']['input']>>;
|
||||
is?: InputMaybe<FilterIs>;
|
||||
lt?: InputMaybe<Scalars['UUID']['input']>;
|
||||
lte?: InputMaybe<Scalars['UUID']['input']>;
|
||||
neq?: InputMaybe<Scalars['UUID']['input']>;
|
||||
};
|
||||
|
||||
export type UuidFilterComparison = {
|
||||
eq?: InputMaybe<Scalars['UUID']['input']>;
|
||||
gt?: InputMaybe<Scalars['UUID']['input']>;
|
||||
|
||||
@ -1129,6 +1129,7 @@ export type MutationGetLoginTokenFromCredentialsArgs = {
|
||||
|
||||
export type MutationGetLoginTokenFromEmailVerificationTokenArgs = {
|
||||
captchaToken?: InputMaybe<Scalars['String']>;
|
||||
email: Scalars['String'];
|
||||
emailVerificationToken: Scalars['String'];
|
||||
origin: Scalars['String'];
|
||||
};
|
||||
@ -2626,6 +2627,7 @@ export type GetLoginTokenFromCredentialsMutation = { __typename?: 'Mutation', ge
|
||||
|
||||
export type GetLoginTokenFromEmailVerificationTokenMutationVariables = Exact<{
|
||||
emailVerificationToken: Scalars['String'];
|
||||
email: Scalars['String'];
|
||||
captchaToken?: InputMaybe<Scalars['String']>;
|
||||
origin: Scalars['String'];
|
||||
}>;
|
||||
@ -2749,6 +2751,7 @@ export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typ
|
||||
export type SearchQueryVariables = Exact<{
|
||||
searchInput: Scalars['String'];
|
||||
limit: Scalars['Int'];
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
excludedObjectNameSingulars?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
|
||||
includedObjectNameSingulars?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
|
||||
filter?: InputMaybe<ObjectRecordFilterInput>;
|
||||
@ -3885,9 +3888,10 @@ export type GetLoginTokenFromCredentialsMutationHookResult = ReturnType<typeof u
|
||||
export type GetLoginTokenFromCredentialsMutationResult = Apollo.MutationResult<GetLoginTokenFromCredentialsMutation>;
|
||||
export type GetLoginTokenFromCredentialsMutationOptions = Apollo.BaseMutationOptions<GetLoginTokenFromCredentialsMutation, GetLoginTokenFromCredentialsMutationVariables>;
|
||||
export const GetLoginTokenFromEmailVerificationTokenDocument = gql`
|
||||
mutation GetLoginTokenFromEmailVerificationToken($emailVerificationToken: String!, $captchaToken: String, $origin: String!) {
|
||||
mutation GetLoginTokenFromEmailVerificationToken($emailVerificationToken: String!, $email: String!, $captchaToken: String, $origin: String!) {
|
||||
getLoginTokenFromEmailVerificationToken(
|
||||
emailVerificationToken: $emailVerificationToken
|
||||
email: $email
|
||||
captchaToken: $captchaToken
|
||||
origin: $origin
|
||||
) {
|
||||
@ -3917,6 +3921,7 @@ export type GetLoginTokenFromEmailVerificationTokenMutationFn = Apollo.MutationF
|
||||
* const [getLoginTokenFromEmailVerificationTokenMutation, { data, loading, error }] = useGetLoginTokenFromEmailVerificationTokenMutation({
|
||||
* variables: {
|
||||
* emailVerificationToken: // value for 'emailVerificationToken'
|
||||
* email: // value for 'email'
|
||||
* captchaToken: // value for 'captchaToken'
|
||||
* origin: // value for 'origin'
|
||||
* },
|
||||
@ -4641,10 +4646,11 @@ export type GetClientConfigQueryHookResult = ReturnType<typeof useGetClientConfi
|
||||
export type GetClientConfigLazyQueryHookResult = ReturnType<typeof useGetClientConfigLazyQuery>;
|
||||
export type GetClientConfigQueryResult = Apollo.QueryResult<GetClientConfigQuery, GetClientConfigQueryVariables>;
|
||||
export const SearchDocument = gql`
|
||||
query Search($searchInput: String!, $limit: Int!, $excludedObjectNameSingulars: [String!], $includedObjectNameSingulars: [String!], $filter: ObjectRecordFilterInput) {
|
||||
query Search($searchInput: String!, $limit: Int!, $after: String, $excludedObjectNameSingulars: [String!], $includedObjectNameSingulars: [String!], $filter: ObjectRecordFilterInput) {
|
||||
search(
|
||||
searchInput: $searchInput
|
||||
limit: $limit
|
||||
after: $after
|
||||
excludedObjectNameSingulars: $excludedObjectNameSingulars
|
||||
includedObjectNameSingulars: $includedObjectNameSingulars
|
||||
filter: $filter
|
||||
@ -4682,6 +4688,7 @@ export const SearchDocument = gql`
|
||||
* variables: {
|
||||
* searchInput: // value for 'searchInput'
|
||||
* limit: // value for 'limit'
|
||||
* after: // value for 'after'
|
||||
* excludedObjectNameSingulars: // value for 'excludedObjectNameSingulars'
|
||||
* includedObjectNameSingulars: // value for 'includedObjectNameSingulars'
|
||||
* filter: // value for 'filter'
|
||||
|
||||
@ -2,6 +2,7 @@ import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
|
||||
import { useVerifyLogin } from '@/auth/hooks/useVerifyLogin';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
@ -41,7 +42,10 @@ export const VerifyEmailEffect = () => {
|
||||
|
||||
try {
|
||||
const { loginToken, workspaceUrls } =
|
||||
await getLoginTokenFromEmailVerificationToken(emailVerificationToken);
|
||||
await getLoginTokenFromEmailVerificationToken(
|
||||
emailVerificationToken,
|
||||
email,
|
||||
);
|
||||
|
||||
enqueueSnackBar(t`Email verified.`, {
|
||||
dedupeKey: 'email-verification-dedupe-key',
|
||||
@ -56,10 +60,23 @@ export const VerifyEmailEffect = () => {
|
||||
}
|
||||
verifyLoginToken(loginToken.token);
|
||||
} catch (error) {
|
||||
enqueueSnackBar(t`Email verification failed.`, {
|
||||
const message: string =
|
||||
error instanceof ApolloError
|
||||
? error.message
|
||||
: 'Email verification failed';
|
||||
|
||||
enqueueSnackBar(t`${message}`, {
|
||||
dedupeKey: 'email-verification-error-dedupe-key',
|
||||
variant: SnackBarVariant.Error,
|
||||
});
|
||||
if (
|
||||
error instanceof ApolloError &&
|
||||
error.graphQLErrors[0].extensions?.subCode ===
|
||||
'EMAIL_ALREADY_VERIFIED'
|
||||
) {
|
||||
navigate(AppPath.SignInUp);
|
||||
}
|
||||
|
||||
setIsError(true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,11 +3,13 @@ import { gql } from '@apollo/client';
|
||||
export const GET_LOGIN_TOKEN_FROM_EMAIL_VERIFICATION_TOKEN = gql`
|
||||
mutation GetLoginTokenFromEmailVerificationToken(
|
||||
$emailVerificationToken: String!
|
||||
$email: String!
|
||||
$captchaToken: String
|
||||
$origin: String!
|
||||
) {
|
||||
getLoginTokenFromEmailVerificationToken(
|
||||
emailVerificationToken: $emailVerificationToken
|
||||
email: $email
|
||||
captchaToken: $captchaToken
|
||||
origin: $origin
|
||||
) {
|
||||
|
||||
@ -210,9 +210,14 @@ export const useAuth = () => {
|
||||
);
|
||||
|
||||
const handleGetLoginTokenFromEmailVerificationToken = useCallback(
|
||||
async (emailVerificationToken: string, captchaToken?: string) => {
|
||||
async (
|
||||
emailVerificationToken: string,
|
||||
email: string,
|
||||
captchaToken?: string,
|
||||
) => {
|
||||
const loginTokenResult = await getLoginTokenFromEmailVerificationToken({
|
||||
variables: {
|
||||
email,
|
||||
emailVerificationToken,
|
||||
captchaToken,
|
||||
origin,
|
||||
|
||||
Reference in New Issue
Block a user