mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 04:26:33 +00:00
Improve verification and resend code logic, added oidc and ldap
This commit is contained in:
@@ -26,6 +26,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.AuthTokens, "aliasId"))) {
|
||||||
|
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||||
|
t.string("aliasId").nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
@@ -34,4 +40,10 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
t.dropColumn("isEmailVerified");
|
t.dropColumn("isEmailVerified");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await knex.schema.hasColumn(TableName.AuthTokens, "aliasId")) {
|
||||||
|
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||||
|
t.dropColumn("aliasId");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ export const AuthTokensSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
userId: z.string().uuid().nullable().optional(),
|
userId: z.string().uuid().nullable().optional(),
|
||||||
orgId: z.string().uuid().nullable().optional()
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
aliasId: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAuthTokens = z.infer<typeof AuthTokensSchema>;
|
export type TAuthTokens = z.infer<typeof AuthTokensSchema>;
|
||||||
|
|||||||
@@ -400,15 +400,13 @@ export const ldapConfigServiceFactory = ({
|
|||||||
|
|
||||||
userAlias = await userDAL.transaction(async (tx) => {
|
userAlias = await userDAL.transaction(async (tx) => {
|
||||||
let newUser: TUsers | undefined;
|
let newUser: TUsers | undefined;
|
||||||
if (serverCfg.trustLdapEmails) {
|
newUser = await userDAL.findOne(
|
||||||
newUser = await userDAL.findOne(
|
{
|
||||||
{
|
email: email.toLowerCase(),
|
||||||
email: email.toLowerCase(),
|
isEmailVerified: true
|
||||||
isEmailVerified: true
|
},
|
||||||
},
|
tx
|
||||||
tx
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newUser) {
|
if (!newUser) {
|
||||||
const uniqueUsername = await normalizeUsername(username, userDAL);
|
const uniqueUsername = await normalizeUsername(username, userDAL);
|
||||||
@@ -433,7 +431,8 @@ export const ldapConfigServiceFactory = ({
|
|||||||
aliasType: UserAliasType.LDAP,
|
aliasType: UserAliasType.LDAP,
|
||||||
externalId,
|
externalId,
|
||||||
emails: [email],
|
emails: [email],
|
||||||
orgId
|
orgId,
|
||||||
|
isEmailVerified: serverCfg.trustLdapEmails
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -556,15 +555,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
return newUser;
|
return newUser;
|
||||||
});
|
});
|
||||||
|
|
||||||
const isUserCompleted = Boolean(user.isAccepted);
|
const isUserCompleted = Boolean(user.isAccepted) && userAlias.isEmailVerified;
|
||||||
|
|
||||||
const providerAuthToken = crypto.jwt().sign(
|
const providerAuthToken = crypto.jwt().sign(
|
||||||
{
|
{
|
||||||
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
hasExchangedPrivateKey: true,
|
hasExchangedPrivateKey: true,
|
||||||
...(user.email && { email: user.email, isEmailVerified: user.isEmailVerified }),
|
...(user.email && { email: user.email, isEmailVerified: userAlias.isEmailVerified }),
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
organizationName: organization.name,
|
organizationName: organization.name,
|
||||||
@@ -572,6 +570,7 @@ export const ldapConfigServiceFactory = ({
|
|||||||
organizationSlug: organization.slug,
|
organizationSlug: organization.slug,
|
||||||
authMethod: AuthMethod.LDAP,
|
authMethod: AuthMethod.LDAP,
|
||||||
authType: UserAliasType.LDAP,
|
authType: UserAliasType.LDAP,
|
||||||
|
aliasId: userAlias.id,
|
||||||
isUserCompleted,
|
isUserCompleted,
|
||||||
...(relayState
|
...(relayState
|
||||||
? {
|
? {
|
||||||
@@ -585,10 +584,11 @@ export const ldapConfigServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (user.email && !user.isEmailVerified) {
|
if (user.email && !userAlias.isEmailVerified) {
|
||||||
const token = await tokenService.createTokenForUser({
|
const token = await tokenService.createTokenForUser({
|
||||||
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
||||||
userId: user.id
|
userId: user.id,
|
||||||
|
aliasId: userAlias.id
|
||||||
});
|
});
|
||||||
|
|
||||||
await smtpService.sendMail({
|
await smtpService.sendMail({
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export const oidcConfigServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const userAlias = await userAliasDAL.findOne({
|
let userAlias = await userAliasDAL.findOne({
|
||||||
externalId,
|
externalId,
|
||||||
orgId,
|
orgId,
|
||||||
aliasType: UserAliasType.OIDC
|
aliasType: UserAliasType.OIDC
|
||||||
@@ -231,32 +231,29 @@ export const oidcConfigServiceFactory = ({
|
|||||||
} else {
|
} else {
|
||||||
user = await userDAL.transaction(async (tx) => {
|
user = await userDAL.transaction(async (tx) => {
|
||||||
let newUser: TUsers | undefined;
|
let newUser: TUsers | undefined;
|
||||||
|
// we prioritize getting the most complete user to create the new alias under
|
||||||
|
newUser = await userDAL.findOne(
|
||||||
|
{
|
||||||
|
email,
|
||||||
|
isEmailVerified: true
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
if (serverCfg.trustOidcEmails) {
|
if (!newUser) {
|
||||||
// we prioritize getting the most complete user to create the new alias under
|
// this fetches user entries created via invites
|
||||||
newUser = await userDAL.findOne(
|
newUser = await userDAL.findOne(
|
||||||
{
|
{
|
||||||
email,
|
username: email
|
||||||
isEmailVerified: true
|
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!newUser) {
|
if (newUser && !newUser.isEmailVerified) {
|
||||||
// this fetches user entries created via invites
|
// we automatically mark it as email-verified because we've configured trust for OIDC emails
|
||||||
newUser = await userDAL.findOne(
|
newUser = await userDAL.updateById(newUser.id, {
|
||||||
{
|
isEmailVerified: serverCfg.trustOidcEmails
|
||||||
username: email
|
});
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
if (newUser && !newUser.isEmailVerified) {
|
|
||||||
// we automatically mark it as email-verified because we've configured trust for OIDC emails
|
|
||||||
newUser = await userDAL.updateById(newUser.id, {
|
|
||||||
isEmailVerified: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,13 +273,14 @@ export const oidcConfigServiceFactory = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await userAliasDAL.create(
|
userAlias = await userAliasDAL.create(
|
||||||
{
|
{
|
||||||
userId: newUser.id,
|
userId: newUser.id,
|
||||||
aliasType: UserAliasType.OIDC,
|
aliasType: UserAliasType.OIDC,
|
||||||
externalId,
|
externalId,
|
||||||
emails: email ? [email] : [],
|
emails: email ? [email] : [],
|
||||||
orgId
|
orgId,
|
||||||
|
isEmailVerified: serverCfg.trustOidcEmails
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -404,19 +402,20 @@ export const oidcConfigServiceFactory = ({
|
|||||||
|
|
||||||
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
|
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
|
||||||
|
|
||||||
const isUserCompleted = Boolean(user.isAccepted);
|
const isUserCompleted = Boolean(user.isAccepted) && userAlias.isEmailVerified;
|
||||||
const providerAuthToken = crypto.jwt().sign(
|
const providerAuthToken = crypto.jwt().sign(
|
||||||
{
|
{
|
||||||
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
...(user.email && { email: user.email, isEmailVerified: user.isEmailVerified }),
|
...(user.email && { email: user.email, isEmailVerified: userAlias.isEmailVerified }),
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
organizationName: organization.name,
|
organizationName: organization.name,
|
||||||
organizationId: organization.id,
|
organizationId: organization.id,
|
||||||
organizationSlug: organization.slug,
|
organizationSlug: organization.slug,
|
||||||
hasExchangedPrivateKey: true,
|
hasExchangedPrivateKey: true,
|
||||||
|
aliasId: userAlias.id,
|
||||||
authMethod: AuthMethod.OIDC,
|
authMethod: AuthMethod.OIDC,
|
||||||
authType: UserAliasType.OIDC,
|
authType: UserAliasType.OIDC,
|
||||||
isUserCompleted,
|
isUserCompleted,
|
||||||
@@ -430,10 +429,11 @@ export const oidcConfigServiceFactory = ({
|
|||||||
|
|
||||||
await oidcConfigDAL.update({ orgId }, { lastUsed: new Date() });
|
await oidcConfigDAL.update({ orgId }, { lastUsed: new Date() });
|
||||||
|
|
||||||
if (user.email && !user.isEmailVerified) {
|
if (user.email && !userAlias.isEmailVerified) {
|
||||||
const token = await tokenService.createTokenForUser({
|
const token = await tokenService.createTokenForUser({
|
||||||
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
||||||
userId: user.id
|
userId: user.id,
|
||||||
|
aliasId: userAlias.id
|
||||||
});
|
});
|
||||||
|
|
||||||
await smtpService
|
await smtpService
|
||||||
|
|||||||
@@ -443,7 +443,8 @@ export const samlConfigServiceFactory = ({
|
|||||||
if (user.email && !userAlias.isEmailVerified) {
|
if (user.email && !userAlias.isEmailVerified) {
|
||||||
const token = await tokenService.createTokenForUser({
|
const token = await tokenService.createTokenForUser({
|
||||||
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
||||||
userId: user.id
|
userId: user.id,
|
||||||
|
aliasId: userAlias.id
|
||||||
});
|
});
|
||||||
|
|
||||||
await smtpService.sendMail({
|
await smtpService.sendMail({
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: z.object({
|
body: z.object({
|
||||||
referer: z.string().trim()
|
token: z.string().trim()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({})
|
200: z.object({})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
await server.services.user.sendEmailVerificationCode(req.headers.referer);
|
await server.services.user.sendEmailVerificationCode(req.body.token);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAuthTokenServiceFactoryDep) => {
|
export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAuthTokenServiceFactoryDep) => {
|
||||||
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
|
const createTokenForUser = async ({ type, userId, orgId, aliasId }: TCreateTokenForUserDTO) => {
|
||||||
const { token, ...tkCfg } = getTokenConfig(type);
|
const { token, ...tkCfg } = getTokenConfig(type);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const tokenHash = await crypto.hashing().createHash(token, appCfg.SALT_ROUNDS);
|
const tokenHash = await crypto.hashing().createHash(token, appCfg.SALT_ROUNDS);
|
||||||
@@ -88,7 +88,8 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu
|
|||||||
type,
|
type,
|
||||||
userId,
|
userId,
|
||||||
orgId,
|
orgId,
|
||||||
triesLeft: tkCfg?.triesLeft
|
triesLeft: tkCfg?.triesLeft,
|
||||||
|
aliasId
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export type TCreateTokenForUserDTO = {
|
|||||||
type: TokenType;
|
type: TokenType;
|
||||||
userId: string;
|
userId: string;
|
||||||
orgId?: string;
|
orgId?: string;
|
||||||
|
aliasId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreateOrgInviteTokenDTO = {
|
export type TCreateOrgInviteTokenDTO = {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { TokenType } from "@app/services/auth-token/auth-token-types";
|
|||||||
import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
|
import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
|
||||||
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
|
|
||||||
import { AuthMethod } from "../auth/auth-type";
|
import { AuthMethod, AuthTokenType } from "../auth/auth-type";
|
||||||
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
|
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
|
||||||
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
||||||
import { TUserAliasDALFactory } from "../user-alias/user-alias-dal";
|
import { TUserAliasDALFactory } from "../user-alias/user-alias-dal";
|
||||||
@@ -39,7 +39,7 @@ type TUserServiceFactoryDep = {
|
|||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
||||||
smtpService: Pick<TSmtpService, "sendMail">;
|
smtpService: Pick<TSmtpService, "sendMail">;
|
||||||
permissionService: TPermissionServiceFactory;
|
permissionService: TPermissionServiceFactory;
|
||||||
userAliasDAL: Pick<TUserAliasDALFactory, "findOne" | "find" | "update">;
|
userAliasDAL: Pick<TUserAliasDALFactory, "findOne" | "find" | "updateById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUserServiceFactory = ReturnType<typeof userServiceFactory>;
|
export type TUserServiceFactory = ReturnType<typeof userServiceFactory>;
|
||||||
@@ -54,23 +54,23 @@ export const userServiceFactory = ({
|
|||||||
permissionService,
|
permissionService,
|
||||||
userAliasDAL
|
userAliasDAL
|
||||||
}: TUserServiceFactoryDep) => {
|
}: TUserServiceFactoryDep) => {
|
||||||
const sendEmailVerificationCode = async (referer: string) => {
|
const sendEmailVerificationCode = async (token: string) => {
|
||||||
const url = new URL(referer);
|
const { authType, aliasId, username, authTokenType } = crypto.jwt().decode(token) as {
|
||||||
const refererToken = url.searchParams.get("token");
|
|
||||||
if (!refererToken)
|
|
||||||
throw new BadRequestError({ name: "Failed to send email verification code due to no token on referer" });
|
|
||||||
const { authType, aliasId, username } = crypto.jwt().decode(refererToken) as {
|
|
||||||
authType: string;
|
authType: string;
|
||||||
aliasId: string;
|
aliasId?: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
authTokenType: AuthTokenType;
|
||||||
};
|
};
|
||||||
|
if (authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new BadRequestError({ name: "Invalid auth token type" });
|
||||||
|
|
||||||
// akhilmhdh: case sensitive email resolution
|
// akhilmhdh: case sensitive email resolution
|
||||||
const users = await userDAL.findUserByUsername(username);
|
const users = await userDAL.findUserByUsername(username);
|
||||||
const user = users?.length > 1 ? users.find((el) => el.username === username) : users?.[0];
|
const user = users?.length > 1 ? users.find((el) => el.username === username) : users?.[0];
|
||||||
if (!user) throw new NotFoundError({ name: `User with username '${username}' not found` });
|
if (!user) throw new NotFoundError({ name: `User with username '${username}' not found` });
|
||||||
let { isEmailVerified } = user;
|
let { isEmailVerified } = user;
|
||||||
const userAlias = await userAliasDAL.findOne({ userId: user.id, aliasType: authType, id: aliasId });
|
if (aliasId) {
|
||||||
if (userAlias) {
|
const userAlias = await userAliasDAL.findOne({ userId: user.id, aliasType: authType, id: aliasId });
|
||||||
|
if (!userAlias) throw new NotFoundError({ name: `User alias with ID '${aliasId}' not found` });
|
||||||
isEmailVerified = userAlias.isEmailVerified;
|
isEmailVerified = userAlias.isEmailVerified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,9 +79,10 @@ export const userServiceFactory = ({
|
|||||||
if (isEmailVerified)
|
if (isEmailVerified)
|
||||||
throw new BadRequestError({ name: "Failed to send email verification code due to email already verified" });
|
throw new BadRequestError({ name: "Failed to send email verification code due to email already verified" });
|
||||||
|
|
||||||
const token = await tokenService.createTokenForUser({
|
const userToken = await tokenService.createTokenForUser({
|
||||||
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
||||||
userId: user.id
|
userId: user.id,
|
||||||
|
aliasId
|
||||||
});
|
});
|
||||||
|
|
||||||
await smtpService.sendMail({
|
await smtpService.sendMail({
|
||||||
@@ -89,7 +90,7 @@ export const userServiceFactory = ({
|
|||||||
subjectLine: "Infisical confirmation code",
|
subjectLine: "Infisical confirmation code",
|
||||||
recipients: [user.email],
|
recipients: [user.email],
|
||||||
substitutions: {
|
substitutions: {
|
||||||
code: token
|
code: userToken
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -114,19 +115,20 @@ export const userServiceFactory = ({
|
|||||||
if (!user.email)
|
if (!user.email)
|
||||||
throw new BadRequestError({ name: "Failed to verify email verification code due to no email on user" });
|
throw new BadRequestError({ name: "Failed to verify email verification code due to no email on user" });
|
||||||
|
|
||||||
const userAliases = await userAliasDAL.find({ userId: user.id });
|
const token = await tokenService.validateTokenForUser({
|
||||||
if (user.isEmailVerified && userAliases?.every((alias) => alias.isEmailVerified))
|
|
||||||
throw new BadRequestError({ name: "Failed to verify email verification code due to email already verified" });
|
|
||||||
|
|
||||||
await tokenService.validateTokenForUser({
|
|
||||||
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
type: TokenType.TOKEN_EMAIL_VERIFICATION,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
code
|
code
|
||||||
});
|
});
|
||||||
|
|
||||||
const userEmails = user?.email ? await userDAL.find({ email: user.email }) : [];
|
if (token?.aliasId) {
|
||||||
|
const userAlias = await userAliasDAL.findOne({ userId: user.id, id: token.aliasId });
|
||||||
|
if (userAlias?.isEmailVerified)
|
||||||
|
throw new BadRequestError({ name: "Failed to verify email verification code due to email already verified" });
|
||||||
|
|
||||||
await userAliasDAL.update({ userId: user.id }, { isEmailVerified: true });
|
await userAliasDAL.updateById(token.aliasId, { isEmailVerified: true });
|
||||||
|
}
|
||||||
|
const userEmails = user?.email ? await userDAL.find({ email: user.email }) : [];
|
||||||
|
|
||||||
await userDAL.updateById(user.id, {
|
await userDAL.updateById(user.id, {
|
||||||
isEmailVerified: true,
|
isEmailVerified: true,
|
||||||
|
|||||||
@@ -26,16 +26,16 @@ export const useAddUserToWsNonE2EE = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendEmailVerificationCode = async (username: string) => {
|
export const sendEmailVerificationCode = async (token: string) => {
|
||||||
return apiRequest.post("/api/v2/users/me/emails/code", {
|
return apiRequest.post("/api/v2/users/me/emails/code", {
|
||||||
username
|
token
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSendEmailVerificationCode = () => {
|
export const useSendEmailVerificationCode = () => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (username: string) => {
|
mutationFn: async (token: string) => {
|
||||||
await sendEmailVerificationCode(username);
|
await sendEmailVerificationCode(token);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+10
-1
@@ -114,7 +114,16 @@ export const EmailConfirmationStep = ({
|
|||||||
|
|
||||||
const resendCode = async () => {
|
const resendCode = async () => {
|
||||||
try {
|
try {
|
||||||
await sendEmailVerificationCode(username);
|
const queryParams = new URLSearchParams(window.location.search);
|
||||||
|
const token = queryParams.get("token");
|
||||||
|
if (!token) {
|
||||||
|
createNotification({
|
||||||
|
text: "Failed to resend code, no token found",
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await sendEmailVerificationCode(token);
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Successfully resent code",
|
text: "Successfully resent code",
|
||||||
type: "success"
|
type: "success"
|
||||||
|
|||||||
Reference in New Issue
Block a user