@adonis-agora/authkit-server 0.34.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/LICENSE +21 -0
- package/README.md +158 -0
- package/build/assets/grafana/authkit-dashboard.json +118 -0
- package/build/commands/clients_create.d.ts +27 -0
- package/build/commands/clients_create.js +121 -0
- package/build/commands/commands.json +292 -0
- package/build/commands/configure.d.ts +2 -0
- package/build/commands/configure.js +45 -0
- package/build/commands/doctor.d.ts +10 -0
- package/build/commands/doctor.js +113 -0
- package/build/commands/eject.d.ts +11 -0
- package/build/commands/eject.js +96 -0
- package/build/commands/expire_scan.d.ts +28 -0
- package/build/commands/expire_scan.js +92 -0
- package/build/commands/import_users.d.ts +17 -0
- package/build/commands/import_users.js +80 -0
- package/build/commands/keys_rotate.d.ts +21 -0
- package/build/commands/keys_rotate.js +126 -0
- package/build/commands/main.d.ts +12 -0
- package/build/commands/main.js +38 -0
- package/build/commands/settings_get.d.ts +18 -0
- package/build/commands/settings_get.js +43 -0
- package/build/commands/settings_list.d.ts +17 -0
- package/build/commands/settings_list.js +39 -0
- package/build/commands/settings_set.d.ts +20 -0
- package/build/commands/settings_set.js +55 -0
- package/build/commands/settings_unset.d.ts +18 -0
- package/build/commands/settings_unset.js +46 -0
- package/build/commands/ui_preset.d.ts +4 -0
- package/build/commands/ui_preset.js +32 -0
- package/build/database/migrations/make_authkit_oidc_table.d.ts +6 -0
- package/build/database/migrations/make_authkit_oidc_table.js +19 -0
- package/build/host/ui/admin.html +29 -0
- package/build/host/views/account/apps.edge +59 -0
- package/build/host/views/account/confirm.edge +70 -0
- package/build/host/views/account/email-confirmed.edge +16 -0
- package/build/host/views/account/login.edge +33 -0
- package/build/host/views/account/mfa.edge +152 -0
- package/build/host/views/account/orgs.edge +58 -0
- package/build/host/views/account/security.edge +215 -0
- package/build/host/views/account/tokens.edge +75 -0
- package/build/host/views/consent.edge +20 -0
- package/build/host/views/forgot.edge +43 -0
- package/build/host/views/login.edge +251 -0
- package/build/host/views/maintenance.edge +32 -0
- package/build/host/views/mfa-challenge.edge +107 -0
- package/build/host/views/otp-unlock.edge +40 -0
- package/build/host/views/partials/styles.edge +2 -0
- package/build/host/views/reset.edge +30 -0
- package/build/host/views/signup.edge +62 -0
- package/build/host/views/verify-email.edge +17 -0
- package/build/index.d.ts +115 -0
- package/build/index.js +76 -0
- package/build/password/common_passwords.txt +10000 -0
- package/build/providers/authkit_server_provider.d.ts +27 -0
- package/build/providers/authkit_server_provider.js +242 -0
- package/build/src/accounts/account_store.d.ts +578 -0
- package/build/src/accounts/account_store.js +60 -0
- package/build/src/accounts/lucid_account_store.d.ts +156 -0
- package/build/src/accounts/lucid_account_store.js +294 -0
- package/build/src/accounts/lucid_store/core.d.ts +9 -0
- package/build/src/accounts/lucid_store/core.js +306 -0
- package/build/src/accounts/lucid_store/mfa.d.ts +15 -0
- package/build/src/accounts/lucid_store/mfa.js +108 -0
- package/build/src/accounts/lucid_store/organizations.d.ts +13 -0
- package/build/src/accounts/lucid_store/organizations.js +294 -0
- package/build/src/accounts/lucid_store/password_hygiene.d.ts +20 -0
- package/build/src/accounts/lucid_store/password_hygiene.js +130 -0
- package/build/src/accounts/lucid_store/provider_identity.d.ts +8 -0
- package/build/src/accounts/lucid_store/provider_identity.js +59 -0
- package/build/src/accounts/lucid_store/shared.d.ts +113 -0
- package/build/src/accounts/lucid_store/shared.js +130 -0
- package/build/src/accounts/lucid_store/status_profile.d.ts +34 -0
- package/build/src/accounts/lucid_store/status_profile.js +100 -0
- package/build/src/accounts/lucid_store/webauthn.d.ts +8 -0
- package/build/src/accounts/lucid_store/webauthn.js +140 -0
- package/build/src/accounts/lucid_stores.d.ts +45 -0
- package/build/src/accounts/lucid_stores.js +30 -0
- package/build/src/adapters/adapter_contract.d.ts +37 -0
- package/build/src/adapters/adapter_contract.js +1 -0
- package/build/src/adapters/database_adapter.d.ts +21 -0
- package/build/src/adapters/database_adapter.js +79 -0
- package/build/src/adapters/factory.d.ts +30 -0
- package/build/src/adapters/factory.js +43 -0
- package/build/src/adapters/redis_adapter.d.ts +24 -0
- package/build/src/adapters/redis_adapter.js +122 -0
- package/build/src/audit/audit_sink.d.ts +63 -0
- package/build/src/audit/audit_sink.js +1 -0
- package/build/src/audit/lucid_audit_sink.d.ts +10 -0
- package/build/src/audit/lucid_audit_sink.js +99 -0
- package/build/src/commands/expire_scan_command.d.ts +60 -0
- package/build/src/commands/expire_scan_command.js +229 -0
- package/build/src/commands/import_clients.d.ts +40 -0
- package/build/src/commands/import_clients.js +79 -0
- package/build/src/commands/import_users.d.ts +51 -0
- package/build/src/commands/import_users.js +94 -0
- package/build/src/commands/resolve_config.d.ts +13 -0
- package/build/src/commands/resolve_config.js +18 -0
- package/build/src/commands/settings_commands.d.ts +47 -0
- package/build/src/commands/settings_commands.js +270 -0
- package/build/src/controllers/oidc_callback_controller.d.ts +22 -0
- package/build/src/controllers/oidc_callback_controller.js +33 -0
- package/build/src/define_config.d.ts +772 -0
- package/build/src/define_config.js +351 -0
- package/build/src/doctor/checks.d.ts +197 -0
- package/build/src/doctor/checks.js +858 -0
- package/build/src/events/dispatcher.d.ts +45 -0
- package/build/src/events/dispatcher.js +117 -0
- package/build/src/host/account_api/account_api_controller.d.ts +245 -0
- package/build/src/host/account_api/account_api_controller.js +827 -0
- package/build/src/host/account_deletion_ops.d.ts +80 -0
- package/build/src/host/account_deletion_ops.js +118 -0
- package/build/src/host/account_deletion_service.d.ts +63 -0
- package/build/src/host/account_deletion_service.js +133 -0
- package/build/src/host/account_export_service.d.ts +76 -0
- package/build/src/host/account_export_service.js +140 -0
- package/build/src/host/account_home.d.ts +11 -0
- package/build/src/host/account_home.js +11 -0
- package/build/src/host/account_lockout.d.ts +86 -0
- package/build/src/host/account_lockout.js +185 -0
- package/build/src/host/active_org_cookie.d.ts +28 -0
- package/build/src/host/active_org_cookie.js +47 -0
- package/build/src/host/admin_api/admin_api_guard.d.ts +16 -0
- package/build/src/host/admin_api/admin_api_guard.js +59 -0
- package/build/src/host/admin_api/admin_orgs_service.d.ts +125 -0
- package/build/src/host/admin_api/admin_orgs_service.js +324 -0
- package/build/src/host/admin_api/admin_users_service.d.ts +163 -0
- package/build/src/host/admin_api/admin_users_service.js +308 -0
- package/build/src/host/admin_api/api_clients_controller.d.ts +54 -0
- package/build/src/host/admin_api/api_clients_controller.js +89 -0
- package/build/src/host/admin_api/api_keys_controller.d.ts +19 -0
- package/build/src/host/admin_api/api_keys_controller.js +36 -0
- package/build/src/host/admin_api/api_misc_controller.d.ts +19 -0
- package/build/src/host/admin_api/api_misc_controller.js +44 -0
- package/build/src/host/admin_api/api_orgs_controller.d.ts +108 -0
- package/build/src/host/admin_api/api_orgs_controller.js +189 -0
- package/build/src/host/admin_api/api_settings_controller.d.ts +55 -0
- package/build/src/host/admin_api/api_settings_controller.js +134 -0
- package/build/src/host/admin_api/api_users_controller.d.ts +108 -0
- package/build/src/host/admin_api/api_users_controller.js +187 -0
- package/build/src/host/admin_api/dto.d.ts +131 -0
- package/build/src/host/admin_api/dto.js +122 -0
- package/build/src/host/admin_api/token_verify_service.d.ts +34 -0
- package/build/src/host/admin_api/token_verify_service.js +74 -0
- package/build/src/host/admin_clients_service.d.ts +88 -0
- package/build/src/host/admin_clients_service.js +181 -0
- package/build/src/host/admin_console/admin_shell_controller.d.ts +27 -0
- package/build/src/host/admin_console/admin_shell_controller.js +167 -0
- package/build/src/host/admin_console/console_audit_controller.d.ts +17 -0
- package/build/src/host/admin_console/console_audit_controller.js +25 -0
- package/build/src/host/admin_console/console_clients_controller.d.ts +53 -0
- package/build/src/host/admin_console/console_clients_controller.js +102 -0
- package/build/src/host/admin_console/console_impersonation_controller.d.ts +23 -0
- package/build/src/host/admin_console/console_impersonation_controller.js +45 -0
- package/build/src/host/admin_console/console_keys_controller.d.ts +24 -0
- package/build/src/host/admin_console/console_keys_controller.js +41 -0
- package/build/src/host/admin_console/console_orgs_controller.d.ts +96 -0
- package/build/src/host/admin_console/console_orgs_controller.js +238 -0
- package/build/src/host/admin_console/console_overview_controller.d.ts +27 -0
- package/build/src/host/admin_console/console_overview_controller.js +44 -0
- package/build/src/host/admin_console/console_roles_controller.d.ts +31 -0
- package/build/src/host/admin_console/console_roles_controller.js +108 -0
- package/build/src/host/admin_console/console_sessions_controller.d.ts +91 -0
- package/build/src/host/admin_console/console_sessions_controller.js +125 -0
- package/build/src/host/admin_console/console_settings_controller.d.ts +47 -0
- package/build/src/host/admin_console/console_settings_controller.js +115 -0
- package/build/src/host/admin_console/console_users_controller.d.ts +110 -0
- package/build/src/host/admin_console/console_users_controller.js +212 -0
- package/build/src/host/admin_prefix.d.ts +50 -0
- package/build/src/host/admin_prefix.js +77 -0
- package/build/src/host/admin_sessions_service.d.ts +119 -0
- package/build/src/host/admin_sessions_service.js +284 -0
- package/build/src/host/admin_stats_service.d.ts +44 -0
- package/build/src/host/admin_stats_service.js +130 -0
- package/build/src/host/admin_validators.d.ts +247 -0
- package/build/src/host/admin_validators.js +197 -0
- package/build/src/host/augmentations.d.ts +12 -0
- package/build/src/host/augmentations.js +1 -0
- package/build/src/host/auth_host_config.d.ts +22 -0
- package/build/src/host/auth_host_config.js +13 -0
- package/build/src/host/avatar_storage.d.ts +68 -0
- package/build/src/host/avatar_storage.js +166 -0
- package/build/src/host/bot_protection.d.ts +187 -0
- package/build/src/host/bot_protection.js +132 -0
- package/build/src/host/branding.d.ts +19 -0
- package/build/src/host/branding.js +8 -0
- package/build/src/host/config_locks.d.ts +38 -0
- package/build/src/host/config_locks.js +70 -0
- package/build/src/host/console_session.d.ts +27 -0
- package/build/src/host/console_session.js +36 -0
- package/build/src/host/controllers/account_apps_controller.d.ts +15 -0
- package/build/src/host/controllers/account_apps_controller.js +61 -0
- package/build/src/host/controllers/account_confirm_controller.d.ts +24 -0
- package/build/src/host/controllers/account_confirm_controller.js +144 -0
- package/build/src/host/controllers/account_mfa_controller.d.ts +28 -0
- package/build/src/host/controllers/account_mfa_controller.js +208 -0
- package/build/src/host/controllers/account_orgs_controller.d.ts +80 -0
- package/build/src/host/controllers/account_orgs_controller.js +401 -0
- package/build/src/host/controllers/account_security_controller.d.ts +43 -0
- package/build/src/host/controllers/account_security_controller.js +546 -0
- package/build/src/host/controllers/account_session_controller.d.ts +21 -0
- package/build/src/host/controllers/account_session_controller.js +113 -0
- package/build/src/host/controllers/account_tokens_controller.d.ts +7 -0
- package/build/src/host/controllers/account_tokens_controller.js +67 -0
- package/build/src/host/controllers/interaction_controller.d.ts +125 -0
- package/build/src/host/controllers/interaction_controller.js +981 -0
- package/build/src/host/controllers/pat_introspection_controller.d.ts +22 -0
- package/build/src/host/controllers/pat_introspection_controller.js +46 -0
- package/build/src/host/controllers/registration_controller.d.ts +18 -0
- package/build/src/host/controllers/registration_controller.js +382 -0
- package/build/src/host/controllers/social_controller.d.ts +8 -0
- package/build/src/host/controllers/social_controller.js +89 -0
- package/build/src/host/csrf.d.ts +29 -0
- package/build/src/host/csrf.js +14 -0
- package/build/src/host/default_mailer.d.ts +112 -0
- package/build/src/host/default_mailer.js +417 -0
- package/build/src/host/durable/account_deletion_workflow.d.ts +48 -0
- package/build/src/host/durable/account_deletion_workflow.js +86 -0
- package/build/src/host/durable/account_export_workflow.d.ts +68 -0
- package/build/src/host/durable/account_export_workflow.js +93 -0
- package/build/src/host/durable/index.d.ts +68 -0
- package/build/src/host/durable/index.js +77 -0
- package/build/src/host/email_templates.d.ts +39 -0
- package/build/src/host/email_templates.js +69 -0
- package/build/src/host/geo.d.ts +22 -0
- package/build/src/host/geo.js +39 -0
- package/build/src/host/i18n.d.ts +1416 -0
- package/build/src/host/i18n.js +1583 -0
- package/build/src/host/impersonation.d.ts +25 -0
- package/build/src/host/impersonation.js +31 -0
- package/build/src/host/key_rotation.d.ts +14 -0
- package/build/src/host/key_rotation.js +27 -0
- package/build/src/host/key_rotation_actions.d.ts +42 -0
- package/build/src/host/key_rotation_actions.js +27 -0
- package/build/src/host/login_attempt.d.ts +98 -0
- package/build/src/host/login_attempt.js +211 -0
- package/build/src/host/login_notify.d.ts +27 -0
- package/build/src/host/login_notify.js +142 -0
- package/build/src/host/middleware/account_auth.d.ts +7 -0
- package/build/src/host/middleware/account_auth.js +11 -0
- package/build/src/host/otp_lockout.d.ts +103 -0
- package/build/src/host/otp_lockout.js +221 -0
- package/build/src/host/rate_limit.d.ts +39 -0
- package/build/src/host/rate_limit.js +94 -0
- package/build/src/host/register_auth_host.d.ts +97 -0
- package/build/src/host/register_auth_host.js +466 -0
- package/build/src/host/renderers/edge_renderer.d.ts +12 -0
- package/build/src/host/renderers/edge_renderer.js +38 -0
- package/build/src/host/renderers/inertia_renderer.d.ts +70 -0
- package/build/src/host/renderers/inertia_renderer.js +54 -0
- package/build/src/host/runtime_settings.d.ts +181 -0
- package/build/src/host/runtime_settings.js +307 -0
- package/build/src/host/runtime_toggles.d.ts +807 -0
- package/build/src/host/runtime_toggles.js +784 -0
- package/build/src/host/security_notice_service.d.ts +36 -0
- package/build/src/host/security_notice_service.js +87 -0
- package/build/src/host/session_context.d.ts +23 -0
- package/build/src/host/session_context.js +89 -0
- package/build/src/host/sudo_mode.d.ts +56 -0
- package/build/src/host/sudo_mode.js +99 -0
- package/build/src/host/svg_chart.d.ts +15 -0
- package/build/src/host/svg_chart.js +45 -0
- package/build/src/host/trusted_device.d.ts +61 -0
- package/build/src/host/trusted_device.js +65 -0
- package/build/src/host/ui-dist/assets/index-CRWcmsex.js +137 -0
- package/build/src/host/ui-dist/assets/index-DTSmD4RU.css +1 -0
- package/build/src/host/ui-dist/index.html +17 -0
- package/build/src/host/user_agent.d.ts +18 -0
- package/build/src/host/user_agent.js +50 -0
- package/build/src/host/validators.d.ts +127 -0
- package/build/src/host/validators.js +53 -0
- package/build/src/keys/jwks_manager.d.ts +6 -0
- package/build/src/keys/jwks_manager.js +11 -0
- package/build/src/keys/keystore.d.ts +52 -0
- package/build/src/keys/keystore.js +68 -0
- package/build/src/keys/keystore_codec.d.ts +20 -0
- package/build/src/keys/keystore_codec.js +42 -0
- package/build/src/keys/keystore_crypto.d.ts +9 -0
- package/build/src/keys/keystore_crypto.js +27 -0
- package/build/src/keys/keystore_manager.d.ts +43 -0
- package/build/src/keys/keystore_manager.js +104 -0
- package/build/src/keys/keystore_vault.d.ts +113 -0
- package/build/src/keys/keystore_vault.js +265 -0
- package/build/src/mixins/json_column.d.ts +33 -0
- package/build/src/mixins/json_column.js +38 -0
- package/build/src/mixins/with_audit_log.d.ts +19 -0
- package/build/src/mixins/with_audit_log.js +39 -0
- package/build/src/mixins/with_auth_user.d.ts +24 -0
- package/build/src/mixins/with_auth_user.js +46 -0
- package/build/src/mixins/with_credentials.d.ts +20 -0
- package/build/src/mixins/with_credentials.js +29 -0
- package/build/src/mixins/with_mfa.d.ts +35 -0
- package/build/src/mixins/with_mfa.js +21 -0
- package/build/src/mixins/with_personal_access_token.d.ts +19 -0
- package/build/src/mixins/with_personal_access_token.js +42 -0
- package/build/src/mixins/with_provider_identity.d.ts +20 -0
- package/build/src/mixins/with_provider_identity.js +32 -0
- package/build/src/mixins/with_webauthn_credential.d.ts +37 -0
- package/build/src/mixins/with_webauthn_credential.js +46 -0
- package/build/src/observability/diagnostics_bridge.d.ts +6 -0
- package/build/src/observability/diagnostics_bridge.js +27 -0
- package/build/src/observability/metrics_controller.d.ts +5 -0
- package/build/src/observability/metrics_controller.js +24 -0
- package/build/src/observability/metrics_service.d.ts +2 -0
- package/build/src/observability/metrics_service.js +7 -0
- package/build/src/observability/otel_recorder.d.ts +10 -0
- package/build/src/observability/otel_recorder.js +59 -0
- package/build/src/observability/telescope/data_providers.d.ts +24 -0
- package/build/src/observability/telescope/data_providers.js +235 -0
- package/build/src/observability/telescope/extension.d.ts +29 -0
- package/build/src/observability/telescope/extension.js +167 -0
- package/build/src/observability/telescope/index.d.ts +8 -0
- package/build/src/observability/telescope/index.js +8 -0
- package/build/src/observability/wire_provider_events.d.ts +12 -0
- package/build/src/observability/wire_provider_events.js +30 -0
- package/build/src/password/common_passwords.d.ts +31 -0
- package/build/src/password/common_passwords.js +73 -0
- package/build/src/password/password_manager.d.ts +163 -0
- package/build/src/password/password_manager.js +191 -0
- package/build/src/password/policy.d.ts +71 -0
- package/build/src/password/policy.js +55 -0
- package/build/src/password/pwned.d.ts +36 -0
- package/build/src/password/pwned.js +52 -0
- package/build/src/pat/lucid_pat_store.d.ts +6 -0
- package/build/src/pat/lucid_pat_store.js +62 -0
- package/build/src/pat/pat_store.d.ts +31 -0
- package/build/src/pat/pat_store.js +1 -0
- package/build/src/pat/pat_tokens.d.ts +4 -0
- package/build/src/pat/pat_tokens.js +9 -0
- package/build/src/provider/build_provider.d.ts +45 -0
- package/build/src/provider/build_provider.js +219 -0
- package/build/src/provider/device_sources.d.ts +6 -0
- package/build/src/provider/device_sources.js +65 -0
- package/build/src/provider/interaction_actions.d.ts +36 -0
- package/build/src/provider/interaction_actions.js +55 -0
- package/build/src/provider/key_rotation_scheduler.d.ts +28 -0
- package/build/src/provider/key_rotation_scheduler.js +40 -0
- package/build/src/provider/keystore_reload.d.ts +21 -0
- package/build/src/provider/keystore_reload.js +39 -0
- package/build/src/provider/logout_sources.d.ts +13 -0
- package/build/src/provider/logout_sources.js +64 -0
- package/build/src/provider/oidc_service.d.ts +81 -0
- package/build/src/provider/oidc_service.js +254 -0
- package/build/src/provider/single_flight_lock.d.ts +18 -0
- package/build/src/provider/single_flight_lock.js +31 -0
- package/build/src/provider/token_exchange.d.ts +21 -0
- package/build/src/provider/token_exchange.js +124 -0
- package/build/src/register_routes.d.ts +16 -0
- package/build/src/register_routes.js +21 -0
- package/build/src/schema/ensure.d.ts +41 -0
- package/build/src/schema/ensure.js +262 -0
- package/build/stubs/config/authkit.stub +20 -0
- package/build/stubs/config/authkit_react.stub +52 -0
- package/build/stubs/main.d.ts +1 -0
- package/build/stubs/main.js +2 -0
- package/build/stubs/models/auth_user.stub +22 -0
- package/build/stubs/ui/edge/views/consent.edge +13 -0
- package/build/stubs/ui/edge/views/login.edge +19 -0
- package/build/stubs/ui/react/components/auth_shell.tsx +67 -0
- package/build/stubs/ui/react/pages/account/login.tsx +56 -0
- package/build/stubs/ui/react/pages/account/mfa.tsx +132 -0
- package/build/stubs/ui/react/pages/account/tokens.tsx +88 -0
- package/build/stubs/ui/react/pages/consent.tsx +39 -0
- package/build/stubs/ui/react/pages/forgot.tsx +44 -0
- package/build/stubs/ui/react/pages/login.tsx +171 -0
- package/build/stubs/ui/react/pages/mfa-challenge.tsx +72 -0
- package/build/stubs/ui/react/pages/reset.tsx +58 -0
- package/build/stubs/ui/react/pages/signup.tsx +78 -0
- package/build/stubs/ui/react/pages/verify-email.tsx +24 -0
- package/build/types.d.ts +7 -0
- package/build/types.js +1 -0
- package/package.json +147 -0
- package/stubs/config/authkit.stub +20 -0
- package/stubs/config/authkit_react.stub +52 -0
- package/stubs/main.ts +2 -0
- package/stubs/models/auth_user.stub +22 -0
- package/stubs/ui/edge/views/consent.edge +13 -0
- package/stubs/ui/edge/views/login.edge +19 -0
- package/stubs/ui/react/components/auth_shell.tsx +67 -0
- package/stubs/ui/react/pages/account/login.tsx +56 -0
- package/stubs/ui/react/pages/account/mfa.tsx +132 -0
- package/stubs/ui/react/pages/account/tokens.tsx +88 -0
- package/stubs/ui/react/pages/consent.tsx +39 -0
- package/stubs/ui/react/pages/forgot.tsx +44 -0
- package/stubs/ui/react/pages/login.tsx +171 -0
- package/stubs/ui/react/pages/mfa-challenge.tsx +72 -0
- package/stubs/ui/react/pages/reset.tsx +58 -0
- package/stubs/ui/react/pages/signup.tsx +78 -0
- package/stubs/ui/react/pages/verify-email.tsx +24 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { type PasswordPolicyViolation, type ResolvedPasswordConfig } from './policy.js';
|
|
2
|
+
import { type PwnedLogger, type FetchLike } from './pwned.js';
|
|
3
|
+
/**
|
|
4
|
+
* Verificador de hashes legados (de OUTROS sistemas). Chamado quando a
|
|
5
|
+
* verificação nativa do hasher do Adonis falha OU não reconhece o formato do
|
|
6
|
+
* hash (ex.: bcrypt PHP `$2y$`, Django `pbkdf2_sha256$`, MD5, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Retorno:
|
|
9
|
+
* - `true` → a senha confere (o store então re-hasheia com o hasher atual);
|
|
10
|
+
* - `false` → a senha NÃO confere;
|
|
11
|
+
* - `null` → este verifier não trata esse formato (deixa o login falhar).
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // bcrypt vindo do PHP usa o prefixo `$2y$`; o hasher bcrypt do Node entende
|
|
15
|
+
* // `$2b$`. A conversão é só trocar o prefixo (mesmo algoritmo):
|
|
16
|
+
* const legacyVerifier = async (hashed, plain) => {
|
|
17
|
+
* if (!hashed.startsWith('$2y$')) return null // não é meu formato
|
|
18
|
+
* const normalized = '$2b$' + hashed.slice(4)
|
|
19
|
+
* return bcrypt.compare(plain, normalized) // true | false
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export type LegacyPasswordVerifier = (hashedPassword: string, plainPassword: string) => Promise<boolean | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Config de senha aceita pelo store (entrada do host).
|
|
25
|
+
*
|
|
26
|
+
* Política de complexidade e checagem de vazamento são gerenciadas em runtime
|
|
27
|
+
* via setting `password_policy` no admin console ou Admin API.
|
|
28
|
+
* Aqui ficam apenas os parâmetros de infra/código.
|
|
29
|
+
*/
|
|
30
|
+
export interface PasswordConfigInput {
|
|
31
|
+
/**
|
|
32
|
+
* Verificador de hashes legados de outros sistemas. Acionado quando a
|
|
33
|
+
* verificação nativa falha. Veja {@link LegacyPasswordVerifier}.
|
|
34
|
+
*/
|
|
35
|
+
legacyVerifier?: LegacyPasswordVerifier;
|
|
36
|
+
/**
|
|
37
|
+
* Pepper de infra (segredo de boot). HMAC-SHA256 da senha ANTES do hasher
|
|
38
|
+
* seguindo OWASP (defense-in-depth: DB comprometido sem o pepper = hashes
|
|
39
|
+
* inúteis).
|
|
40
|
+
*
|
|
41
|
+
* - `string` → pepper corrente.
|
|
42
|
+
* - `string[]` → rotação: o PRIMEIRO é o corrente (hash); TODOS são tentados
|
|
43
|
+
* no verify. Se confere com um pepper antigo → lazy re-hash com o corrente.
|
|
44
|
+
* - Ausente → comportamento original (sem HMAC, back-compat total).
|
|
45
|
+
*
|
|
46
|
+
* IMPORTANTE: Contas existentes podem ter hash SEM pepper — o verify tenta
|
|
47
|
+
* com cada pepper E sem pepper (legacy); em sucesso re-hasheia com o corrente.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // config/authkit.ts
|
|
51
|
+
* password: { pepper: env.get('PASSWORD_PEPPER') }
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Rotação: novo pepper primeiro, antigos no array.
|
|
55
|
+
* password: { pepper: [env.get('PEPPER_V2'), env.get('PEPPER_V1')] }
|
|
56
|
+
*/
|
|
57
|
+
pepper?: string | string[];
|
|
58
|
+
/**
|
|
59
|
+
* Timeout em ms para a checagem de vazamento HIBP (HaveIBeenPwned). Infra.
|
|
60
|
+
* Default: 2000 ms. A checagem é habilitada/desabilitada via runtime setting
|
|
61
|
+
* `password_policy.checkPwned` no admin console.
|
|
62
|
+
*/
|
|
63
|
+
pwnedTimeoutMs?: number;
|
|
64
|
+
}
|
|
65
|
+
/** Erro de política/vazamento de senha — carrega a chave i18n + params. */
|
|
66
|
+
export declare class PasswordPolicyError extends Error {
|
|
67
|
+
readonly key: PasswordPolicyViolation | 'password.pwned' | 'password.reused' | 'password.common';
|
|
68
|
+
readonly params?: Record<string, string | number> | undefined;
|
|
69
|
+
constructor(key: PasswordPolicyViolation | 'password.pwned' | 'password.reused' | 'password.common', params?: Record<string, string | number> | undefined);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Aplica o pepper à senha em claro via HMAC-SHA256, retornando um hex-digest
|
|
73
|
+
* que será entregue ao hasher como se fosse a senha. Sem pepper → retorna a
|
|
74
|
+
* senha inalterada (back-compat total).
|
|
75
|
+
*/
|
|
76
|
+
export declare function applyPepper(plain: string, pepper: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Resolve o array de peppers a tentar no verify, incluindo o sentinel "sem
|
|
79
|
+
* pepper" (cadeia vazia) para back-compat com hashes antigos sem pepper.
|
|
80
|
+
*
|
|
81
|
+
* @returns [corrente, ...antigos, ''] — string vazia = tentar sem HMAC (legacy).
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolvePeppers(pepper: string | string[] | undefined): string[];
|
|
84
|
+
/**
|
|
85
|
+
* Aplica o pepper corrente à senha em claro. O pepper corrente é SEMPRE o
|
|
86
|
+
* primeiro do array (ou a string direta). Sem pepper → retorna a senha.
|
|
87
|
+
*/
|
|
88
|
+
export declare function applyCurrentPepper(plain: string, pepper: string | string[] | undefined): string;
|
|
89
|
+
/**
|
|
90
|
+
* Resultado de uma verificação de senha pelo manager. `rehash` indica que a
|
|
91
|
+
* senha confere mas o hash armazenado deve ser re-gerado (formato legado OU
|
|
92
|
+
* parâmetros do hasher desatualizados) — o chamador (store) persiste o novo hash
|
|
93
|
+
* best-effort.
|
|
94
|
+
*/
|
|
95
|
+
export interface PasswordVerifyResult {
|
|
96
|
+
ok: boolean;
|
|
97
|
+
rehash: boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Concentra a lógica de senha do store: validação de política + vazamento (ao
|
|
101
|
+
* DEFINIR uma senha) e verificação com lazy rehash + legacy verifier (ao
|
|
102
|
+
* AUTENTICAR). A política usa lib defaults — a runtime setting `password_policy`
|
|
103
|
+
* é a única fonte de customização (via `assertAcceptable` com override).
|
|
104
|
+
*/
|
|
105
|
+
export declare class PasswordManager {
|
|
106
|
+
readonly config: ResolvedPasswordConfig;
|
|
107
|
+
private readonly legacyVerifier?;
|
|
108
|
+
private readonly logger?;
|
|
109
|
+
private readonly fetchImpl?;
|
|
110
|
+
/** Pepper configurado (secret de boot). Pode ser string ou array para rotação. */
|
|
111
|
+
readonly pepper: string | string[] | undefined;
|
|
112
|
+
/** Timeout em ms para a checagem de vazamento HIBP. */
|
|
113
|
+
readonly pwnedTimeoutMs: number;
|
|
114
|
+
constructor(input?: PasswordConfigInput, deps?: {
|
|
115
|
+
logger?: PwnedLogger;
|
|
116
|
+
fetchImpl?: FetchLike;
|
|
117
|
+
});
|
|
118
|
+
/** Há um verificador de hash legado configurado? */
|
|
119
|
+
hasLegacyVerifier(): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Aplica o pepper corrente à senha em claro antes do hash. Sem pepper →
|
|
122
|
+
* retorna a senha inalterada (back-compat total).
|
|
123
|
+
*/
|
|
124
|
+
applyCurrentPepper(plain: string): string;
|
|
125
|
+
/**
|
|
126
|
+
* Valida uma senha NOVA: política primeiro (barata, local), depois vazamento
|
|
127
|
+
* (rede, opcional, fail-safe). Lança {@link PasswordPolicyError} na 1ª falha.
|
|
128
|
+
*
|
|
129
|
+
* @param policyOverride - Política resolvida em runtime (via setting `password_policy`).
|
|
130
|
+
* Quando fornecida, sobrescreve os defaults da lib para esta chamada.
|
|
131
|
+
*/
|
|
132
|
+
assertAcceptable(plainPassword: string, policyOverride?: {
|
|
133
|
+
minLength?: number;
|
|
134
|
+
requireUppercase?: boolean;
|
|
135
|
+
requireLowercase?: boolean;
|
|
136
|
+
requireNumbers?: boolean;
|
|
137
|
+
requireSymbols?: boolean;
|
|
138
|
+
checkPwned?: boolean;
|
|
139
|
+
blockCommon?: boolean;
|
|
140
|
+
}): Promise<void>;
|
|
141
|
+
/**
|
|
142
|
+
* Verifica `plainPassword` contra o `hashedPassword` armazenado, com suporte
|
|
143
|
+
* a pepper.
|
|
144
|
+
*
|
|
145
|
+
* Sequência:
|
|
146
|
+
* 1. Para cada pepper possível (corrente + antigos + sem pepper para legacy):
|
|
147
|
+
* a. `nativeVerify(hashed, peppered(plain))`. Se OK → checa `needsRehash`
|
|
148
|
+
* e devolve `{ ok: true, rehash }`. rehash=true quando pepper não é o
|
|
149
|
+
* corrente (re-hash com o corrente transparente).
|
|
150
|
+
* 2. Se nenhum pepper funcionou com native, tenta o `legacyVerifier` com
|
|
151
|
+
* `applyCurrentPepper(plain)` (e também sem pepper, para import de sistemas
|
|
152
|
+
* legados antes de pepperar).
|
|
153
|
+
* `true` → `{ ok: true, rehash: true }`;
|
|
154
|
+
* `false`/`null` → `{ ok: false, rehash: false }`.
|
|
155
|
+
*
|
|
156
|
+
* `nativeVerify`/`needsRehash` são injetados pelo store (vêm do model Lucid),
|
|
157
|
+
* mantendo este manager desacoplado do Lucid.
|
|
158
|
+
*/
|
|
159
|
+
verify(hashedPassword: string, plainPassword: string, hooks: {
|
|
160
|
+
nativeVerify: (hashed: string, plain: string) => Promise<boolean>;
|
|
161
|
+
needsRehash: (hashed: string) => boolean;
|
|
162
|
+
}): Promise<PasswordVerifyResult>;
|
|
163
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { checkPasswordPolicy, policyViolationParams, resolvePasswordConfig, DEFAULT_PWNED_TIMEOUT_MS, } from './policy.js';
|
|
3
|
+
import { isPasswordPwned } from './pwned.js';
|
|
4
|
+
import { isCommonPassword } from './common_passwords.js';
|
|
5
|
+
/** Erro de política/vazamento de senha — carrega a chave i18n + params. */
|
|
6
|
+
export class PasswordPolicyError extends Error {
|
|
7
|
+
key;
|
|
8
|
+
params;
|
|
9
|
+
constructor(key, params) {
|
|
10
|
+
super(key);
|
|
11
|
+
this.key = key;
|
|
12
|
+
this.params = params;
|
|
13
|
+
this.name = 'PasswordPolicyError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Pepper helpers (OWASP pattern: HMAC-SHA256 before hashing)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Aplica o pepper à senha em claro via HMAC-SHA256, retornando um hex-digest
|
|
21
|
+
* que será entregue ao hasher como se fosse a senha. Sem pepper → retorna a
|
|
22
|
+
* senha inalterada (back-compat total).
|
|
23
|
+
*/
|
|
24
|
+
export function applyPepper(plain, pepper) {
|
|
25
|
+
return createHmac('sha256', pepper).update(plain).digest('hex');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve o array de peppers a tentar no verify, incluindo o sentinel "sem
|
|
29
|
+
* pepper" (cadeia vazia) para back-compat com hashes antigos sem pepper.
|
|
30
|
+
*
|
|
31
|
+
* @returns [corrente, ...antigos, ''] — string vazia = tentar sem HMAC (legacy).
|
|
32
|
+
*/
|
|
33
|
+
export function resolvePeppers(pepper) {
|
|
34
|
+
if (!pepper)
|
|
35
|
+
return [''];
|
|
36
|
+
const arr = Array.isArray(pepper) ? pepper : [pepper];
|
|
37
|
+
// Inclui string vazia no final para tentar sem pepper (legacy back-compat).
|
|
38
|
+
return [...arr, ''];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Aplica o pepper corrente à senha em claro. O pepper corrente é SEMPRE o
|
|
42
|
+
* primeiro do array (ou a string direta). Sem pepper → retorna a senha.
|
|
43
|
+
*/
|
|
44
|
+
export function applyCurrentPepper(plain, pepper) {
|
|
45
|
+
if (!pepper)
|
|
46
|
+
return plain;
|
|
47
|
+
const current = Array.isArray(pepper) ? pepper[0] : pepper;
|
|
48
|
+
if (!current)
|
|
49
|
+
return plain;
|
|
50
|
+
return applyPepper(plain, current);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Concentra a lógica de senha do store: validação de política + vazamento (ao
|
|
54
|
+
* DEFINIR uma senha) e verificação com lazy rehash + legacy verifier (ao
|
|
55
|
+
* AUTENTICAR). A política usa lib defaults — a runtime setting `password_policy`
|
|
56
|
+
* é a única fonte de customização (via `assertAcceptable` com override).
|
|
57
|
+
*/
|
|
58
|
+
export class PasswordManager {
|
|
59
|
+
config;
|
|
60
|
+
legacyVerifier;
|
|
61
|
+
logger;
|
|
62
|
+
fetchImpl;
|
|
63
|
+
/** Pepper configurado (secret de boot). Pode ser string ou array para rotação. */
|
|
64
|
+
pepper;
|
|
65
|
+
/** Timeout em ms para a checagem de vazamento HIBP. */
|
|
66
|
+
pwnedTimeoutMs;
|
|
67
|
+
constructor(input = {}, deps = {}) {
|
|
68
|
+
// Lib defaults: minLength=8, sem complexidade, sem checkPwned (setting-driven).
|
|
69
|
+
this.config = resolvePasswordConfig({});
|
|
70
|
+
this.legacyVerifier = input.legacyVerifier;
|
|
71
|
+
this.logger = deps.logger;
|
|
72
|
+
this.fetchImpl = deps.fetchImpl;
|
|
73
|
+
this.pepper = input.pepper;
|
|
74
|
+
this.pwnedTimeoutMs = input.pwnedTimeoutMs ?? DEFAULT_PWNED_TIMEOUT_MS;
|
|
75
|
+
}
|
|
76
|
+
/** Há um verificador de hash legado configurado? */
|
|
77
|
+
hasLegacyVerifier() {
|
|
78
|
+
return typeof this.legacyVerifier === 'function';
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Aplica o pepper corrente à senha em claro antes do hash. Sem pepper →
|
|
82
|
+
* retorna a senha inalterada (back-compat total).
|
|
83
|
+
*/
|
|
84
|
+
applyCurrentPepper(plain) {
|
|
85
|
+
return applyCurrentPepper(plain, this.pepper);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Valida uma senha NOVA: política primeiro (barata, local), depois vazamento
|
|
89
|
+
* (rede, opcional, fail-safe). Lança {@link PasswordPolicyError} na 1ª falha.
|
|
90
|
+
*
|
|
91
|
+
* @param policyOverride - Política resolvida em runtime (via setting `password_policy`).
|
|
92
|
+
* Quando fornecida, sobrescreve os defaults da lib para esta chamada.
|
|
93
|
+
*/
|
|
94
|
+
async assertAcceptable(plainPassword, policyOverride) {
|
|
95
|
+
const effectivePolicy = policyOverride
|
|
96
|
+
? {
|
|
97
|
+
minLength: policyOverride.minLength ?? this.config.policy.minLength,
|
|
98
|
+
requireUppercase: policyOverride.requireUppercase ?? this.config.policy.requireUppercase,
|
|
99
|
+
requireLowercase: policyOverride.requireLowercase ?? this.config.policy.requireLowercase,
|
|
100
|
+
requireNumbers: policyOverride.requireNumbers ?? this.config.policy.requireNumbers,
|
|
101
|
+
requireSymbols: policyOverride.requireSymbols ?? this.config.policy.requireSymbols,
|
|
102
|
+
}
|
|
103
|
+
: this.config.policy;
|
|
104
|
+
const violation = checkPasswordPolicy(plainPassword, effectivePolicy);
|
|
105
|
+
if (violation) {
|
|
106
|
+
throw new PasswordPolicyError(violation, policyViolationParams(violation, effectivePolicy));
|
|
107
|
+
}
|
|
108
|
+
// Checagem offline de senhas comuns (case-insensitive, ANTES do HIBP).
|
|
109
|
+
// Default: blockCommon=true. Somente pula se explicitamente desligado.
|
|
110
|
+
const blockCommon = policyOverride?.blockCommon !== false;
|
|
111
|
+
if (blockCommon && isCommonPassword(plainPassword)) {
|
|
112
|
+
throw new PasswordPolicyError('password.common');
|
|
113
|
+
}
|
|
114
|
+
if (policyOverride?.checkPwned) {
|
|
115
|
+
const pwned = await isPasswordPwned(plainPassword, {
|
|
116
|
+
timeoutMs: this.pwnedTimeoutMs,
|
|
117
|
+
logger: this.logger,
|
|
118
|
+
fetchImpl: this.fetchImpl,
|
|
119
|
+
});
|
|
120
|
+
if (pwned)
|
|
121
|
+
throw new PasswordPolicyError('password.pwned');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Verifica `plainPassword` contra o `hashedPassword` armazenado, com suporte
|
|
126
|
+
* a pepper.
|
|
127
|
+
*
|
|
128
|
+
* Sequência:
|
|
129
|
+
* 1. Para cada pepper possível (corrente + antigos + sem pepper para legacy):
|
|
130
|
+
* a. `nativeVerify(hashed, peppered(plain))`. Se OK → checa `needsRehash`
|
|
131
|
+
* e devolve `{ ok: true, rehash }`. rehash=true quando pepper não é o
|
|
132
|
+
* corrente (re-hash com o corrente transparente).
|
|
133
|
+
* 2. Se nenhum pepper funcionou com native, tenta o `legacyVerifier` com
|
|
134
|
+
* `applyCurrentPepper(plain)` (e também sem pepper, para import de sistemas
|
|
135
|
+
* legados antes de pepperar).
|
|
136
|
+
* `true` → `{ ok: true, rehash: true }`;
|
|
137
|
+
* `false`/`null` → `{ ok: false, rehash: false }`.
|
|
138
|
+
*
|
|
139
|
+
* `nativeVerify`/`needsRehash` são injetados pelo store (vêm do model Lucid),
|
|
140
|
+
* mantendo este manager desacoplado do Lucid.
|
|
141
|
+
*/
|
|
142
|
+
async verify(hashedPassword, plainPassword, hooks) {
|
|
143
|
+
const peppers = resolvePeppers(this.pepper);
|
|
144
|
+
const currentPepper = Array.isArray(this.pepper) ? this.pepper[0] : (this.pepper ?? '');
|
|
145
|
+
for (let i = 0; i < peppers.length; i++) {
|
|
146
|
+
const p = peppers[i];
|
|
147
|
+
const peppered = p ? applyPepper(plainPassword, p) : plainPassword;
|
|
148
|
+
let nativeOk = false;
|
|
149
|
+
try {
|
|
150
|
+
nativeOk = await hooks.nativeVerify(hashedPassword, peppered);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
nativeOk = false;
|
|
154
|
+
}
|
|
155
|
+
if (nativeOk) {
|
|
156
|
+
// Se este não é o pepper corrente → re-hash obrigatório com o corrente.
|
|
157
|
+
const isCurrentPepper = (p === currentPepper) || (!p && !this.pepper);
|
|
158
|
+
let rehash = isCurrentPepper ? false : true;
|
|
159
|
+
if (!rehash) {
|
|
160
|
+
try {
|
|
161
|
+
rehash = hooks.needsRehash(hashedPassword);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
rehash = false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { ok: true, rehash };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Nenhum pepper funcionou com nativeVerify → tenta legacyVerifier.
|
|
171
|
+
if (this.legacyVerifier) {
|
|
172
|
+
// Tenta com o pepper corrente E sem pepper (para hashes de sistemas legados
|
|
173
|
+
// que ainda não tinham pepper).
|
|
174
|
+
const tryCandidates = this.pepper
|
|
175
|
+
? [applyCurrentPepper(plainPassword, this.pepper), plainPassword]
|
|
176
|
+
: [plainPassword];
|
|
177
|
+
for (const candidate of tryCandidates) {
|
|
178
|
+
let legacy = null;
|
|
179
|
+
try {
|
|
180
|
+
legacy = await this.legacyVerifier(hashedPassword, candidate);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
legacy = null;
|
|
184
|
+
}
|
|
185
|
+
if (legacy === true)
|
|
186
|
+
return { ok: true, rehash: true };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { ok: false, rehash: false };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Política de senha (shapes + checagens puras). Testável em isolamento.
|
|
3
|
+
* A política ativa é gerenciada via runtime setting `password_policy` em
|
|
4
|
+
* `auth_settings` (admin console / Admin API). Os defaults da lib ficam aqui.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Regras de complexidade de senha (shape interno — alinhado com o shape
|
|
8
|
+
* da runtime setting `password_policy` em `auth_settings`).
|
|
9
|
+
*/
|
|
10
|
+
export interface PasswordPolicyInput {
|
|
11
|
+
/** Comprimento mínimo. Default: 8. */
|
|
12
|
+
minLength?: number;
|
|
13
|
+
/** Exige ao menos uma letra maiúscula. Default: false. */
|
|
14
|
+
requireUppercase?: boolean;
|
|
15
|
+
/** Exige ao menos uma letra minúscula. Default: false. */
|
|
16
|
+
requireLowercase?: boolean;
|
|
17
|
+
/** Exige ao menos um dígito. Default: false. */
|
|
18
|
+
requireNumbers?: boolean;
|
|
19
|
+
/** Exige ao menos um símbolo (não alfanumérico). Default: false. */
|
|
20
|
+
requireSymbols?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Política resolvida (todos os campos presentes). */
|
|
23
|
+
export interface ResolvedPasswordPolicy {
|
|
24
|
+
minLength: number;
|
|
25
|
+
requireUppercase: boolean;
|
|
26
|
+
requireLowercase: boolean;
|
|
27
|
+
requireNumbers: boolean;
|
|
28
|
+
requireSymbols: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checagem contra vazamentos (HaveIBeenPwned Range API, k-anonymity). Quando
|
|
32
|
+
* `true`, usa os defaults; um objeto permite ajustar o timeout. FAIL-SAFE: erro
|
|
33
|
+
* de rede/timeout/5xx NÃO bloqueia a senha (loga warning e permite).
|
|
34
|
+
*/
|
|
35
|
+
export type CheckPwnedInput = boolean | {
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
};
|
|
38
|
+
/** Config de senha resolvida, carregada pelo store/controllers. */
|
|
39
|
+
export interface ResolvedPasswordConfig {
|
|
40
|
+
policy: ResolvedPasswordPolicy;
|
|
41
|
+
checkPwned: {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
timeoutMs: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export declare const DEFAULT_PWNED_TIMEOUT_MS = 2000;
|
|
47
|
+
/**
|
|
48
|
+
* Chave i18n da regra de política violada (estável — os catálogos en/pt-BR
|
|
49
|
+
* carregam todas). `password.pwned` é a mensagem do vazamento.
|
|
50
|
+
*/
|
|
51
|
+
export type PasswordPolicyViolation = 'password.policy.min_length' | 'password.policy.uppercase' | 'password.policy.lowercase' | 'password.policy.numbers' | 'password.policy.symbols';
|
|
52
|
+
export declare function resolvePasswordPolicy(input?: PasswordPolicyInput): ResolvedPasswordPolicy;
|
|
53
|
+
export declare function resolveCheckPwned(input?: CheckPwnedInput): {
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
timeoutMs: number;
|
|
56
|
+
};
|
|
57
|
+
export declare function resolvePasswordConfig(input?: {
|
|
58
|
+
policy?: PasswordPolicyInput;
|
|
59
|
+
checkPwned?: CheckPwnedInput;
|
|
60
|
+
}): ResolvedPasswordConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Aplica a política a uma senha em claro. Devolve a PRIMEIRA violação (chave
|
|
63
|
+
* i18n) ou `null` se a senha passa. Ordem estável: comprimento → maiúscula →
|
|
64
|
+
* minúscula → dígito → símbolo.
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkPasswordPolicy(password: string, policy: ResolvedPasswordPolicy): PasswordPolicyViolation | null;
|
|
67
|
+
/**
|
|
68
|
+
* Parâmetros para interpolar a mensagem i18n da violação (ex.: `{min}` no
|
|
69
|
+
* comprimento mínimo). Devolve `undefined` para regras sem parâmetro.
|
|
70
|
+
*/
|
|
71
|
+
export declare function policyViolationParams(violation: PasswordPolicyViolation, policy: ResolvedPasswordPolicy): Record<string, string | number> | undefined;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Política de senha (shapes + checagens puras). Testável em isolamento.
|
|
3
|
+
* A política ativa é gerenciada via runtime setting `password_policy` em
|
|
4
|
+
* `auth_settings` (admin console / Admin API). Os defaults da lib ficam aqui.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_PWNED_TIMEOUT_MS = 2000;
|
|
7
|
+
export function resolvePasswordPolicy(input) {
|
|
8
|
+
return {
|
|
9
|
+
minLength: input?.minLength ?? 8,
|
|
10
|
+
requireUppercase: input?.requireUppercase ?? false,
|
|
11
|
+
requireLowercase: input?.requireLowercase ?? false,
|
|
12
|
+
requireNumbers: input?.requireNumbers ?? false,
|
|
13
|
+
requireSymbols: input?.requireSymbols ?? false,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function resolveCheckPwned(input) {
|
|
17
|
+
if (!input)
|
|
18
|
+
return { enabled: false, timeoutMs: DEFAULT_PWNED_TIMEOUT_MS };
|
|
19
|
+
if (input === true)
|
|
20
|
+
return { enabled: true, timeoutMs: DEFAULT_PWNED_TIMEOUT_MS };
|
|
21
|
+
return { enabled: true, timeoutMs: input.timeoutMs ?? DEFAULT_PWNED_TIMEOUT_MS };
|
|
22
|
+
}
|
|
23
|
+
export function resolvePasswordConfig(input) {
|
|
24
|
+
return {
|
|
25
|
+
policy: resolvePasswordPolicy(input?.policy),
|
|
26
|
+
checkPwned: resolveCheckPwned(input?.checkPwned),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Aplica a política a uma senha em claro. Devolve a PRIMEIRA violação (chave
|
|
31
|
+
* i18n) ou `null` se a senha passa. Ordem estável: comprimento → maiúscula →
|
|
32
|
+
* minúscula → dígito → símbolo.
|
|
33
|
+
*/
|
|
34
|
+
export function checkPasswordPolicy(password, policy) {
|
|
35
|
+
if (password.length < policy.minLength)
|
|
36
|
+
return 'password.policy.min_length';
|
|
37
|
+
if (policy.requireUppercase && !/[A-Z]/.test(password))
|
|
38
|
+
return 'password.policy.uppercase';
|
|
39
|
+
if (policy.requireLowercase && !/[a-z]/.test(password))
|
|
40
|
+
return 'password.policy.lowercase';
|
|
41
|
+
if (policy.requireNumbers && !/[0-9]/.test(password))
|
|
42
|
+
return 'password.policy.numbers';
|
|
43
|
+
if (policy.requireSymbols && !/[^A-Za-z0-9]/.test(password))
|
|
44
|
+
return 'password.policy.symbols';
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parâmetros para interpolar a mensagem i18n da violação (ex.: `{min}` no
|
|
49
|
+
* comprimento mínimo). Devolve `undefined` para regras sem parâmetro.
|
|
50
|
+
*/
|
|
51
|
+
export function policyViolationParams(violation, policy) {
|
|
52
|
+
if (violation === 'password.policy.min_length')
|
|
53
|
+
return { min: policy.minLength };
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checagem de senha vazada via HaveIBeenPwned Pwned Passwords (Range API), com
|
|
3
|
+
* k-anonymity: NUNCA enviamos a senha nem o hash completo — só os 5 primeiros
|
|
4
|
+
* hex chars do SHA-1, e procuramos o sufixo localmente na resposta.
|
|
5
|
+
*
|
|
6
|
+
* FAIL-SAFE por design: qualquer erro (rede, timeout, 5xx, parsing) resulta em
|
|
7
|
+
* "não vazada" (permite a senha) e loga um warning. A indisponibilidade do
|
|
8
|
+
* serviço externo NUNCA deve bloquear o usuário de definir uma senha.
|
|
9
|
+
*/
|
|
10
|
+
/** Logger mínimo (subconjunto do logger do AdonisJS). */
|
|
11
|
+
export interface PwnedLogger {
|
|
12
|
+
warn(obj: unknown, msg?: string): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Cliente HTTP injetável (fetch nativo por default). Existe para testes: permite
|
|
16
|
+
* simular hit/miss/erro/timeout SEM rede. A assinatura espelha o `fetch` global.
|
|
17
|
+
*/
|
|
18
|
+
export type FetchLike = (url: string, init?: {
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
}) => Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
status: number;
|
|
24
|
+
text(): Promise<string>;
|
|
25
|
+
}>;
|
|
26
|
+
/** Injeta um fetch fake para testes. `undefined` restaura o fetch nativo. */
|
|
27
|
+
export declare function __setFetchForTests(impl: FetchLike | undefined): void;
|
|
28
|
+
/**
|
|
29
|
+
* Retorna `true` se a senha aparece na base do HIBP, `false` caso contrário OU
|
|
30
|
+
* em qualquer falha (fail-safe). `timeoutMs` aborta a request.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isPasswordPwned(password: string, options?: {
|
|
33
|
+
timeoutMs: number;
|
|
34
|
+
logger?: PwnedLogger;
|
|
35
|
+
fetchImpl?: FetchLike;
|
|
36
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
let fetchImpl;
|
|
3
|
+
/** Injeta um fetch fake para testes. `undefined` restaura o fetch nativo. */
|
|
4
|
+
export function __setFetchForTests(impl) {
|
|
5
|
+
fetchImpl = impl;
|
|
6
|
+
}
|
|
7
|
+
function getFetch() {
|
|
8
|
+
if (fetchImpl)
|
|
9
|
+
return fetchImpl;
|
|
10
|
+
return globalThis.fetch;
|
|
11
|
+
}
|
|
12
|
+
const HIBP_RANGE_URL = 'https://api.pwnedpasswords.com/range/';
|
|
13
|
+
/**
|
|
14
|
+
* Retorna `true` se a senha aparece na base do HIBP, `false` caso contrário OU
|
|
15
|
+
* em qualquer falha (fail-safe). `timeoutMs` aborta a request.
|
|
16
|
+
*/
|
|
17
|
+
export async function isPasswordPwned(password, options = {
|
|
18
|
+
timeoutMs: 2000,
|
|
19
|
+
}) {
|
|
20
|
+
const sha1 = createHash('sha1').update(password, 'utf8').digest('hex').toUpperCase();
|
|
21
|
+
const prefix = sha1.slice(0, 5);
|
|
22
|
+
const suffix = sha1.slice(5);
|
|
23
|
+
const doFetch = options.fetchImpl ?? getFetch();
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
26
|
+
try {
|
|
27
|
+
const res = await doFetch(`${HIBP_RANGE_URL}${prefix}`, {
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
// Add-Padding obscurece o tamanho da resposta (k-anonymity reforçado).
|
|
30
|
+
headers: { 'Add-Padding': 'true' },
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
options.logger?.warn({ status: res.status }, 'authkit: HIBP range API returned a non-OK status — skipping pwned check (fail-safe).');
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const body = await res.text();
|
|
37
|
+
// Cada linha: "<SUFIXO>:<count>". Linhas de padding têm count 0 — ignoradas.
|
|
38
|
+
for (const line of body.split('\n')) {
|
|
39
|
+
const [candidate, countStr] = line.trim().split(':');
|
|
40
|
+
if (candidate === suffix && Number(countStr) > 0)
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
options.logger?.warn({ err: error }, 'authkit: HIBP range API request failed (network/timeout) — skipping pwned check (fail-safe).');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PatStore } from './pat_store.js';
|
|
2
|
+
/**
|
|
3
|
+
* Implementação default do {@link PatStore} sobre um model Lucid composto de
|
|
4
|
+
* `withPersonalAccessToken()`. A coluna DB `user_id` é mapeada de `accountId`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function lucidPatStore(Model: any): PatStore;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import { generatePatToken, hashPatToken } from './pat_tokens.js';
|
|
3
|
+
/**
|
|
4
|
+
* Implementação default do {@link PatStore} sobre um model Lucid composto de
|
|
5
|
+
* `withPersonalAccessToken()`. A coluna DB `user_id` é mapeada de `accountId`.
|
|
6
|
+
*/
|
|
7
|
+
export function lucidPatStore(Model) {
|
|
8
|
+
const toRecord = (row) => ({
|
|
9
|
+
id: row.id,
|
|
10
|
+
name: row.name,
|
|
11
|
+
scopes: row.scopes ?? [],
|
|
12
|
+
audience: row.audience ?? null,
|
|
13
|
+
createdAt: row.createdAt ? row.createdAt.toISO() : '',
|
|
14
|
+
lastUsedAt: row.lastUsedAt ? row.lastUsedAt.toISO() : null,
|
|
15
|
+
expiresAt: row.expiresAt ? row.expiresAt.toISO() : null,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
async issue(input) {
|
|
19
|
+
const token = generatePatToken();
|
|
20
|
+
const row = await Model.create({
|
|
21
|
+
userId: input.accountId,
|
|
22
|
+
name: input.name,
|
|
23
|
+
tokenHash: hashPatToken(token),
|
|
24
|
+
scopes: input.scopes ?? [],
|
|
25
|
+
audience: input.audience ?? null,
|
|
26
|
+
expiresAt: input.expiresInDays
|
|
27
|
+
? DateTime.now().plus({ days: input.expiresInDays })
|
|
28
|
+
: null,
|
|
29
|
+
});
|
|
30
|
+
return { token, pat: toRecord(row) };
|
|
31
|
+
},
|
|
32
|
+
async listForAccount(accountId) {
|
|
33
|
+
const rows = await Model.query()
|
|
34
|
+
.where('user_id', accountId)
|
|
35
|
+
.orderBy('created_at', 'desc');
|
|
36
|
+
return rows.map(toRecord);
|
|
37
|
+
},
|
|
38
|
+
async revoke(accountId, id) {
|
|
39
|
+
const row = await Model.query().where('id', id).where('user_id', accountId).first();
|
|
40
|
+
if (!row)
|
|
41
|
+
return false;
|
|
42
|
+
await row.delete();
|
|
43
|
+
return true;
|
|
44
|
+
},
|
|
45
|
+
async findActiveByToken(token) {
|
|
46
|
+
const hash = hashPatToken(token);
|
|
47
|
+
const row = await Model.query().where('token_hash', hash).first();
|
|
48
|
+
if (!row)
|
|
49
|
+
return null;
|
|
50
|
+
if (row.expiresAt && row.expiresAt < DateTime.now())
|
|
51
|
+
return null;
|
|
52
|
+
row.lastUsedAt = DateTime.now();
|
|
53
|
+
await row.save();
|
|
54
|
+
return {
|
|
55
|
+
accountId: row.userId,
|
|
56
|
+
scopes: row.scopes ?? [],
|
|
57
|
+
audience: row.audience ?? null,
|
|
58
|
+
exp: row.expiresAt ? Math.floor(row.expiresAt.toSeconds()) : null,
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** DTO seguro do PAT — sem o hash do token. */
|
|
2
|
+
export interface PatRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
scopes: string[];
|
|
6
|
+
audience: string | null;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
lastUsedAt: string | null;
|
|
9
|
+
expiresAt: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface IssuePatInput {
|
|
12
|
+
accountId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
scopes?: string[];
|
|
15
|
+
audience?: string | null;
|
|
16
|
+
expiresInDays?: number | null;
|
|
17
|
+
}
|
|
18
|
+
export interface PatStore {
|
|
19
|
+
issue(input: IssuePatInput): Promise<{
|
|
20
|
+
token: string;
|
|
21
|
+
pat: PatRecord;
|
|
22
|
+
}>;
|
|
23
|
+
listForAccount(accountId: string): Promise<PatRecord[]>;
|
|
24
|
+
revoke(accountId: string, id: string): Promise<boolean>;
|
|
25
|
+
findActiveByToken(token: string): Promise<{
|
|
26
|
+
accountId: string;
|
|
27
|
+
scopes: string[];
|
|
28
|
+
audience: string | null;
|
|
29
|
+
exp: number | null;
|
|
30
|
+
} | null>;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Gera um Personal Access Token opaco no formato `pat_<base64url>`. */
|
|
2
|
+
export declare function generatePatToken(): string;
|
|
3
|
+
/** SHA-256 (hex) do token — é o que se persiste; o token cru nunca é guardado. */
|
|
4
|
+
export declare function hashPatToken(token: string): string;
|