@ackplus/nest-auth 0.1.51 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -513
- package/eslint.config.mjs +59 -0
- package/jest.config.ts +10 -0
- package/package.json +14 -44
- package/project.json +86 -0
- package/src/index.ts +30 -0
- package/src/lib/admin-console/admin-console.module.ts +62 -0
- package/src/lib/admin-console/controllers/admin-auth.controller.ts +339 -0
- package/src/lib/admin-console/controllers/admin-console.controller.ts +82 -0
- package/src/lib/admin-console/controllers/admin-permissions.controller.ts +180 -0
- package/src/lib/admin-console/controllers/admin-roles.controller.ts +89 -0
- package/src/lib/admin-console/controllers/admin-tenants.controller.ts +68 -0
- package/src/lib/admin-console/controllers/admin-users.controller.ts +379 -0
- package/src/lib/admin-console/decorators/current-admin.decorator.ts +9 -0
- package/src/lib/admin-console/dto/admin-permission.dto.ts +106 -0
- package/src/lib/admin-console/dto/admin-role.dto.ts +45 -0
- package/src/lib/admin-console/dto/admin-tenant.dto.ts +43 -0
- package/src/lib/admin-console/dto/admin-user.dto.ts +87 -0
- package/src/lib/admin-console/dto/create-dashboard-admin.dto.ts +34 -0
- package/src/lib/admin-console/dto/login.dto.ts +10 -0
- package/src/lib/admin-console/dto/reset-password.dto.ts +21 -0
- package/src/lib/admin-console/dto/setup-admin.dto.ts +23 -0
- package/src/lib/admin-console/dto/signup.dto.ts +51 -0
- package/src/lib/admin-console/entities/admin-user.entity.ts +74 -0
- package/src/lib/admin-console/guards/admin-session.guard.ts +47 -0
- package/src/lib/admin-console/services/admin-auth.service.ts +82 -0
- package/src/lib/admin-console/services/admin-console-config.service.ts +62 -0
- package/src/lib/admin-console/services/admin-session.service.ts +106 -0
- package/src/lib/admin-console/services/admin-user.service.ts +96 -0
- package/src/lib/admin-console/static/index.html +771 -0
- package/src/lib/auth/auth.module.ts +58 -0
- package/src/lib/auth/controllers/auth.controller.ts +393 -0
- package/src/lib/auth/controllers/mfa.controller.ts +200 -0
- package/src/lib/auth/dto/credentials/email-credentials.dto.ts +24 -0
- package/src/lib/auth/dto/credentials/phone-credentials.dto.ts +24 -0
- package/src/lib/auth/dto/credentials/social-credentials.dto.ts +15 -0
- package/src/lib/auth/dto/index.ts +1 -0
- package/src/lib/auth/dto/requests/change-password.request.dto.ts +34 -0
- package/src/lib/auth/dto/requests/forgot-password.request.dto.ts +30 -0
- package/src/lib/auth/dto/requests/initialize-admin.request.dto.ts +51 -0
- package/src/lib/auth/dto/requests/login.request.dto.ts +65 -0
- package/src/lib/auth/dto/requests/refresh-token.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/reset-password-with-token.request.dto.ts +22 -0
- package/src/lib/auth/dto/requests/reset-password.request.dto.ts +50 -0
- package/src/lib/auth/dto/requests/send-email-verification.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.ts +19 -0
- package/src/lib/auth/dto/requests/signup.request.dto.ts +42 -0
- package/src/lib/auth/dto/requests/toggle-mfa.request.dto.ts +12 -0
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.ts +24 -0
- package/src/lib/auth/dto/requests/verify-email.request.dto.ts +22 -0
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.ts +41 -0
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.ts +22 -0
- package/src/lib/auth/dto/responses/auth-cookie.response.dto.ts +58 -0
- package/src/lib/auth/dto/responses/auth-success.response.dto.ts +58 -0
- package/src/lib/auth/dto/responses/auth.response.dto.ts +99 -0
- package/src/lib/auth/dto/responses/client-config.response.dto.ts +153 -0
- package/src/lib/auth/dto/responses/initialize-admin.response.dto.ts +22 -0
- package/src/lib/auth/dto/responses/mfa-code-response.dto.ts +27 -0
- package/src/lib/auth/dto/responses/mfa-status.response.dto.ts +89 -0
- package/src/lib/auth/dto/responses/verify-otp.response.dto.ts +9 -0
- package/src/lib/auth/entities/mfa-secret.entity.ts +33 -0
- package/src/lib/auth/entities/otp.entity.ts +33 -0
- package/src/lib/auth/events/{logged-out-all.event.d.ts → logged-out-all.event.ts} +6 -3
- package/src/lib/auth/events/{logged-out.event.d.ts → logged-out.event.ts} +5 -3
- package/src/lib/auth/events/{password-reset-requested.event.d.ts → password-reset-requested.event.ts} +6 -3
- package/src/lib/auth/events/{password-reset.event.d.ts → password-reset.event.ts} +6 -3
- package/src/lib/auth/events/{user-2fa-verified.event.d.ts → user-2fa-verified.event.ts} +6 -3
- package/src/lib/auth/events/{user-logged-in.event.d.ts → user-logged-in.event.ts} +7 -3
- package/src/lib/auth/events/{user-refresh-token.event.d.ts → user-refresh-token.event.ts} +6 -3
- package/src/lib/auth/events/{user-registered.event.d.ts → user-registered.event.ts} +7 -3
- package/src/lib/auth/guards/auth.guard.ts +386 -0
- package/src/lib/auth/{index.d.ts → index.ts} +28 -1
- package/src/lib/auth/interceptors/refresh-token.interceptor.ts +117 -0
- package/src/lib/auth/services/auth.service.ts +947 -0
- package/src/lib/auth/services/client-config.service.ts +157 -0
- package/src/lib/auth/services/cookie.service.ts +43 -0
- package/src/lib/auth/services/mfa.service.ts +391 -0
- package/src/lib/auth.constants.ts +63 -0
- package/src/lib/core/core.module.ts +50 -0
- package/src/lib/core/decorators/auth.decorator.ts +38 -0
- package/src/lib/core/decorators/permissions.decorator.ts +17 -0
- package/src/lib/core/decorators/public.decorator.ts +33 -0
- package/src/lib/core/decorators/role.decorator.ts +12 -0
- package/src/lib/core/decorators/skip-mfa.decorator.ts +4 -0
- package/src/lib/core/dto/message.response.dto.ts +6 -0
- package/src/lib/core/{entities.d.ts → entities.ts} +18 -1
- package/src/lib/core/{index.d.ts → index.ts} +17 -0
- package/src/lib/core/interfaces/auth-module-options.interface.ts +211 -0
- package/src/lib/core/interfaces/mfa-options.interface.ts +46 -0
- package/src/lib/core/interfaces/otp.interface.ts +6 -0
- package/src/lib/core/interfaces/session-options.interface.ts +19 -0
- package/src/lib/core/interfaces/{token-payload.interface.d.ts → token-payload.interface.ts} +4 -1
- package/src/lib/core/providers/apple-auth.provider.ts +61 -0
- package/src/lib/core/providers/base-auth.provider.ts +74 -0
- package/src/lib/core/providers/email-auth.provider.ts +71 -0
- package/src/lib/core/providers/facebook-auth.provider.ts +55 -0
- package/src/lib/core/providers/github-auth.provider.ts +79 -0
- package/src/lib/core/providers/google-auth.provider.ts +61 -0
- package/src/lib/core/providers/jwt-auth.provider.ts +50 -0
- package/src/lib/core/providers/phone-auth.provider.ts +45 -0
- package/src/lib/core/services/auth-config.service.ts +184 -0
- package/src/lib/core/services/auth-provider-registry.service.ts +93 -0
- package/src/lib/core/services/{debug-logger.service.js → debug-logger.service.ts} +92 -59
- package/src/lib/core/services/initialization.service.ts +29 -0
- package/src/lib/core/services/jwt.service.ts +137 -0
- package/src/lib/nest-auth.module.ts +152 -0
- package/src/lib/permission/entities/permission.entity.ts +56 -0
- package/src/lib/permission/index.ts +4 -0
- package/src/lib/permission/permission.module.ts +14 -0
- package/src/lib/permission/services/permission.service.ts +233 -0
- package/src/lib/request-context/index.ts +2 -0
- package/src/lib/request-context/request-context.middleware.ts +13 -0
- package/src/lib/request-context/{request-context.js → request-context.ts} +51 -27
- package/src/lib/role/entities/role.entity.ts +103 -0
- package/src/lib/role/{index.d.ts → index.ts} +2 -0
- package/src/lib/role/role.module.ts +15 -0
- package/src/lib/role/services/{role.service.js → role.service.ts} +117 -52
- package/src/lib/session/entities/session.entity.ts +54 -0
- package/src/lib/session/index.ts +20 -0
- package/src/lib/session/interfaces/session-repository.interface.ts +58 -0
- package/src/lib/session/repositories/base-session.repository.ts +74 -0
- package/src/lib/session/repositories/memory-session.repository.ts +153 -0
- package/src/lib/session/repositories/redis-session.repository.ts +171 -0
- package/src/lib/session/repositories/typeorm-session.repository.ts +86 -0
- package/src/lib/session/services/session-manager.service.ts +261 -0
- package/src/lib/session/session.module.ts +102 -0
- package/src/lib/session/utils/session.util.ts +166 -0
- package/src/lib/tenant/entities/tenant.entity.ts +40 -0
- package/src/lib/tenant/events/tenant-created.event.ts +9 -0
- package/src/lib/tenant/events/tenant-deleted.event.ts +11 -0
- package/src/lib/tenant/events/{tenant-updated.event.d.ts → tenant-updated.event.ts} +6 -3
- package/src/lib/tenant/index.ts +9 -0
- package/src/lib/tenant/services/tenant.service.ts +336 -0
- package/src/lib/tenant/tenant.module.ts +19 -0
- package/src/lib/types/express.d.ts +14 -0
- package/src/lib/user/dto/requests/update-user.dto.ts +15 -0
- package/src/lib/user/entities/access-key.entity.ts +53 -0
- package/src/lib/user/entities/identity.entity.ts +31 -0
- package/src/lib/user/entities/user.entity.ts +212 -0
- package/src/lib/user/events/{user-created.event.d.ts → user-created.event.ts} +4 -3
- package/src/lib/user/events/{user-deleted.event.d.ts → user-deleted.event.ts} +6 -3
- package/src/lib/user/events/{user-updated.event.d.ts → user-updated.event.ts} +6 -3
- package/src/lib/user/index.ts +11 -0
- package/src/lib/user/services/access-key.service.ts +145 -0
- package/src/lib/user/services/{user.service.js → user.service.ts} +199 -95
- package/src/lib/user/user.module.ts +26 -0
- package/src/lib/utils/database.utils.ts +6 -0
- package/src/lib/utils/date.util.ts +106 -0
- package/src/lib/utils/device.util.ts +111 -0
- package/src/lib/utils/index.ts +6 -0
- package/src/lib/utils/otp.ts +3 -0
- package/src/lib/utils/security.util.ts +27 -0
- package/src/lib/utils/slug.util.ts +58 -0
- package/src/types/ms.d.ts +1 -0
- package/test/access-key.service.spec.ts +204 -0
- package/test/auth.service.spec.ts +541 -0
- package/test/mfa.service.spec.ts +359 -0
- package/test/role.service.spec.ts +418 -0
- package/test/tenant.service.spec.ts +218 -0
- package/test/test.setup.ts +66 -0
- package/test/user.service.spec.ts +374 -0
- package/tsconfig.json +17 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.spec.json +15 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/ui/.env +1 -0
- package/ui/.env.example +1 -0
- package/ui/.eslintignore +7 -0
- package/ui/README.md +288 -0
- package/ui/index.html +17 -0
- package/ui/package.json +34 -0
- package/ui/postcss.config.js +6 -0
- package/ui/src/App.tsx +245 -0
- package/ui/src/components/AuthGuard.tsx +59 -0
- package/ui/src/components/AuthProvider.tsx +76 -0
- package/ui/src/components/Button.tsx +37 -0
- package/ui/src/components/Card.tsx +37 -0
- package/ui/src/components/ErrorMessage.tsx +15 -0
- package/ui/src/components/FormDialog.tsx +61 -0
- package/ui/src/components/FormFooter.tsx +37 -0
- package/ui/src/components/Layout.tsx +112 -0
- package/ui/src/components/LoadingMessage.tsx +11 -0
- package/ui/src/components/Modal.tsx +97 -0
- package/ui/src/components/MultiSelect.tsx +145 -0
- package/ui/src/components/PageHeader.tsx +42 -0
- package/ui/src/components/PanelHeader.tsx +28 -0
- package/ui/src/components/PermissionInput.tsx +473 -0
- package/ui/src/components/SearchInput.tsx +69 -0
- package/ui/src/components/Select.tsx +51 -0
- package/ui/src/components/SwaggerUIWrapper.tsx +316 -0
- package/ui/src/components/Table.tsx +207 -0
- package/ui/src/components/Tag.tsx +9 -0
- package/ui/src/components/TagsInput.tsx +96 -0
- package/ui/src/components/admin/AdminForm.tsx +170 -0
- package/ui/src/components/admin/CreateAdminDialog.tsx +38 -0
- package/ui/src/components/auth/LoginFooter.tsx +17 -0
- package/ui/src/components/auth/LoginHeader.tsx +14 -0
- package/ui/src/components/auth/components/CodeBlock.tsx +43 -0
- package/ui/src/components/auth/components/CreateAccountCodeExamples.tsx +60 -0
- package/ui/src/components/auth/components/PasswordRequirements.tsx +16 -0
- package/ui/src/components/auth/components/PasswordStrengthIndicator.tsx +48 -0
- package/ui/src/components/auth/components/ResetPasswordCodeExamples.tsx +76 -0
- package/ui/src/components/auth/components/Tabs.tsx +32 -0
- package/ui/src/components/auth/dialogs/CreateAccountDialog.tsx +79 -0
- package/ui/src/components/auth/dialogs/ForgotPasswordDialog.tsx +79 -0
- package/ui/src/components/auth/forms/CreateAccountForm.tsx +226 -0
- package/ui/src/components/auth/forms/LoginForm.tsx +149 -0
- package/ui/src/components/auth/forms/ResetPasswordForm.tsx +202 -0
- package/ui/src/components/auth/types.ts +17 -0
- package/ui/src/components/auth/utils/security.ts +82 -0
- package/ui/src/components/auth/utils/utils.ts +25 -0
- package/ui/src/components/form/EmailField.tsx +25 -0
- package/ui/src/components/form/FormField.tsx +102 -0
- package/ui/src/components/form/FormMultiSelect.tsx +46 -0
- package/ui/src/components/form/FormSelect.tsx +60 -0
- package/ui/src/components/form/FormTagsInput.tsx +42 -0
- package/ui/src/components/form/FormTextarea.tsx +42 -0
- package/ui/src/components/form/PasswordField.tsx +93 -0
- package/ui/src/components/form/SecretKeyField.tsx +49 -0
- package/ui/src/components/permission/CreatePermissionDialog.tsx +44 -0
- package/ui/src/components/permission/EditPermissionDialog.tsx +55 -0
- package/ui/src/components/permission/PermissionForm.tsx +251 -0
- package/ui/src/components/role/CreateRoleDialog.tsx +45 -0
- package/ui/src/components/role/EditRoleDialog.tsx +55 -0
- package/ui/src/components/role/RoleDialog.tsx +252 -0
- package/ui/src/components/role/RoleForm.tsx +246 -0
- package/ui/src/components/tenant/CreateTenantDialog.tsx +41 -0
- package/ui/src/components/tenant/EditTenantDialog.tsx +52 -0
- package/ui/src/components/tenant/TenantForm.tsx +160 -0
- package/ui/src/components/user/CreateUserDialog.tsx +45 -0
- package/ui/src/components/user/UserDetailModal.tsx +815 -0
- package/ui/src/components/user/UserForm.tsx +191 -0
- package/ui/src/data/nest-auth.json +1687 -0
- package/ui/src/hooks/useApi.ts +69 -0
- package/ui/src/hooks/useAuth.ts +100 -0
- package/ui/src/hooks/useConfirm.tsx +105 -0
- package/ui/src/hooks/useFormFooter.tsx +42 -0
- package/ui/src/hooks/usePagination.ts +69 -0
- package/ui/src/index.css +59 -0
- package/ui/src/main.tsx +13 -0
- package/ui/src/pages/AdminsPage.tsx +178 -0
- package/ui/src/pages/ApiPage.tsx +89 -0
- package/ui/src/pages/DashboardPage.tsx +281 -0
- package/ui/src/pages/LoginPage.tsx +39 -0
- package/ui/src/pages/PermissionsPage.tsx +376 -0
- package/ui/src/pages/RolesPage.tsx +274 -0
- package/ui/src/pages/TenantsPage.tsx +221 -0
- package/ui/src/pages/UsersPage.tsx +387 -0
- package/ui/src/services/api.ts +115 -0
- package/ui/src/types/index.ts +136 -0
- package/ui/src/vite-env.d.ts +9 -0
- package/ui/tailwind.config.js +45 -0
- package/ui/tsconfig.json +24 -0
- package/ui/tsconfig.node.json +10 -0
- package/ui/vite.config.ts +37 -0
- package/ui/yarn.lock +3137 -0
- package/src/index.d.ts +0 -11
- package/src/index.js +0 -18
- package/src/index.js.map +0 -1
- package/src/lib/auth/auth.module.d.ts +0 -2
- package/src/lib/auth/auth.module.js +0 -54
- package/src/lib/auth/auth.module.js.map +0 -1
- package/src/lib/auth/controllers/auth.controller.d.ts +0 -29
- package/src/lib/auth/controllers/auth.controller.js +0 -206
- package/src/lib/auth/controllers/auth.controller.js.map +0 -1
- package/src/lib/auth/controllers/mfa.controller.d.ts +0 -23
- package/src/lib/auth/controllers/mfa.controller.js +0 -131
- package/src/lib/auth/controllers/mfa.controller.js.map +0 -1
- package/src/lib/auth/dto/index.d.ts +0 -0
- package/src/lib/auth/dto/index.js +0 -1
- package/src/lib/auth/dto/index.js.map +0 -1
- package/src/lib/auth/dto/requests/forgot-password.request.dto.d.ts +0 -5
- package/src/lib/auth/dto/requests/forgot-password.request.dto.js +0 -30
- package/src/lib/auth/dto/requests/forgot-password.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/login.request.dto.d.ts +0 -6
- package/src/lib/auth/dto/requests/login.request.dto.js +0 -38
- package/src/lib/auth/dto/requests/login.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/refresh-token.request.dto.d.ts +0 -3
- package/src/lib/auth/dto/requests/refresh-token.request.dto.js +0 -15
- package/src/lib/auth/dto/requests/refresh-token.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/reset-password.request.dto.d.ts +0 -7
- package/src/lib/auth/dto/requests/reset-password.request.dto.js +0 -42
- package/src/lib/auth/dto/requests/reset-password.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.d.ts +0 -4
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.js +0 -16
- package/src/lib/auth/dto/requests/send-mfa-code.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/signup.request.dto.d.ts +0 -7
- package/src/lib/auth/dto/requests/signup.request.dto.js +0 -37
- package/src/lib/auth/dto/requests/signup.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/social-login.request.dto.d.ts +0 -3
- package/src/lib/auth/dto/requests/social-login.request.dto.js +0 -16
- package/src/lib/auth/dto/requests/social-login.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.d.ts +0 -5
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.js +0 -21
- package/src/lib/auth/dto/requests/verify-2fa.request.dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.d.ts +0 -6
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.js +0 -35
- package/src/lib/auth/dto/requests/verify-forgot-password-otp-request-dto.js.map +0 -1
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.d.ts +0 -4
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.js +0 -20
- package/src/lib/auth/dto/requests/verify-totp-setup.request.dto.js.map +0 -1
- package/src/lib/auth/dto/responses/auth.response.dto.d.ts +0 -16
- package/src/lib/auth/dto/responses/auth.response.dto.js +0 -50
- package/src/lib/auth/dto/responses/auth.response.dto.js.map +0 -1
- package/src/lib/auth/entities/mfa-secret.entity.d.ts +0 -12
- package/src/lib/auth/entities/mfa-secret.entity.js +0 -50
- package/src/lib/auth/entities/mfa-secret.entity.js.map +0 -1
- package/src/lib/auth/entities/otp.entity.d.ts +0 -13
- package/src/lib/auth/entities/otp.entity.js +0 -50
- package/src/lib/auth/entities/otp.entity.js.map +0 -1
- package/src/lib/auth/events/logged-out-all.event.js +0 -10
- package/src/lib/auth/events/logged-out-all.event.js.map +0 -1
- package/src/lib/auth/events/logged-out.event.js +0 -10
- package/src/lib/auth/events/logged-out.event.js.map +0 -1
- package/src/lib/auth/events/password-reset-requested.event.js +0 -10
- package/src/lib/auth/events/password-reset-requested.event.js.map +0 -1
- package/src/lib/auth/events/password-reset.event.js +0 -10
- package/src/lib/auth/events/password-reset.event.js.map +0 -1
- package/src/lib/auth/events/user-2fa-verified.event.js +0 -10
- package/src/lib/auth/events/user-2fa-verified.event.js.map +0 -1
- package/src/lib/auth/events/user-logged-in.event.js +0 -10
- package/src/lib/auth/events/user-logged-in.event.js.map +0 -1
- package/src/lib/auth/events/user-refresh-token.event.js +0 -10
- package/src/lib/auth/events/user-refresh-token.event.js.map +0 -1
- package/src/lib/auth/events/user-registered.event.js +0 -10
- package/src/lib/auth/events/user-registered.event.js.map +0 -1
- package/src/lib/auth/guards/auth.guard.d.ts +0 -28
- package/src/lib/auth/guards/auth.guard.js +0 -304
- package/src/lib/auth/guards/auth.guard.js.map +0 -1
- package/src/lib/auth/index.js +0 -31
- package/src/lib/auth/index.js.map +0 -1
- package/src/lib/auth/services/auth.service.d.ts +0 -53
- package/src/lib/auth/services/auth.service.js +0 -522
- package/src/lib/auth/services/auth.service.js.map +0 -1
- package/src/lib/auth/services/cookie.service.d.ts +0 -9
- package/src/lib/auth/services/cookie.service.js +0 -43
- package/src/lib/auth/services/cookie.service.js.map +0 -1
- package/src/lib/auth/services/mfa.service.d.ts +0 -38
- package/src/lib/auth/services/mfa.service.js +0 -254
- package/src/lib/auth/services/mfa.service.js.map +0 -1
- package/src/lib/auth.constants.d.ts +0 -39
- package/src/lib/auth.constants.js +0 -43
- package/src/lib/auth.constants.js.map +0 -1
- package/src/lib/core/core.module.d.ts +0 -2
- package/src/lib/core/core.module.js +0 -53
- package/src/lib/core/core.module.js.map +0 -1
- package/src/lib/core/decorators/auth.decorator.d.ts +0 -1
- package/src/lib/core/decorators/auth.decorator.js +0 -8
- package/src/lib/core/decorators/auth.decorator.js.map +0 -1
- package/src/lib/core/decorators/permissions.decorator.d.ts +0 -2
- package/src/lib/core/decorators/permissions.decorator.js +0 -14
- package/src/lib/core/decorators/permissions.decorator.js.map +0 -1
- package/src/lib/core/decorators/role.decorator.d.ts +0 -3
- package/src/lib/core/decorators/role.decorator.js +0 -14
- package/src/lib/core/decorators/role.decorator.js.map +0 -1
- package/src/lib/core/decorators/skip-mfa.decorator.d.ts +0 -2
- package/src/lib/core/decorators/skip-mfa.decorator.js +0 -8
- package/src/lib/core/decorators/skip-mfa.decorator.js.map +0 -1
- package/src/lib/core/dto/message.response.dto.d.ts +0 -3
- package/src/lib/core/dto/message.response.dto.js +0 -13
- package/src/lib/core/dto/message.response.dto.js.map +0 -1
- package/src/lib/core/entities.js +0 -31
- package/src/lib/core/entities.js.map +0 -1
- package/src/lib/core/index.js +0 -27
- package/src/lib/core/index.js.map +0 -1
- package/src/lib/core/interfaces/auth-module-options.interface.d.ts +0 -62
- package/src/lib/core/interfaces/auth-module-options.interface.js +0 -3
- package/src/lib/core/interfaces/auth-module-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/mfa-options.interface.d.ts +0 -25
- package/src/lib/core/interfaces/mfa-options.interface.js +0 -10
- package/src/lib/core/interfaces/mfa-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/otp.interface.d.ts +0 -5
- package/src/lib/core/interfaces/otp.interface.js +0 -10
- package/src/lib/core/interfaces/otp.interface.js.map +0 -1
- package/src/lib/core/interfaces/session-options.interface.d.ts +0 -12
- package/src/lib/core/interfaces/session-options.interface.js +0 -9
- package/src/lib/core/interfaces/session-options.interface.js.map +0 -1
- package/src/lib/core/interfaces/token-payload.interface.js +0 -3
- package/src/lib/core/interfaces/token-payload.interface.js.map +0 -1
- package/src/lib/core/providers/apple-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/apple-auth.provider.js +0 -57
- package/src/lib/core/providers/apple-auth.provider.js.map +0 -1
- package/src/lib/core/providers/base-auth.provider.d.ts +0 -26
- package/src/lib/core/providers/base-auth.provider.js +0 -43
- package/src/lib/core/providers/base-auth.provider.js.map +0 -1
- package/src/lib/core/providers/email-auth.provider.d.ts +0 -17
- package/src/lib/core/providers/email-auth.provider.js +0 -40
- package/src/lib/core/providers/email-auth.provider.js.map +0 -1
- package/src/lib/core/providers/facebook-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/facebook-auth.provider.js +0 -56
- package/src/lib/core/providers/facebook-auth.provider.js.map +0 -1
- package/src/lib/core/providers/google-auth.provider.d.ts +0 -21
- package/src/lib/core/providers/google-auth.provider.js +0 -58
- package/src/lib/core/providers/google-auth.provider.js.map +0 -1
- package/src/lib/core/providers/jwt-auth.provider.d.ts +0 -33
- package/src/lib/core/providers/jwt-auth.provider.js +0 -50
- package/src/lib/core/providers/jwt-auth.provider.js.map +0 -1
- package/src/lib/core/providers/phone-auth.provider.d.ts +0 -18
- package/src/lib/core/providers/phone-auth.provider.js +0 -43
- package/src/lib/core/providers/phone-auth.provider.js.map +0 -1
- package/src/lib/core/services/auth-config.service.d.ts +0 -12
- package/src/lib/core/services/auth-config.service.js +0 -79
- package/src/lib/core/services/auth-config.service.js.map +0 -1
- package/src/lib/core/services/auth-provider-registry.service.d.ts +0 -24
- package/src/lib/core/services/auth-provider-registry.service.js +0 -71
- package/src/lib/core/services/auth-provider-registry.service.js.map +0 -1
- package/src/lib/core/services/debug-logger.service.d.ts +0 -38
- package/src/lib/core/services/debug-logger.service.js.map +0 -1
- package/src/lib/core/services/initialization.service.d.ts +0 -10
- package/src/lib/core/services/initialization.service.js +0 -34
- package/src/lib/core/services/initialization.service.js.map +0 -1
- package/src/lib/core/services/jwt.service.d.ts +0 -14
- package/src/lib/core/services/jwt.service.js +0 -92
- package/src/lib/core/services/jwt.service.js.map +0 -1
- package/src/lib/nest-auth.module.d.ts +0 -11
- package/src/lib/nest-auth.module.js +0 -177
- package/src/lib/nest-auth.module.js.map +0 -1
- package/src/lib/request-context/request-context.d.ts +0 -22
- package/src/lib/request-context/request-context.js.map +0 -1
- package/src/lib/request-context/request-context.middleware.d.ts +0 -4
- package/src/lib/request-context/request-context.middleware.js +0 -16
- package/src/lib/request-context/request-context.middleware.js.map +0 -1
- package/src/lib/role/entities/role.entity.d.ts +0 -20
- package/src/lib/role/entities/role.entity.js +0 -110
- package/src/lib/role/entities/role.entity.js.map +0 -1
- package/src/lib/role/index.js +0 -5
- package/src/lib/role/index.js.map +0 -1
- package/src/lib/role/role.module.d.ts +0 -2
- package/src/lib/role/role.module.js +0 -23
- package/src/lib/role/role.module.js.map +0 -1
- package/src/lib/role/services/role.service.d.ts +0 -20
- package/src/lib/role/services/role.service.js.map +0 -1
- package/src/lib/session/entities/session.entity.d.ts +0 -16
- package/src/lib/session/entities/session.entity.js +0 -63
- package/src/lib/session/entities/session.entity.js.map +0 -1
- package/src/lib/session/index.d.ts +0 -3
- package/src/lib/session/index.js +0 -7
- package/src/lib/session/index.js.map +0 -1
- package/src/lib/session/services/base-session.service.d.ts +0 -23
- package/src/lib/session/services/base-session.service.js +0 -64
- package/src/lib/session/services/base-session.service.js.map +0 -1
- package/src/lib/session/services/database-session.service.d.ts +0 -17
- package/src/lib/session/services/database-session.service.js +0 -51
- package/src/lib/session/services/database-session.service.js.map +0 -1
- package/src/lib/session/services/redis-session.service.d.ts +0 -20
- package/src/lib/session/services/redis-session.service.js +0 -117
- package/src/lib/session/services/redis-session.service.js.map +0 -1
- package/src/lib/session/session.module.d.ts +0 -2
- package/src/lib/session/session.module.js +0 -33
- package/src/lib/session/session.module.js.map +0 -1
- package/src/lib/tenant/entities/tenant.entity.d.ts +0 -10
- package/src/lib/tenant/entities/tenant.entity.js +0 -44
- package/src/lib/tenant/entities/tenant.entity.js.map +0 -1
- package/src/lib/tenant/events/tenant-created.event.d.ts +0 -8
- package/src/lib/tenant/events/tenant-created.event.js +0 -10
- package/src/lib/tenant/events/tenant-created.event.js.map +0 -1
- package/src/lib/tenant/events/tenant-deleted.event.d.ts +0 -8
- package/src/lib/tenant/events/tenant-deleted.event.js +0 -10
- package/src/lib/tenant/events/tenant-deleted.event.js.map +0 -1
- package/src/lib/tenant/events/tenant-updated.event.js +0 -10
- package/src/lib/tenant/events/tenant-updated.event.js.map +0 -1
- package/src/lib/tenant/index.d.ts +0 -1
- package/src/lib/tenant/index.js +0 -5
- package/src/lib/tenant/index.js.map +0 -1
- package/src/lib/tenant/services/tenant.service.d.ts +0 -26
- package/src/lib/tenant/services/tenant.service.js +0 -200
- package/src/lib/tenant/services/tenant.service.js.map +0 -1
- package/src/lib/tenant/tenant.module.d.ts +0 -2
- package/src/lib/tenant/tenant.module.js +0 -27
- package/src/lib/tenant/tenant.module.js.map +0 -1
- package/src/lib/user/dto/requests/update-user.dto.d.ts +0 -5
- package/src/lib/user/dto/requests/update-user.dto.js +0 -24
- package/src/lib/user/dto/requests/update-user.dto.js.map +0 -1
- package/src/lib/user/entities/access-key.entity.d.ts +0 -16
- package/src/lib/user/entities/access-key.entity.js +0 -63
- package/src/lib/user/entities/access-key.entity.js.map +0 -1
- package/src/lib/user/entities/identity.entity.d.ts +0 -12
- package/src/lib/user/entities/identity.entity.js +0 -47
- package/src/lib/user/entities/identity.entity.js.map +0 -1
- package/src/lib/user/entities/user.entity.d.ts +0 -39
- package/src/lib/user/entities/user.entity.js +0 -201
- package/src/lib/user/entities/user.entity.js.map +0 -1
- package/src/lib/user/events/user-created.event.js +0 -10
- package/src/lib/user/events/user-created.event.js.map +0 -1
- package/src/lib/user/events/user-deleted.event.js +0 -10
- package/src/lib/user/events/user-deleted.event.js.map +0 -1
- package/src/lib/user/events/user-updated.event.js +0 -10
- package/src/lib/user/events/user-updated.event.js.map +0 -1
- package/src/lib/user/index.d.ts +0 -3
- package/src/lib/user/index.js +0 -7
- package/src/lib/user/index.js.map +0 -1
- package/src/lib/user/services/access-key.service.d.ts +0 -19
- package/src/lib/user/services/access-key.service.js +0 -119
- package/src/lib/user/services/access-key.service.js.map +0 -1
- package/src/lib/user/services/user.service.d.ts +0 -24
- package/src/lib/user/services/user.service.js.map +0 -1
- package/src/lib/user/user.module.d.ts +0 -2
- package/src/lib/user/user.module.js +0 -34
- package/src/lib/user/user.module.js.map +0 -1
- package/src/lib/utils/database.utils.d.ts +0 -2
- package/src/lib/utils/database.utils.js +0 -8
- package/src/lib/utils/database.utils.js.map +0 -1
- package/src/lib/utils/otp.d.ts +0 -1
- package/src/lib/utils/otp.js +0 -7
- package/src/lib/utils/otp.js.map +0 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { User, AlertCircle, Check } from 'lucide-react';
|
|
3
|
+
import { useForm, Controller } from 'react-hook-form';
|
|
4
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
5
|
+
import * as yup from 'yup';
|
|
6
|
+
import { PasswordRequirements } from '../components/PasswordRequirements';
|
|
7
|
+
import { PasswordField } from '../../form/PasswordField';
|
|
8
|
+
import { EmailField } from '../../form/EmailField';
|
|
9
|
+
import { SecretKeyField } from '../../form/SecretKeyField';
|
|
10
|
+
import { FormField } from '../../form/FormField';
|
|
11
|
+
|
|
12
|
+
interface CreateAccountFormData {
|
|
13
|
+
email: string;
|
|
14
|
+
password: string;
|
|
15
|
+
name: string;
|
|
16
|
+
secretKey: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const createAccountSchema = yup.object({
|
|
20
|
+
email: yup.string().email('Invalid email address').required('Email is required').max(254),
|
|
21
|
+
password: yup
|
|
22
|
+
.string()
|
|
23
|
+
.required('Password is required')
|
|
24
|
+
.min(8, 'Password must be at least 8 characters')
|
|
25
|
+
.max(128, 'Password must be less than 128 characters')
|
|
26
|
+
.matches(/[A-Z]/, 'Password must contain at least one uppercase letter')
|
|
27
|
+
.matches(/[a-z]/, 'Password must contain at least one lowercase letter')
|
|
28
|
+
.matches(/\d/, 'Password must contain at least one number')
|
|
29
|
+
.matches(/[@$!%*?&]/, 'Password must contain at least one special character (@$!%*?&)'),
|
|
30
|
+
name: yup.string().max(100, 'Name must be less than 100 characters').optional(),
|
|
31
|
+
secretKey: yup
|
|
32
|
+
.string()
|
|
33
|
+
.required('Secret key is required')
|
|
34
|
+
.min(8, 'Secret key must be at least 8 characters')
|
|
35
|
+
.max(128, 'Secret key must be less than 128 characters'),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
interface CreateAccountFormProps {
|
|
39
|
+
onSuccess: () => void;
|
|
40
|
+
onError: (error: string) => void;
|
|
41
|
+
error?: string;
|
|
42
|
+
success?: boolean;
|
|
43
|
+
adminApiBaseUrl: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const CreateAccountFormComponent: React.FC<CreateAccountFormProps> = ({
|
|
47
|
+
onSuccess,
|
|
48
|
+
onError,
|
|
49
|
+
error,
|
|
50
|
+
success,
|
|
51
|
+
adminApiBaseUrl,
|
|
52
|
+
}) => {
|
|
53
|
+
const {
|
|
54
|
+
control,
|
|
55
|
+
handleSubmit,
|
|
56
|
+
formState: { errors, isSubmitting },
|
|
57
|
+
reset,
|
|
58
|
+
} = useForm<CreateAccountFormData>({
|
|
59
|
+
resolver: yupResolver(createAccountSchema) as any,
|
|
60
|
+
defaultValues: {
|
|
61
|
+
email: '',
|
|
62
|
+
password: '',
|
|
63
|
+
name: '',
|
|
64
|
+
secretKey: '',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const onSubmit = async (data: CreateAccountFormData) => {
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`${adminApiBaseUrl}/signup`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
credentials: 'include',
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
email: data.email.trim().toLowerCase(),
|
|
76
|
+
password: data.password,
|
|
77
|
+
name: data.name.trim() || undefined,
|
|
78
|
+
secretKey: data.secretKey,
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
let responseData: any = {};
|
|
83
|
+
const contentType = response.headers.get('content-type');
|
|
84
|
+
if (contentType && contentType.includes('application/json')) {
|
|
85
|
+
try {
|
|
86
|
+
responseData = await response.json();
|
|
87
|
+
} catch {
|
|
88
|
+
// Ignore JSON parse errors
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
const errorMessage =
|
|
94
|
+
responseData.message ||
|
|
95
|
+
responseData.error ||
|
|
96
|
+
`Request failed with status ${response.status}`;
|
|
97
|
+
throw new Error(errorMessage);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
reset();
|
|
101
|
+
onSuccess();
|
|
102
|
+
} catch (err: unknown) {
|
|
103
|
+
const errorMessage = err instanceof Error ? err.message : 'An error occurred. Please try again.';
|
|
104
|
+
onError(errorMessage);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className="space-y-4">
|
|
110
|
+
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg flex items-start gap-3">
|
|
111
|
+
<AlertCircle className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
|
|
112
|
+
<div className="text-sm text-amber-800">
|
|
113
|
+
<p className="font-semibold mb-1">Secure Access</p>
|
|
114
|
+
<p>
|
|
115
|
+
Admin accounts can only be created using your <strong>Nest Auth Secret Key</strong> configured
|
|
116
|
+
in <code>adminConsole.secretKey</code>. This key is required for admin console security operations.
|
|
117
|
+
</p>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
{success && (
|
|
122
|
+
<div className="p-3 bg-green-50 border border-green-200 rounded-lg flex items-start gap-2">
|
|
123
|
+
<Check className="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5" />
|
|
124
|
+
<p className="text-sm text-green-600">Admin account created successfully! You can now sign in.</p>
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
|
|
128
|
+
{error && (
|
|
129
|
+
<div className="p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2">
|
|
130
|
+
<AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0 mt-0.5" />
|
|
131
|
+
<p className="text-sm text-red-600">{error}</p>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
136
|
+
<Controller
|
|
137
|
+
name="secretKey"
|
|
138
|
+
control={control}
|
|
139
|
+
render={({ field }) => (
|
|
140
|
+
<SecretKeyField
|
|
141
|
+
id="create-secret-key"
|
|
142
|
+
label="Nest Auth Secret Key *"
|
|
143
|
+
value={field.value}
|
|
144
|
+
onChange={field.onChange}
|
|
145
|
+
disabled={isSubmitting}
|
|
146
|
+
error={errors.secretKey?.message}
|
|
147
|
+
helpText={
|
|
148
|
+
!errors.secretKey ? (
|
|
149
|
+
<>
|
|
150
|
+
Your Nest Auth secret key configured in <code>adminConsole.secretKey</code>{' '}
|
|
151
|
+
(used for admin console security)
|
|
152
|
+
</>
|
|
153
|
+
) : undefined
|
|
154
|
+
}
|
|
155
|
+
/>
|
|
156
|
+
)}
|
|
157
|
+
/>
|
|
158
|
+
|
|
159
|
+
<Controller
|
|
160
|
+
name="email"
|
|
161
|
+
control={control}
|
|
162
|
+
render={({ field }) => (
|
|
163
|
+
<EmailField
|
|
164
|
+
id="create-email"
|
|
165
|
+
label="Email Address *"
|
|
166
|
+
value={field.value}
|
|
167
|
+
onChange={field.onChange}
|
|
168
|
+
disabled={isSubmitting}
|
|
169
|
+
error={errors.email?.message}
|
|
170
|
+
autoComplete="username"
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
/>
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
<Controller
|
|
177
|
+
name="name"
|
|
178
|
+
control={control}
|
|
179
|
+
render={({ field }) => (
|
|
180
|
+
<FormField
|
|
181
|
+
startIcon={<User className="h-5 w-5 text-gray-400" />}
|
|
182
|
+
label="Name (Optional)"
|
|
183
|
+
id="create-name"
|
|
184
|
+
value={field.value}
|
|
185
|
+
onChange={field.onChange}
|
|
186
|
+
disabled={isSubmitting}
|
|
187
|
+
placeholder="Admin User"
|
|
188
|
+
error={errors.name?.message}
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
191
|
+
/>
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
<Controller
|
|
195
|
+
name="password"
|
|
196
|
+
control={control}
|
|
197
|
+
render={({ field }) => (
|
|
198
|
+
<PasswordField
|
|
199
|
+
id="create-password"
|
|
200
|
+
label="Password *"
|
|
201
|
+
value={field.value}
|
|
202
|
+
onChange={field.onChange}
|
|
203
|
+
disabled={isSubmitting}
|
|
204
|
+
error={errors.password?.message}
|
|
205
|
+
showGenerateButton={true}
|
|
206
|
+
showStrengthIndicator={true}
|
|
207
|
+
/>
|
|
208
|
+
)}
|
|
209
|
+
/>
|
|
210
|
+
|
|
211
|
+
<PasswordRequirements />
|
|
212
|
+
|
|
213
|
+
<button type="submit" disabled={isSubmitting} className="w-full btn-primary py-3 text-base">
|
|
214
|
+
{isSubmitting ? (
|
|
215
|
+
<span className="flex items-center justify-center gap-2">
|
|
216
|
+
<div className="animate-spin h-5 w-5 border-2 border-white border-t-transparent rounded-full" />
|
|
217
|
+
Creating account...
|
|
218
|
+
</span>
|
|
219
|
+
) : (
|
|
220
|
+
'Create Admin Account'
|
|
221
|
+
)}
|
|
222
|
+
</button>
|
|
223
|
+
</form>
|
|
224
|
+
</div>
|
|
225
|
+
);
|
|
226
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { AlertCircle } from 'lucide-react';
|
|
3
|
+
import { useForm, Controller } from 'react-hook-form';
|
|
4
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
5
|
+
import * as yup from 'yup';
|
|
6
|
+
import { PasswordField } from '../../form/PasswordField';
|
|
7
|
+
import { EmailField } from '../../form/EmailField';
|
|
8
|
+
import type { LoginForm } from '../types';
|
|
9
|
+
|
|
10
|
+
const loginSchema = yup.object({
|
|
11
|
+
email: yup.string().email('Invalid email address').required('Email is required'),
|
|
12
|
+
password: yup.string().required('Password is required'),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
interface LoginFormProps {
|
|
16
|
+
onSubmit: (credentials: LoginForm) => Promise<void>;
|
|
17
|
+
error?: string | null;
|
|
18
|
+
onOpenCreateAccount: () => void;
|
|
19
|
+
onOpenForgotPassword: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const LoginFormComponent: React.FC<LoginFormProps> = ({
|
|
23
|
+
onSubmit: onSubmitProp,
|
|
24
|
+
error: externalError,
|
|
25
|
+
onOpenCreateAccount,
|
|
26
|
+
onOpenForgotPassword,
|
|
27
|
+
}) => {
|
|
28
|
+
const [internalError, setInternalError] = useState('');
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
control,
|
|
32
|
+
handleSubmit,
|
|
33
|
+
formState: { isSubmitting },
|
|
34
|
+
reset,
|
|
35
|
+
} = useForm<LoginForm>({
|
|
36
|
+
resolver: yupResolver(loginSchema) as any,
|
|
37
|
+
defaultValues: {
|
|
38
|
+
email: '',
|
|
39
|
+
password: '',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const onSubmit = async (data: LoginForm) => {
|
|
44
|
+
try {
|
|
45
|
+
setInternalError('');
|
|
46
|
+
await onSubmitProp({
|
|
47
|
+
email: data.email.trim().toLowerCase(),
|
|
48
|
+
password: data.password,
|
|
49
|
+
});
|
|
50
|
+
reset();
|
|
51
|
+
} catch (err: unknown) {
|
|
52
|
+
const errorMessage = err instanceof Error ? err.message : 'An error occurred. Please try again.';
|
|
53
|
+
setInternalError(errorMessage);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const error = externalError || internalError;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="bg-white rounded-xl shadow-2xl p-8 animate-slide-up">
|
|
61
|
+
<div className="mb-6">
|
|
62
|
+
<h2 className="text-2xl font-bold text-gray-900">Welcome back</h2>
|
|
63
|
+
<p className="text-gray-600 mt-1">Sign in to your admin account</p>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{error && (
|
|
67
|
+
<div className="p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2 mb-4">
|
|
68
|
+
<AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0 mt-0.5" />
|
|
69
|
+
<p className="text-sm text-red-600">{error}</p>
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
|
|
74
|
+
<Controller
|
|
75
|
+
name="email"
|
|
76
|
+
control={control}
|
|
77
|
+
render={({ field }) => (
|
|
78
|
+
<EmailField
|
|
79
|
+
id="email"
|
|
80
|
+
label="Email Address"
|
|
81
|
+
value={field.value}
|
|
82
|
+
onChange={field.onChange}
|
|
83
|
+
disabled={isSubmitting}
|
|
84
|
+
placeholder="admin@example.com"
|
|
85
|
+
autoComplete="username"
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
|
|
90
|
+
<div>
|
|
91
|
+
<Controller
|
|
92
|
+
name="password"
|
|
93
|
+
control={control}
|
|
94
|
+
render={({ field }) => (
|
|
95
|
+
<PasswordField
|
|
96
|
+
id="password"
|
|
97
|
+
label="Password"
|
|
98
|
+
value={field.value}
|
|
99
|
+
onChange={field.onChange}
|
|
100
|
+
disabled={isSubmitting}
|
|
101
|
+
placeholder="••••••••"
|
|
102
|
+
autoComplete="current-password"
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
/>
|
|
106
|
+
<div className="mt-2 text-right">
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
onClick={onOpenForgotPassword}
|
|
110
|
+
className="text-sm text-primary-600 hover:text-primary-700 font-medium"
|
|
111
|
+
>
|
|
112
|
+
Forgot password?
|
|
113
|
+
</button>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<button type="submit" disabled={isSubmitting} className="w-full btn-primary py-3 text-base">
|
|
118
|
+
{isSubmitting ? (
|
|
119
|
+
<span className="flex items-center justify-center gap-2">
|
|
120
|
+
<div className="animate-spin h-5 w-5 border-2 border-white border-t-transparent rounded-full" />
|
|
121
|
+
Signing in...
|
|
122
|
+
</span>
|
|
123
|
+
) : (
|
|
124
|
+
'Sign In'
|
|
125
|
+
)}
|
|
126
|
+
</button>
|
|
127
|
+
</form>
|
|
128
|
+
|
|
129
|
+
<div className="mt-6">
|
|
130
|
+
<div className="relative">
|
|
131
|
+
<div className="absolute inset-0 flex items-center">
|
|
132
|
+
<div className="w-full border-t border-gray-300" />
|
|
133
|
+
</div>
|
|
134
|
+
<div className="relative flex justify-center text-sm">
|
|
135
|
+
<span className="px-2 bg-white text-gray-500">New to this app?</span>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
onClick={onOpenCreateAccount}
|
|
142
|
+
className="mt-4 w-full btn-secondary py-3 text-base"
|
|
143
|
+
>
|
|
144
|
+
Create Admin Account
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AlertCircle, Check } from 'lucide-react';
|
|
3
|
+
import { useForm, Controller } from 'react-hook-form';
|
|
4
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
5
|
+
import * as yup from 'yup';
|
|
6
|
+
import { PasswordRequirements } from '../components/PasswordRequirements';
|
|
7
|
+
import { PasswordField } from '../../form/PasswordField';
|
|
8
|
+
import { EmailField } from '../../form/EmailField';
|
|
9
|
+
import { SecretKeyField } from '../../form/SecretKeyField';
|
|
10
|
+
|
|
11
|
+
interface ResetPasswordFormData {
|
|
12
|
+
email: string;
|
|
13
|
+
secretKey: string;
|
|
14
|
+
newPassword: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const resetPasswordSchema = yup.object({
|
|
18
|
+
email: yup.string().email('Invalid email address').required('Email is required').max(254),
|
|
19
|
+
secretKey: yup
|
|
20
|
+
.string()
|
|
21
|
+
.required('Secret key is required')
|
|
22
|
+
.min(8, 'Secret key must be at least 8 characters')
|
|
23
|
+
.max(128, 'Secret key must be less than 128 characters'),
|
|
24
|
+
newPassword: yup
|
|
25
|
+
.string()
|
|
26
|
+
.required('Password is required')
|
|
27
|
+
.min(8, 'Password must be at least 8 characters')
|
|
28
|
+
.max(128, 'Password must be less than 128 characters')
|
|
29
|
+
.matches(/[A-Z]/, 'Password must contain at least one uppercase letter')
|
|
30
|
+
.matches(/[a-z]/, 'Password must contain at least one lowercase letter')
|
|
31
|
+
.matches(/\d/, 'Password must contain at least one number')
|
|
32
|
+
.matches(/[@$!%*?&]/, 'Password must contain at least one special character (@$!%*?&)'),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
interface ResetPasswordFormProps {
|
|
36
|
+
onSuccess: () => void;
|
|
37
|
+
onError: (error: string) => void;
|
|
38
|
+
error?: string;
|
|
39
|
+
success?: boolean;
|
|
40
|
+
adminApiBaseUrl: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const ResetPasswordFormComponent: React.FC<ResetPasswordFormProps> = ({
|
|
44
|
+
onSuccess,
|
|
45
|
+
onError,
|
|
46
|
+
error,
|
|
47
|
+
success,
|
|
48
|
+
adminApiBaseUrl,
|
|
49
|
+
}) => {
|
|
50
|
+
const {
|
|
51
|
+
control,
|
|
52
|
+
handleSubmit,
|
|
53
|
+
formState: { errors, isSubmitting },
|
|
54
|
+
reset,
|
|
55
|
+
} = useForm<ResetPasswordFormData>({
|
|
56
|
+
resolver: yupResolver(resetPasswordSchema) as any,
|
|
57
|
+
defaultValues: {
|
|
58
|
+
email: '',
|
|
59
|
+
secretKey: '',
|
|
60
|
+
newPassword: '',
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const onSubmit = async (data: ResetPasswordFormData) => {
|
|
65
|
+
try {
|
|
66
|
+
const response = await fetch(`${adminApiBaseUrl}/reset-password`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'Content-Type': 'application/json' },
|
|
69
|
+
credentials: 'include',
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
email: data.email.trim().toLowerCase(),
|
|
72
|
+
secretKey: data.secretKey,
|
|
73
|
+
newPassword: data.newPassword,
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
let responseData: any = {};
|
|
78
|
+
const contentType = response.headers.get('content-type');
|
|
79
|
+
if (contentType && contentType.includes('application/json')) {
|
|
80
|
+
try {
|
|
81
|
+
responseData = await response.json();
|
|
82
|
+
} catch {
|
|
83
|
+
// Ignore JSON parse errors
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const errorMessage =
|
|
89
|
+
responseData.message ||
|
|
90
|
+
responseData.error ||
|
|
91
|
+
`Request failed with status ${response.status}`;
|
|
92
|
+
throw new Error(errorMessage);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
reset();
|
|
96
|
+
onSuccess();
|
|
97
|
+
} catch (err: unknown) {
|
|
98
|
+
const errorMessage = err instanceof Error ? err.message : 'An error occurred. Please try again.';
|
|
99
|
+
onError(errorMessage);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="space-y-4">
|
|
105
|
+
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg flex items-start gap-3">
|
|
106
|
+
<AlertCircle className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
|
|
107
|
+
<div className="text-sm text-amber-800">
|
|
108
|
+
<p className="font-semibold mb-1">Security Required</p>
|
|
109
|
+
<p>
|
|
110
|
+
Password reset requires your <strong>Nest Auth Secret Key</strong> configured in{' '}
|
|
111
|
+
<code>adminConsole.secretKey</code>.
|
|
112
|
+
</p>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
{success && (
|
|
117
|
+
<div className="p-3 bg-green-50 border border-green-200 rounded-lg flex items-start gap-2">
|
|
118
|
+
<Check className="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5" />
|
|
119
|
+
<p className="text-sm text-green-600">Password reset successfully! You can now sign in with your new password.</p>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{error && (
|
|
124
|
+
<div className="p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2">
|
|
125
|
+
<AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0 mt-0.5" />
|
|
126
|
+
<p className="text-sm text-red-600">{error}</p>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
131
|
+
<Controller
|
|
132
|
+
name="email"
|
|
133
|
+
control={control}
|
|
134
|
+
render={({ field }) => (
|
|
135
|
+
<EmailField
|
|
136
|
+
id="reset-email"
|
|
137
|
+
label="Email Address *"
|
|
138
|
+
value={field.value}
|
|
139
|
+
onChange={field.onChange}
|
|
140
|
+
disabled={isSubmitting}
|
|
141
|
+
error={errors.email?.message}
|
|
142
|
+
autoComplete="username"
|
|
143
|
+
/>
|
|
144
|
+
)}
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
<Controller
|
|
148
|
+
name="secretKey"
|
|
149
|
+
control={control}
|
|
150
|
+
render={({ field }) => (
|
|
151
|
+
<SecretKeyField
|
|
152
|
+
id="reset-secret-key"
|
|
153
|
+
label="Nest Auth Secret Key *"
|
|
154
|
+
value={field.value}
|
|
155
|
+
onChange={field.onChange}
|
|
156
|
+
disabled={isSubmitting}
|
|
157
|
+
error={errors.secretKey?.message}
|
|
158
|
+
helpText={
|
|
159
|
+
!errors.secretKey ? (
|
|
160
|
+
<>
|
|
161
|
+
Your Nest Auth secret key configured in <code>adminConsole.secretKey</code>{' '}
|
|
162
|
+
(used for admin console security)
|
|
163
|
+
</>
|
|
164
|
+
) : undefined
|
|
165
|
+
}
|
|
166
|
+
/>
|
|
167
|
+
)}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
<Controller
|
|
171
|
+
name="newPassword"
|
|
172
|
+
control={control}
|
|
173
|
+
render={({ field }) => (
|
|
174
|
+
<PasswordField
|
|
175
|
+
id="reset-new-password"
|
|
176
|
+
label="New Password *"
|
|
177
|
+
value={field.value}
|
|
178
|
+
onChange={field.onChange}
|
|
179
|
+
disabled={isSubmitting}
|
|
180
|
+
error={errors.newPassword?.message}
|
|
181
|
+
showGenerateButton={true}
|
|
182
|
+
showStrengthIndicator={true}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
/>
|
|
186
|
+
|
|
187
|
+
<PasswordRequirements />
|
|
188
|
+
|
|
189
|
+
<button type="submit" disabled={isSubmitting} className="w-full btn-primary py-3 text-base">
|
|
190
|
+
{isSubmitting ? (
|
|
191
|
+
<span className="flex items-center justify-center gap-2">
|
|
192
|
+
<div className="animate-spin h-5 w-5 border-2 border-white border-t-transparent rounded-full" />
|
|
193
|
+
Resetting password...
|
|
194
|
+
</span>
|
|
195
|
+
) : (
|
|
196
|
+
'Reset Password'
|
|
197
|
+
)}
|
|
198
|
+
</button>
|
|
199
|
+
</form>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface LoginForm {
|
|
2
|
+
email: string;
|
|
3
|
+
password: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface CreateAccountForm {
|
|
7
|
+
email: string;
|
|
8
|
+
password: string;
|
|
9
|
+
name: string;
|
|
10
|
+
secretKey: string; // Backend field name - UI displays as "Nest Auth Secret Key"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResetPasswordForm {
|
|
14
|
+
email: string;
|
|
15
|
+
secretKey: string; // Backend field name - UI displays as "Nest Auth Secret Key"
|
|
16
|
+
newPassword: string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security utilities for authentication forms
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calculates password strength for display
|
|
7
|
+
*/
|
|
8
|
+
export const calculatePasswordStrength = (password: string): 'weak' | 'medium' | 'strong' | null => {
|
|
9
|
+
if (!password || password.length === 0) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Check for required character types
|
|
14
|
+
const hasUpperCase = /[A-Z]/.test(password);
|
|
15
|
+
const hasLowerCase = /[a-z]/.test(password);
|
|
16
|
+
const hasNumber = /\d/.test(password);
|
|
17
|
+
const hasSpecialChar = /[@$!%*?&]/.test(password);
|
|
18
|
+
|
|
19
|
+
const charVariety = [hasUpperCase, hasLowerCase, hasNumber, hasSpecialChar].filter(Boolean).length;
|
|
20
|
+
|
|
21
|
+
if (password.length >= 12 && charVariety === 4) {
|
|
22
|
+
return 'strong';
|
|
23
|
+
} else if (password.length >= 10 || charVariety >= 3) {
|
|
24
|
+
return 'medium';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return 'weak';
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generates a secure random password that meets validation requirements
|
|
32
|
+
* @param length - Desired password length (default: 16, min: 8, max: 128)
|
|
33
|
+
* @returns A secure random password with uppercase, lowercase, numbers, and special characters
|
|
34
|
+
*/
|
|
35
|
+
export const generateRandomPassword = (length: number = 16): string => {
|
|
36
|
+
// Ensure length is within valid range
|
|
37
|
+
const validLength = Math.max(8, Math.min(length, 128));
|
|
38
|
+
|
|
39
|
+
// Character sets
|
|
40
|
+
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
41
|
+
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
|
42
|
+
const numbers = '0123456789';
|
|
43
|
+
const special = '@$!%*?&';
|
|
44
|
+
const allChars = uppercase + lowercase + numbers + special;
|
|
45
|
+
|
|
46
|
+
// Use crypto.getRandomValues if available (more secure), fallback to Math.random
|
|
47
|
+
// Use rejection sampling to avoid modulo bias
|
|
48
|
+
const getRandomValue = (max: number): number => {
|
|
49
|
+
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
|
50
|
+
let value: number;
|
|
51
|
+
const maxValid = Math.floor(0xFFFFFFFF / max) * max;
|
|
52
|
+
do {
|
|
53
|
+
const array = new Uint32Array(1);
|
|
54
|
+
crypto.getRandomValues(array);
|
|
55
|
+
value = array[0];
|
|
56
|
+
} while (value >= maxValid);
|
|
57
|
+
return value % max;
|
|
58
|
+
}
|
|
59
|
+
return Math.floor(Math.random() * max);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Ensure at least one character from each required set
|
|
63
|
+
let password = '';
|
|
64
|
+
password += uppercase[getRandomValue(uppercase.length)];
|
|
65
|
+
password += lowercase[getRandomValue(lowercase.length)];
|
|
66
|
+
password += numbers[getRandomValue(numbers.length)];
|
|
67
|
+
password += special[getRandomValue(special.length)];
|
|
68
|
+
|
|
69
|
+
// Fill the rest with random characters
|
|
70
|
+
for (let i = password.length; i < validLength; i++) {
|
|
71
|
+
password += allChars[getRandomValue(allChars.length)];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Shuffle the password to avoid predictable pattern
|
|
75
|
+
const passwordArray = password.split('');
|
|
76
|
+
for (let i = passwordArray.length - 1; i > 0; i--) {
|
|
77
|
+
const j = getRandomValue(i + 1);
|
|
78
|
+
[passwordArray[i], passwordArray[j]] = [passwordArray[j], passwordArray[i]];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return passwordArray.join('');
|
|
82
|
+
};
|