@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,171 @@
|
|
|
1
|
+
import { Injectable, Inject, Optional } from '@nestjs/common';
|
|
2
|
+
import { BaseSessionRepository } from './base-session.repository';
|
|
3
|
+
import { NestAuthSession } from '../entities/session.entity';
|
|
4
|
+
import { SessionPayload } from '../../core/interfaces/token-payload.interface';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
|
|
7
|
+
// Lazy load Redis to make it optional
|
|
8
|
+
let Redis: any;
|
|
9
|
+
let InjectRedis: any;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
Redis = require('ioredis').default || require('ioredis');
|
|
13
|
+
const ioredisModule = require('@nestjs-modules/ioredis');
|
|
14
|
+
InjectRedis = ioredisModule.InjectRedis;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
// Redis is not installed, that's okay if not using Redis sessions
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Redis implementation of session repository
|
|
21
|
+
* Stores sessions in Redis for fast access
|
|
22
|
+
*
|
|
23
|
+
* REQUIREMENTS:
|
|
24
|
+
* - npm install ioredis @nestjs-modules/ioredis
|
|
25
|
+
* - Configure Redis in NestAuthModule
|
|
26
|
+
*/
|
|
27
|
+
@Injectable()
|
|
28
|
+
export class RedisSessionRepository extends BaseSessionRepository {
|
|
29
|
+
private readonly prefix = 'nest-auth:session:';
|
|
30
|
+
private readonly userSessionsPrefix = 'nest-auth:user-sessions:';
|
|
31
|
+
private redis: any;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
@Optional()
|
|
35
|
+
@Inject('REDIS_CLIENT')
|
|
36
|
+
redisClient?: any
|
|
37
|
+
) {
|
|
38
|
+
super();
|
|
39
|
+
|
|
40
|
+
if (!redisClient) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
'RedisSessionRepository requires ioredis and @nestjs-modules/ioredis packages. ' +
|
|
43
|
+
'Install them with: npm install ioredis @nestjs-modules/ioredis'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.redis = redisClient;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private getSessionKey(sessionId: string): string {
|
|
51
|
+
return `${this.prefix}${sessionId}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private getUserSessionsKey(userId: string): string {
|
|
55
|
+
return `${this.userSessionsPrefix}${userId}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async create(session: SessionPayload): Promise<NestAuthSession> {
|
|
59
|
+
const sessionId = session.id || uuidv4();
|
|
60
|
+
const sessionKey = this.getSessionKey(sessionId);
|
|
61
|
+
const userSessionsKey = this.getUserSessionsKey(session.userId);
|
|
62
|
+
|
|
63
|
+
const sessionData: NestAuthSession = {
|
|
64
|
+
id: sessionId,
|
|
65
|
+
userId: session.userId,
|
|
66
|
+
refreshToken: session.refreshToken,
|
|
67
|
+
data: session.data,
|
|
68
|
+
expiresAt: session.expiresAt,
|
|
69
|
+
userAgent: session.userAgent,
|
|
70
|
+
deviceName: session.deviceName,
|
|
71
|
+
ipAddress: session.ipAddress,
|
|
72
|
+
lastActive: session.lastActive || new Date(),
|
|
73
|
+
} as NestAuthSession;
|
|
74
|
+
|
|
75
|
+
// Store session as hash
|
|
76
|
+
const serialized = this.serializeSession(sessionData);
|
|
77
|
+
await this.redis.hmset(sessionKey, serialized);
|
|
78
|
+
|
|
79
|
+
// Add to user's sessions set
|
|
80
|
+
await this.redis.sadd(userSessionsKey, sessionId);
|
|
81
|
+
|
|
82
|
+
// Set TTL
|
|
83
|
+
const ttl = Math.floor((session.expiresAt.getTime() - Date.now()) / 1000);
|
|
84
|
+
if (ttl > 0) {
|
|
85
|
+
await this.redis.expire(sessionKey, ttl);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return sessionData;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async findById(sessionId: string): Promise<NestAuthSession | null> {
|
|
92
|
+
const sessionKey = this.getSessionKey(sessionId);
|
|
93
|
+
const data = await this.redis.hgetall(sessionKey);
|
|
94
|
+
|
|
95
|
+
if (!data || Object.keys(data).length === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return this.deserializeSession(data);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async findByUserId(userId: string): Promise<NestAuthSession[]> {
|
|
103
|
+
const userSessionsKey = this.getUserSessionsKey(userId);
|
|
104
|
+
const sessionIds = await this.redis.smembers(userSessionsKey);
|
|
105
|
+
|
|
106
|
+
const sessions: NestAuthSession[] = [];
|
|
107
|
+
for (const sessionId of sessionIds) {
|
|
108
|
+
const session = await this.findById(sessionId);
|
|
109
|
+
if (session) {
|
|
110
|
+
sessions.push(session);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return sessions;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async findActiveByUserId(userId: string): Promise<NestAuthSession[]> {
|
|
118
|
+
const allSessions = await this.findByUserId(userId);
|
|
119
|
+
return this.filterActive(allSessions);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async update(sessionId: string, updates: Partial<NestAuthSession>): Promise<NestAuthSession> {
|
|
123
|
+
const sessionKey = this.getSessionKey(sessionId);
|
|
124
|
+
const serialized = this.serializeSession(updates as any);
|
|
125
|
+
|
|
126
|
+
await this.redis.hmset(sessionKey, serialized);
|
|
127
|
+
|
|
128
|
+
return await this.findById(sessionId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async delete(sessionId: string): Promise<void> {
|
|
132
|
+
const session = await this.findById(sessionId);
|
|
133
|
+
if (!session) return;
|
|
134
|
+
|
|
135
|
+
const sessionKey = this.getSessionKey(sessionId);
|
|
136
|
+
const userSessionsKey = this.getUserSessionsKey(session.userId);
|
|
137
|
+
|
|
138
|
+
await this.redis.del(sessionKey);
|
|
139
|
+
await this.redis.srem(userSessionsKey, sessionId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async deleteByUserId(userId: string): Promise<void> {
|
|
143
|
+
const userSessionsKey = this.getUserSessionsKey(userId);
|
|
144
|
+
const sessionIds = await this.redis.smembers(userSessionsKey);
|
|
145
|
+
|
|
146
|
+
const pipeline = this.redis.pipeline();
|
|
147
|
+
for (const sessionId of sessionIds) {
|
|
148
|
+
pipeline.del(this.getSessionKey(sessionId));
|
|
149
|
+
}
|
|
150
|
+
pipeline.del(userSessionsKey);
|
|
151
|
+
|
|
152
|
+
await pipeline.exec();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async deleteExpired(): Promise<number> {
|
|
156
|
+
// Redis automatically handles expiration via TTL
|
|
157
|
+
// This is a no-op for Redis, but we implement it for interface compliance
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async countActiveByUserId(userId: string): Promise<number> {
|
|
162
|
+
const activeSessions = await this.findActiveByUserId(userId);
|
|
163
|
+
return activeSessions.length;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async updateLastActive(sessionId: string): Promise<void> {
|
|
167
|
+
await this.update(sessionId, {
|
|
168
|
+
lastActive: new Date(),
|
|
169
|
+
} as any);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
|
+
import { Repository, MoreThan, LessThan } from 'typeorm';
|
|
4
|
+
import { BaseSessionRepository } from './base-session.repository';
|
|
5
|
+
import { NestAuthSession } from '../entities/session.entity';
|
|
6
|
+
import { SessionPayload } from '../../core/interfaces/token-payload.interface';
|
|
7
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* TypeORM implementation of session repository
|
|
11
|
+
* Stores sessions in PostgreSQL/MySQL database
|
|
12
|
+
*/
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class TypeORMSessionRepository extends BaseSessionRepository {
|
|
15
|
+
constructor(
|
|
16
|
+
@InjectRepository(NestAuthSession)
|
|
17
|
+
private readonly repository: Repository<NestAuthSession>,
|
|
18
|
+
) {
|
|
19
|
+
super();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async create(session: SessionPayload): Promise<NestAuthSession> {
|
|
23
|
+
const sessionEntity = this.repository.create(session);
|
|
24
|
+
|
|
25
|
+
return await this.repository.save(sessionEntity);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async findById(sessionId: string): Promise<NestAuthSession | null> {
|
|
29
|
+
return await this.repository.findOne({
|
|
30
|
+
where: { id: sessionId },
|
|
31
|
+
relations: ['user'],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async findByUserId(userId: string): Promise<NestAuthSession[]> {
|
|
36
|
+
return await this.repository.find({
|
|
37
|
+
where: { userId },
|
|
38
|
+
order: { createdAt: 'DESC' },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async findActiveByUserId(userId: string): Promise<NestAuthSession[]> {
|
|
43
|
+
return await this.repository.find({
|
|
44
|
+
where: {
|
|
45
|
+
userId,
|
|
46
|
+
expiresAt: MoreThan(new Date()),
|
|
47
|
+
},
|
|
48
|
+
order: { lastActive: 'DESC' },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async update(sessionId: string, updates: Partial<NestAuthSession>): Promise<NestAuthSession> {
|
|
53
|
+
await this.repository.update(sessionId, updates);
|
|
54
|
+
return await this.findById(sessionId);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async delete(sessionId: string): Promise<void> {
|
|
58
|
+
await this.repository.delete(sessionId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async deleteByUserId(userId: string): Promise<void> {
|
|
62
|
+
await this.repository.delete({ userId });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async deleteExpired(): Promise<number> {
|
|
66
|
+
const result = await this.repository.delete({
|
|
67
|
+
expiresAt: LessThan(new Date()),
|
|
68
|
+
});
|
|
69
|
+
return result.affected || 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async countActiveByUserId(userId: string): Promise<number> {
|
|
73
|
+
return await this.repository.count({
|
|
74
|
+
where: {
|
|
75
|
+
userId,
|
|
76
|
+
expiresAt: MoreThan(new Date()),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async updateLastActive(sessionId: string): Promise<void> {
|
|
82
|
+
await this.repository.update(sessionId, {
|
|
83
|
+
lastActive: new Date(),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { Injectable, UnauthorizedException, Inject } from '@nestjs/common';
|
|
2
|
+
import { ISessionRepository } from '../interfaces/session-repository.interface';
|
|
3
|
+
import { NestAuthSession } from '../entities/session.entity';
|
|
4
|
+
import { SessionPayload } from '../../core/interfaces/token-payload.interface';
|
|
5
|
+
import { AuthModuleOptions } from '../../core/interfaces/auth-module-options.interface';
|
|
6
|
+
import { AuthConfigService } from '../../core/services/auth-config.service';
|
|
7
|
+
import { RequestContext } from '../../request-context/request-context';
|
|
8
|
+
import { NestAuthUser } from '../../user/entities/user.entity';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import ms from 'ms';
|
|
11
|
+
|
|
12
|
+
export const SESSION_REPOSITORY = 'SESSION_REPOSITORY';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* High-level session manager
|
|
16
|
+
* Handles session lifecycle using repository pattern
|
|
17
|
+
*/
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class SessionManagerService {
|
|
20
|
+
private options: AuthModuleOptions;
|
|
21
|
+
private readonly maxSessionsPerUser: number;
|
|
22
|
+
private readonly slidingExpiration: boolean;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
@Inject(SESSION_REPOSITORY)
|
|
26
|
+
private readonly repository: ISessionRepository,
|
|
27
|
+
) {
|
|
28
|
+
this.options = AuthConfigService.getOptions();
|
|
29
|
+
this.maxSessionsPerUser = this.options.session?.maxSessionsPerUser || 10;
|
|
30
|
+
this.slidingExpiration = this.options.session?.slidingExpiration ?? true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a new session
|
|
35
|
+
*/
|
|
36
|
+
async createSession(payload: {
|
|
37
|
+
userId: string;
|
|
38
|
+
refreshToken?: string;
|
|
39
|
+
data?: any;
|
|
40
|
+
userAgent?: string;
|
|
41
|
+
deviceName?: string;
|
|
42
|
+
ipAddress?: string;
|
|
43
|
+
}): Promise<NestAuthSession> {
|
|
44
|
+
const { userId, refreshToken, data, userAgent, deviceName, ipAddress } = payload;
|
|
45
|
+
|
|
46
|
+
// Check max sessions limit
|
|
47
|
+
await this.enforceMaxSessions(userId);
|
|
48
|
+
|
|
49
|
+
const sessionPayload: SessionPayload = {
|
|
50
|
+
id: uuidv4(),
|
|
51
|
+
userId,
|
|
52
|
+
refreshToken: refreshToken || '',
|
|
53
|
+
data: data || {},
|
|
54
|
+
expiresAt: this.calculateExpiration(),
|
|
55
|
+
userAgent: userAgent || RequestContext.currentRequest()?.headers['user-agent'] || 'Unknown',
|
|
56
|
+
deviceName: deviceName || RequestContext.getDeviceInfo().deviceName,
|
|
57
|
+
ipAddress: ipAddress || RequestContext.getDeviceInfo().ipAddress,
|
|
58
|
+
lastActive: new Date(),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return await this.repository.create(sessionPayload);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get session by ID and optionally refresh it
|
|
66
|
+
*/
|
|
67
|
+
async getSession(sessionId: string, refreshSession = true): Promise<NestAuthSession> {
|
|
68
|
+
const session = await this.repository.findById(sessionId);
|
|
69
|
+
|
|
70
|
+
if (!session) {
|
|
71
|
+
throw new UnauthorizedException('Session not found');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if expired
|
|
75
|
+
if (this.isExpired(session)) {
|
|
76
|
+
await this.repository.delete(sessionId);
|
|
77
|
+
throw new UnauthorizedException('Session expired');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Update last active if sliding expiration enabled
|
|
81
|
+
if (refreshSession && this.slidingExpiration) {
|
|
82
|
+
await this.repository.updateLastActive(sessionId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return session;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get all sessions for a user
|
|
90
|
+
*/
|
|
91
|
+
async getUserSessions(userId: string): Promise<NestAuthSession[]> {
|
|
92
|
+
return await this.repository.findByUserId(userId);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get active sessions for a user
|
|
97
|
+
*/
|
|
98
|
+
async getActiveSessions(userId: string): Promise<NestAuthSession[]> {
|
|
99
|
+
return await this.repository.findActiveByUserId(userId);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Update session data
|
|
104
|
+
*/
|
|
105
|
+
async updateSession(sessionId: string, updates: Partial<NestAuthSession>): Promise<NestAuthSession> {
|
|
106
|
+
return await this.repository.update(sessionId, updates);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Revoke (delete) a session
|
|
111
|
+
*/
|
|
112
|
+
async revokeSession(sessionId: string): Promise<void> {
|
|
113
|
+
await this.repository.delete(sessionId);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Revoke all sessions for a user
|
|
118
|
+
*/
|
|
119
|
+
async revokeAllUserSessions(userId: string): Promise<void> {
|
|
120
|
+
await this.repository.deleteByUserId(userId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Revoke all sessions except the current one
|
|
125
|
+
*/
|
|
126
|
+
async revokeOtherSessions(userId: string, currentSessionId: string): Promise<void> {
|
|
127
|
+
const sessions = await this.repository.findByUserId(userId);
|
|
128
|
+
|
|
129
|
+
for (const session of sessions) {
|
|
130
|
+
if (session.id !== currentSessionId) {
|
|
131
|
+
await this.repository.delete(session.id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Clean up expired sessions
|
|
138
|
+
*/
|
|
139
|
+
async cleanupExpiredSessions(): Promise<number> {
|
|
140
|
+
return await this.repository.deleteExpired();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Extend session expiration
|
|
145
|
+
*/
|
|
146
|
+
async extendSession(sessionId: string, duration?: string): Promise<NestAuthSession> {
|
|
147
|
+
const expiresAt = this.calculateExpiration(duration);
|
|
148
|
+
return await this.repository.update(sessionId, { expiresAt } as any);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validate session and return it if valid
|
|
153
|
+
*/
|
|
154
|
+
async validateSession(sessionId: string): Promise<NestAuthSession | null> {
|
|
155
|
+
try {
|
|
156
|
+
return await this.getSession(sessionId, true);
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if user has reached max sessions limit
|
|
164
|
+
*/
|
|
165
|
+
async hasReachedMaxSessions(userId: string): Promise<boolean> {
|
|
166
|
+
const count = await this.repository.countActiveByUserId(userId);
|
|
167
|
+
return count >= this.maxSessionsPerUser;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Enforce max sessions per user by removing oldest sessions
|
|
172
|
+
*/
|
|
173
|
+
private async enforceMaxSessions(userId: string): Promise<void> {
|
|
174
|
+
const activeSessions = await this.repository.findActiveByUserId(userId);
|
|
175
|
+
|
|
176
|
+
if (activeSessions.length >= this.maxSessionsPerUser) {
|
|
177
|
+
// Sort by lastActive (oldest first)
|
|
178
|
+
const sorted = activeSessions.sort((a, b) => {
|
|
179
|
+
const aTime = a.lastActive?.getTime() || 0;
|
|
180
|
+
const bTime = b.lastActive?.getTime() || 0;
|
|
181
|
+
return aTime - bTime;
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Remove oldest session(s)
|
|
185
|
+
const toRemove = sorted.slice(0, activeSessions.length - this.maxSessionsPerUser + 1);
|
|
186
|
+
for (const session of toRemove) {
|
|
187
|
+
await this.repository.delete(session.id);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Calculate session expiration date
|
|
194
|
+
*/
|
|
195
|
+
private calculateExpiration(duration?: string): Date {
|
|
196
|
+
const expiryDuration = duration || this.options.session?.sessionExpiry || '7d';
|
|
197
|
+
const milliseconds = ms(expiryDuration);
|
|
198
|
+
return new Date(Date.now() + milliseconds);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Check if session is expired
|
|
203
|
+
*/
|
|
204
|
+
private isExpired(session: NestAuthSession): boolean {
|
|
205
|
+
if (!session.expiresAt) return false;
|
|
206
|
+
return new Date() > new Date(session.expiresAt);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Create session from user (helper method from old BaseSessionService)
|
|
211
|
+
* For backward compatibility with AuthService
|
|
212
|
+
*/
|
|
213
|
+
async createSessionFromUser(user: NestAuthUser, extraData: { isMfaVerified?: boolean } = {}): Promise<NestAuthSession> {
|
|
214
|
+
const { deviceName, ipAddress, browser } = RequestContext.getDeviceInfo();
|
|
215
|
+
const { isMfaVerified = false } = extraData;
|
|
216
|
+
|
|
217
|
+
if (!user) {
|
|
218
|
+
throw new UnauthorizedException('User not found');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const roles = await user.getRoles();
|
|
222
|
+
const permissions = await user.getPermissions();
|
|
223
|
+
|
|
224
|
+
// Create session using createSession method
|
|
225
|
+
return await this.createSession({
|
|
226
|
+
userId: user.id,
|
|
227
|
+
data: {
|
|
228
|
+
user,
|
|
229
|
+
isMfaVerified,
|
|
230
|
+
roles,
|
|
231
|
+
permissions,
|
|
232
|
+
},
|
|
233
|
+
userAgent: [browser, deviceName].join(' - '),
|
|
234
|
+
ipAddress,
|
|
235
|
+
deviceName,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create new session from existing session (for refresh)
|
|
241
|
+
* For backward compatibility with AuthService
|
|
242
|
+
*/
|
|
243
|
+
async createSessionFromSession(session: NestAuthSession): Promise<NestAuthSession> {
|
|
244
|
+
return await this.createSession({
|
|
245
|
+
userId: session.userId,
|
|
246
|
+
refreshToken: session.refreshToken,
|
|
247
|
+
data: session.data,
|
|
248
|
+
userAgent: session.userAgent,
|
|
249
|
+
deviceName: session.deviceName,
|
|
250
|
+
ipAddress: session.ipAddress,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get current active sessions for a user
|
|
256
|
+
* For backward compatibility with AuthService
|
|
257
|
+
*/
|
|
258
|
+
async getCurrentSessions(userId: string): Promise<NestAuthSession[]> {
|
|
259
|
+
return await this.getActiveSessions(userId);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Module, forwardRef } from '@nestjs/common';
|
|
2
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
+
import { NestAuthSession } from './entities/session.entity';
|
|
4
|
+
import { SessionManagerService, SESSION_REPOSITORY } from './services/session-manager.service';
|
|
5
|
+
import { TypeORMSessionRepository } from './repositories/typeorm-session.repository';
|
|
6
|
+
import { MemorySessionRepository } from './repositories/memory-session.repository';
|
|
7
|
+
import { CoreModule } from '../core/core.module';
|
|
8
|
+
import { SessionStorageType } from '../core/interfaces/session-options.interface';
|
|
9
|
+
import { AuthConfigService } from '../core/services/auth-config.service';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Session Module
|
|
13
|
+
*
|
|
14
|
+
* DEFAULT: Uses TypeORM (Database) for session storage
|
|
15
|
+
* OPTIONAL: Can use Redis if configured (requires ioredis packages)
|
|
16
|
+
*/
|
|
17
|
+
@Module({
|
|
18
|
+
imports: [
|
|
19
|
+
TypeOrmModule.forFeature([NestAuthSession]),
|
|
20
|
+
forwardRef(() => CoreModule),
|
|
21
|
+
],
|
|
22
|
+
providers: [
|
|
23
|
+
// Repository implementations
|
|
24
|
+
TypeORMSessionRepository,
|
|
25
|
+
MemorySessionRepository,
|
|
26
|
+
|
|
27
|
+
// Session Repository Provider (dynamically chooses storage)
|
|
28
|
+
{
|
|
29
|
+
provide: SESSION_REPOSITORY,
|
|
30
|
+
useFactory: (typeormRepo: TypeORMSessionRepository) => {
|
|
31
|
+
const config = AuthConfigService.getOptions();
|
|
32
|
+
const storageType = config.session?.storageType || SessionStorageType.DATABASE;
|
|
33
|
+
|
|
34
|
+
// Handle Redis storage
|
|
35
|
+
if (storageType === SessionStorageType.REDIS) {
|
|
36
|
+
return SessionModule.createRedisRepository(config.session?.redisUrl);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (storageType === SessionStorageType.MEMORY) {
|
|
40
|
+
return new MemorySessionRepository();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Default to database storage
|
|
44
|
+
return typeormRepo;
|
|
45
|
+
},
|
|
46
|
+
inject: [TypeORMSessionRepository],
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// Session Manager
|
|
50
|
+
SessionManagerService,
|
|
51
|
+
],
|
|
52
|
+
exports: [
|
|
53
|
+
SESSION_REPOSITORY,
|
|
54
|
+
SessionManagerService,
|
|
55
|
+
TypeORMSessionRepository,
|
|
56
|
+
MemorySessionRepository,
|
|
57
|
+
],
|
|
58
|
+
})
|
|
59
|
+
export class SessionModule {
|
|
60
|
+
/**
|
|
61
|
+
* Create Redis repository instance
|
|
62
|
+
* Only called if Redis storage is configured
|
|
63
|
+
*/
|
|
64
|
+
private static createRedisRepository(redisUrl?: string): any {
|
|
65
|
+
let RedisSessionRepository: any;
|
|
66
|
+
let ioredisModule: any;
|
|
67
|
+
let redisClient: any;
|
|
68
|
+
|
|
69
|
+
// Try to load Redis modules
|
|
70
|
+
try {
|
|
71
|
+
// Lazy load Redis repository
|
|
72
|
+
RedisSessionRepository = require('./repositories/redis-session.repository').RedisSessionRepository;
|
|
73
|
+
ioredisModule = require('@nestjs-modules/ioredis');
|
|
74
|
+
const Redis = require('ioredis').default || require('ioredis');
|
|
75
|
+
|
|
76
|
+
// Create Redis client
|
|
77
|
+
if (redisUrl) {
|
|
78
|
+
redisClient = new Redis(redisUrl);
|
|
79
|
+
} else {
|
|
80
|
+
redisClient = new Redis(); // Uses default localhost:6379
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Return repository instance
|
|
84
|
+
return new RedisSessionRepository(redisClient);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
87
|
+
|
|
88
|
+
if (errorMessage.includes('Cannot find module')) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'❌ Redis session storage is configured but packages are not installed.\n' +
|
|
91
|
+
' Install them with: npm install ioredis @nestjs-modules/ioredis\n' +
|
|
92
|
+
' Or change session.storageType to SessionStorageType.DATABASE'
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
throw new Error(
|
|
97
|
+
`❌ Failed to initialize Redis session storage: ${errorMessage}\n` +
|
|
98
|
+
' Make sure Redis server is running and accessible.'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|