diff --git a/configure.ts b/configure.ts index 7966ff5..811d0cb 100644 --- a/configure.ts +++ b/configure.ts @@ -41,7 +41,7 @@ export async function configure(command: ConfigureCommand) { } const shouldMakeController = await command.prompt.confirm( - 'Do you want to create controller and routes for a basic 2FA flow?', + 'Do you want to create controller and routes for a basic 2FA flow (API)?', { default: false, hint: 'You should be using @adonisjs/auth', diff --git a/package.json b/package.json index 745f595..e3b8222 100644 --- a/package.json +++ b/package.json @@ -83,11 +83,15 @@ "html" ], "exclude": [ - "tests/**" + "tests/**", + "docs/**" ] }, "eslintConfig": { - "extends": "@adonisjs/eslint-config/package" + "extends": "@adonisjs/eslint-config/package", + "ignorePatterns": [ + "docs/" + ] }, "prettier": "@adonisjs/prettier-config", "dependencies": { diff --git a/src/two_factor_auth_manager.ts b/src/two_factor_auth_manager.ts index b8718fb..885596d 100644 --- a/src/two_factor_auth_manager.ts +++ b/src/two_factor_auth_manager.ts @@ -1,20 +1,20 @@ import * as twoFactor from 'node-2fa' -import stringHelpers from '@adonisjs/core/helpers/string' -import { ResolvedTwoFactorAuthConfig } from './types.js' +import { ResolvedTwoFactorAuthConfig, TwoFactorSecret } from './types.js' +import { randomInt } from 'node:crypto' export class TwoFactorAuthManager { constructor(private config: ResolvedTwoFactorAuthConfig) {} - generateSecret(account: string) { + generateSecret(account: string): TwoFactorSecret { return twoFactor.generateSecret({ name: this.config.issuer, account, }) } - generateRecoveryCodes() { - return Array.from({ length: 16 }, () => stringHelpers.generateRandom(10).toUpperCase()) + generateRecoveryCodes(codeLength = 16) { + return Array.from({ length: codeLength }, () => this.generateRecoveryCode(10)) } verifyToken(secret: string = '', token: string, recoveryCodes: string[] = []) { @@ -31,4 +31,24 @@ export class TwoFactorAuthManager { generateToken(secret: string) { return twoFactor.generateToken(secret) } + + private generateRandomChar() { + const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + const randomIndex = randomInt(0, charset.length) + return charset[randomIndex] + } + + private generateRecoveryCode(length: number) { + let recoveryCode = '' + + for (let i = 0; i < length; i++) { + recoveryCode += this.generateRandomChar() + } + + // Inserir um espaço no meio + const middleIndex = Math.floor(length / 2) + recoveryCode = `${recoveryCode.substring(0, middleIndex)} ${recoveryCode.substring(middleIndex)}` + + return recoveryCode + } } diff --git a/stubs/make/controller/two_factor_controller.stub b/stubs/make/controller/two_factor_controller.stub index 0d0b9ed..9f62377 100644 --- a/stubs/make/controller/two_factor_controller.stub +++ b/stubs/make/controller/two_factor_controller.stub @@ -8,7 +8,7 @@ import type { HttpContext } from '@adonisjs/core/http' import { verifyOtpValidator } from '#validators/verify_otp' -export default class TwoFactorsController { +export default class TwoFactorAuthController { async generate({ auth }: HttpContext) { const user = auth.user! diff --git a/tsconfig.json b/tsconfig.json index 0cfd318..dd0bbdb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,8 @@ "compilerOptions": { "rootDir": "./", "outDir": "./build", - } + }, + "exclude": [ + "docs" + ] }