mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor(core,experience): generate totp qrcode on server side (#4646)
This commit is contained in:
parent
42dbc0e62c
commit
03e654b459
7 changed files with 23 additions and 20 deletions
|
@ -35,12 +35,12 @@
|
|||
"@logto/console": "workspace:*",
|
||||
"@logto/core-kit": "workspace:^2.2.0",
|
||||
"@logto/demo-app": "workspace:*",
|
||||
"@logto/experience": "workspace:*",
|
||||
"@logto/language-kit": "workspace:^1.0.0",
|
||||
"@logto/phrases": "workspace:^1.5.0",
|
||||
"@logto/phrases-experience": "workspace:^1.3.1",
|
||||
"@logto/schemas": "workspace:^1.10.0",
|
||||
"@logto/shared": "workspace:^3.0.0",
|
||||
"@logto/experience": "workspace:*",
|
||||
"@silverhand/essentials": "^2.8.4",
|
||||
"@withtyped/client": "^0.7.22",
|
||||
"chalk": "^5.0.0",
|
||||
|
@ -72,6 +72,7 @@
|
|||
"otplib": "^12.0.1",
|
||||
"p-retry": "^6.0.0",
|
||||
"pg-protocol": "^1.6.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"redis": "^4.6.5",
|
||||
"roarr": "^7.11.0",
|
||||
"semver": "^7.3.8",
|
||||
|
@ -98,6 +99,7 @@
|
|||
"@types/koa__cors": "^4.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/oidc-provider": "^8.0.0",
|
||||
"@types/qrcode": "^1.5.2",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@types/sinon": "^10.0.13",
|
||||
"@types/supertest": "^2.0.11",
|
||||
|
|
|
@ -194,6 +194,7 @@ describe('interaction routes', () => {
|
|||
expect(storeInteractionResult).toBeCalled();
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.body).toHaveProperty('secret');
|
||||
expect(response.body).toHaveProperty('secretQrCode');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { MfaFactor, requestVerificationCodePayloadGuard } from '@logto/schemas';
|
||||
import type Router from 'koa-router';
|
||||
import { type IRouterParamContext } from 'koa-router';
|
||||
import qrcode from 'qrcode';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { type WithLogContext } from '#src/middleware/koa-audit-log.js';
|
||||
|
@ -78,6 +79,7 @@ export default function additionalRoutes<T extends IRouterParamContext>(
|
|||
status: [200],
|
||||
response: z.object({
|
||||
secret: z.string(),
|
||||
secretQrCode: z.string(),
|
||||
}),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
|
@ -94,7 +96,10 @@ export default function additionalRoutes<T extends IRouterParamContext>(
|
|||
true
|
||||
);
|
||||
|
||||
ctx.body = { secret };
|
||||
ctx.body = {
|
||||
secret,
|
||||
secretQrCode: await qrcode.toDataURL(`otpauth://totp/?secret=${secret}`),
|
||||
};
|
||||
|
||||
return next();
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
"@testing-library/react": "^14.0.0",
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/qrcode": "^1.5.2",
|
||||
"@types/react": "^18.0.31",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/react-helmet": "^6.1.6",
|
||||
|
@ -118,8 +117,5 @@
|
|||
"stylelint": {
|
||||
"extends": "@silverhand/eslint-config-react/.stylelintrc"
|
||||
},
|
||||
"prettier": "@silverhand/eslint-config/.prettierrc",
|
||||
"dependencies": {
|
||||
"qrcode": "^1.5.3"
|
||||
}
|
||||
"prettier": "@silverhand/eslint-config/.prettierrc"
|
||||
}
|
||||
|
|
|
@ -226,7 +226,9 @@ export const linkWithSocial = async (connectorId: string) => {
|
|||
};
|
||||
|
||||
export const createTotpSecret = async () =>
|
||||
api.post(`${interactionPrefix}/${verificationPath}/totp`).json<{ secret: string }>();
|
||||
api
|
||||
.post(`${interactionPrefix}/${verificationPath}/totp`)
|
||||
.json<{ secret: string; secretQrCode: string }>();
|
||||
|
||||
export const bindMfa = async (payload: BindMfaPayload) => {
|
||||
await api.put(`${interactionPrefix}/bind-mfa`, { json: payload });
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { MfaFactor } from '@logto/schemas';
|
||||
import qrcode from 'qrcode';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
|
@ -28,13 +27,12 @@ const useStartTotpBinding = ({ replace }: Options = {}) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const { secret } = result ?? {};
|
||||
const { secret, secretQrCode } = result ?? {};
|
||||
|
||||
if (secret) {
|
||||
if (secret && secretQrCode) {
|
||||
const state: TotpBindingState = {
|
||||
secret,
|
||||
// Todo @wangsijie generate QR code on the server side
|
||||
secretQrCode: await qrcode.toDataURL(`otpauth://totp/?secret=${secret}`),
|
||||
secretQrCode,
|
||||
availableFactors,
|
||||
};
|
||||
navigate({ pathname: `/${UserMfaFlow.MfaBinding}/${MfaFactor.TOTP}` }, { replace, state });
|
||||
|
|
|
@ -3262,6 +3262,9 @@ importers:
|
|||
pg-protocol:
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0
|
||||
qrcode:
|
||||
specifier: ^1.5.3
|
||||
version: 1.5.3
|
||||
redis:
|
||||
specifier: ^4.6.5
|
||||
version: 4.6.5
|
||||
|
@ -3335,6 +3338,9 @@ importers:
|
|||
'@types/oidc-provider':
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0
|
||||
'@types/qrcode':
|
||||
specifier: ^1.5.2
|
||||
version: 1.5.2
|
||||
'@types/semver':
|
||||
specifier: ^7.3.12
|
||||
version: 7.3.12
|
||||
|
@ -3478,10 +3484,6 @@ importers:
|
|||
version: 3.22.3
|
||||
|
||||
packages/experience:
|
||||
dependencies:
|
||||
qrcode:
|
||||
specifier: ^1.5.3
|
||||
version: 1.5.3
|
||||
devDependencies:
|
||||
'@jest/types':
|
||||
specifier: ^29.5.0
|
||||
|
@ -3558,9 +3560,6 @@ importers:
|
|||
'@types/jest':
|
||||
specifier: ^29.4.0
|
||||
version: 29.4.0
|
||||
'@types/qrcode':
|
||||
specifier: ^1.5.2
|
||||
version: 1.5.2
|
||||
'@types/react':
|
||||
specifier: ^18.0.31
|
||||
version: 18.0.31
|
||||
|
|
Loading…
Reference in a new issue