@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,36 @@
|
|
|
1
|
+
import { ACCOUNT_SESSION_KEY } from './middleware/account_auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Helpers públicos para integrar a sessão do console do AuthKit com
|
|
4
|
+
* qualquer coisa fora do pacote (ex.: proteger o dashboard do
|
|
5
|
+
* adonis-telescope, rotas administrativas próprias, etc).
|
|
6
|
+
*
|
|
7
|
+
* Use estes helpers em vez de ler `ctx.session` com a key interna —
|
|
8
|
+
* eles são contrato público e continuam funcionando se o mecanismo de
|
|
9
|
+
* sessão mudar.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Retorna o id da conta logada no console (ou `null` quando não há
|
|
13
|
+
* sessão).
|
|
14
|
+
*/
|
|
15
|
+
export function getAccountId(ctx) {
|
|
16
|
+
const accountId = ctx.session?.get(ACCOUNT_SESSION_KEY);
|
|
17
|
+
return accountId ?? null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* `true` quando o request carrega uma sessão de conta do console.
|
|
21
|
+
*/
|
|
22
|
+
export function hasAccountSession(ctx) {
|
|
23
|
+
return getAccountId(ctx) !== null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* URL do login do console, com `return_to` opcional de volta ao destino
|
|
27
|
+
* original após autenticar.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* consoleLoginUrl('/telescope') // => '/account/login?return_to=%2Ftelescope'
|
|
31
|
+
*/
|
|
32
|
+
export function consoleLoginUrl(returnTo) {
|
|
33
|
+
if (!returnTo)
|
|
34
|
+
return '/account/login';
|
|
35
|
+
return `/account/login?return_to=${encodeURIComponent(returnTo)}`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import '../augmentations.js';
|
|
2
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
+
/**
|
|
4
|
+
* Self-service de consentimento ("apps com acesso") no console de conta. Lista os
|
|
5
|
+
* Grants da própria conta agrupados por client (resolvendo o nome do client da
|
|
6
|
+
* config estática ou do payload do adapter) e permite revogar o acesso de um
|
|
7
|
+
* client (destrói os grants + AT/RT daquele client). Degrada graciosamente quando
|
|
8
|
+
* o adapter OIDC não enumera (`list`), espelhando o console admin.
|
|
9
|
+
*/
|
|
10
|
+
export default class AccountAppsController {
|
|
11
|
+
/** GET /account/apps — lista os apps com acesso (grants) da conta logada. */
|
|
12
|
+
index(ctx: HttpContext): Promise<any>;
|
|
13
|
+
/** POST /account/apps/:clientId/revoke — revoga o acesso de um client. */
|
|
14
|
+
revoke(ctx: HttpContext): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import '../augmentations.js';
|
|
2
|
+
import { ACCOUNT_SESSION_KEY } from '../middleware/account_auth.js';
|
|
3
|
+
import { AdminSessionsService } from '../admin_sessions_service.js';
|
|
4
|
+
/**
|
|
5
|
+
* Self-service de consentimento ("apps com acesso") no console de conta. Lista os
|
|
6
|
+
* Grants da própria conta agrupados por client (resolvendo o nome do client da
|
|
7
|
+
* config estática ou do payload do adapter) e permite revogar o acesso de um
|
|
8
|
+
* client (destrói os grants + AT/RT daquele client). Degrada graciosamente quando
|
|
9
|
+
* o adapter OIDC não enumera (`list`), espelhando o console admin.
|
|
10
|
+
*/
|
|
11
|
+
export default class AccountAppsController {
|
|
12
|
+
/** GET /account/apps — lista os apps com acesso (grants) da conta logada. */
|
|
13
|
+
async index(ctx) {
|
|
14
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
15
|
+
const cfg = service.config;
|
|
16
|
+
const render = cfg.render;
|
|
17
|
+
const accountId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
18
|
+
const sessions = new AdminSessionsService(service);
|
|
19
|
+
const supported = sessions.canList;
|
|
20
|
+
const grantList = supported ? await sessions.listGrants(accountId) : [];
|
|
21
|
+
// Resolve o nome amigável do client: clientId é o fallback (config estática não
|
|
22
|
+
// carrega um display name).
|
|
23
|
+
const nameOf = (clientId) => clientId ?? '';
|
|
24
|
+
const revoked = ctx.session.flashMessages.get('appRevoked');
|
|
25
|
+
return render(ctx, 'account/apps', {
|
|
26
|
+
csrfToken: ctx.request.csrfToken,
|
|
27
|
+
supported,
|
|
28
|
+
revoked: revoked ?? null,
|
|
29
|
+
apps: grantList
|
|
30
|
+
.filter((g) => !!g.clientId)
|
|
31
|
+
.map((g) => ({
|
|
32
|
+
clientId: g.clientId,
|
|
33
|
+
name: nameOf(g.clientId),
|
|
34
|
+
accessTokens: g.accessTokens,
|
|
35
|
+
refreshTokens: g.refreshTokens,
|
|
36
|
+
})),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** POST /account/apps/:clientId/revoke — revoga o acesso de um client. */
|
|
40
|
+
async revoke(ctx) {
|
|
41
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
42
|
+
const cfg = service.config;
|
|
43
|
+
const accountId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
44
|
+
const clientId = ctx.request.param('clientId');
|
|
45
|
+
const sessions = new AdminSessionsService(service);
|
|
46
|
+
const result = await sessions.revokeClientGrants(accountId, clientId);
|
|
47
|
+
await cfg.audit?.record({
|
|
48
|
+
type: 'grant.revoked_by_user',
|
|
49
|
+
accountId,
|
|
50
|
+
clientId,
|
|
51
|
+
ip: ctx.request.ip?.() ?? null,
|
|
52
|
+
metadata: {
|
|
53
|
+
grants: result.grants,
|
|
54
|
+
accessTokens: result.accessTokens,
|
|
55
|
+
refreshTokens: result.refreshTokens,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
ctx.session.flash('appRevoked', cfg.messages['account.apps.revoked'] ?? 'account.apps.revoked');
|
|
59
|
+
return ctx.response.redirect('/account/apps');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudo mode — tela de confirmação de identidade (/account/confirm).
|
|
3
|
+
*
|
|
4
|
+
* GET /account/confirm → exibe o formulário de senha (e opção de passkey se disponível).
|
|
5
|
+
* POST /account/confirm → verifica a senha e, se correta, marca o sudo na sessão.
|
|
6
|
+
* POST /account/confirm/passkey/options → gera as opções de autenticação.
|
|
7
|
+
* POST /account/confirm/passkey → verifica a resposta da passkey e marca o sudo.
|
|
8
|
+
*
|
|
9
|
+
* A tela está atrás do `accountGuard` (requer sessão de conta ativa).
|
|
10
|
+
* Após confirmação, redireciona para `return_to` (validado) ou para `/account/tokens`.
|
|
11
|
+
*/
|
|
12
|
+
import '../augmentations.js';
|
|
13
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
14
|
+
export default class AccountConfirmController {
|
|
15
|
+
show(ctx: HttpContext): Promise<any>;
|
|
16
|
+
confirm(ctx: HttpContext): Promise<void>;
|
|
17
|
+
passkeyOptions(ctx: HttpContext): Promise<any>;
|
|
18
|
+
passkeyConfirm(ctx: HttpContext): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Verifica se a conta é "passwordless" (sem hash de senha definido).
|
|
21
|
+
* Fail-safe: retorna `false` quando não é possível determinar.
|
|
22
|
+
*/
|
|
23
|
+
private isPasswordless;
|
|
24
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudo mode — tela de confirmação de identidade (/account/confirm).
|
|
3
|
+
*
|
|
4
|
+
* GET /account/confirm → exibe o formulário de senha (e opção de passkey se disponível).
|
|
5
|
+
* POST /account/confirm → verifica a senha e, se correta, marca o sudo na sessão.
|
|
6
|
+
* POST /account/confirm/passkey/options → gera as opções de autenticação.
|
|
7
|
+
* POST /account/confirm/passkey → verifica a resposta da passkey e marca o sudo.
|
|
8
|
+
*
|
|
9
|
+
* A tela está atrás do `accountGuard` (requer sessão de conta ativa).
|
|
10
|
+
* Após confirmação, redireciona para `return_to` (validado) ou para `/account/tokens`.
|
|
11
|
+
*/
|
|
12
|
+
import '../augmentations.js';
|
|
13
|
+
import { ACCOUNT_SESSION_KEY } from '../middleware/account_auth.js';
|
|
14
|
+
import { translate } from '../i18n.js';
|
|
15
|
+
import { supportsPasskeys } from '../../accounts/account_store.js';
|
|
16
|
+
import { markSudo } from '../sudo_mode.js';
|
|
17
|
+
import { validateReturnTo } from './account_session_controller.js';
|
|
18
|
+
import { accountHome } from '../account_home.js';
|
|
19
|
+
/** Chave de sessão para o challenge de passkey no confirm. */
|
|
20
|
+
const CONFIRM_PASSKEY_CHALLENGE_KEY = 'authkit_confirm_passkey_challenge';
|
|
21
|
+
export default class AccountConfirmController {
|
|
22
|
+
async show(ctx) {
|
|
23
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
24
|
+
const cfg = service.config;
|
|
25
|
+
const render = cfg.render;
|
|
26
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
27
|
+
const passkeyAvailable = supportsPasskeys(cfg.accountStore)
|
|
28
|
+
? (await cfg.accountStore.listPasskeys(userId)).length > 0
|
|
29
|
+
: false;
|
|
30
|
+
// Conta passwordless: sem hash de senha (campo `password` vazio/null no model).
|
|
31
|
+
// Verificamos indiretamente: verifyCredentials com senha fictícia vai falhar,
|
|
32
|
+
// mas precisamos saber se a conta TEM senha. Abordagem: a conta é "passwordless"
|
|
33
|
+
// se o store suporta passkeys, a conta tem pelo menos uma passkey E não tem
|
|
34
|
+
// hash de senha — mas sem expor o hash, usamos uma flag do store se disponível.
|
|
35
|
+
// Fallback conservador: assumimos que a conta tem senha se não soubermos.
|
|
36
|
+
const passwordless = await this.isPasswordless(cfg, userId);
|
|
37
|
+
const rawReturnTo = ctx.request.qs?.()?.return_to ?? ctx.request.input?.('return_to');
|
|
38
|
+
const returnTo = validateReturnTo(rawReturnTo);
|
|
39
|
+
return render(ctx, 'account/confirm', {
|
|
40
|
+
csrfToken: ctx.request.csrfToken,
|
|
41
|
+
returnTo,
|
|
42
|
+
error: ctx.session.flashMessages.get('confirmError') ?? null,
|
|
43
|
+
passwordless,
|
|
44
|
+
passkeyAvailable,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async confirm(ctx) {
|
|
48
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
49
|
+
const cfg = service.config;
|
|
50
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
51
|
+
const account = await cfg.accountStore.findById(userId);
|
|
52
|
+
const rawReturnTo = ctx.request.input?.('return_to');
|
|
53
|
+
const returnTo = validateReturnTo(rawReturnTo);
|
|
54
|
+
const { password } = ctx.request.only(['password']);
|
|
55
|
+
if (!password || !account) {
|
|
56
|
+
ctx.session.flash('confirmError', translate(cfg.messages, 'account.confirm.error'));
|
|
57
|
+
return ctx.response.redirect(`/account/confirm${returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : ''}`);
|
|
58
|
+
}
|
|
59
|
+
const verified = await cfg.accountStore.verifyCredentials(account.email, password);
|
|
60
|
+
if (!verified) {
|
|
61
|
+
ctx.session.flash('confirmError', translate(cfg.messages, 'account.confirm.error'));
|
|
62
|
+
return ctx.response.redirect(`/account/confirm${returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : ''}`);
|
|
63
|
+
}
|
|
64
|
+
// Confirmado: marca o sudo na sessão.
|
|
65
|
+
markSudo(ctx);
|
|
66
|
+
await cfg.audit?.record({
|
|
67
|
+
type: 'sudo.confirmed',
|
|
68
|
+
accountId: userId,
|
|
69
|
+
ip: ctx.request.ip?.() ?? null,
|
|
70
|
+
metadata: { method: 'password' },
|
|
71
|
+
});
|
|
72
|
+
return ctx.response.redirect(returnTo ?? accountHome(cfg));
|
|
73
|
+
}
|
|
74
|
+
async passkeyOptions(ctx) {
|
|
75
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
76
|
+
const cfg = service.config;
|
|
77
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
78
|
+
const generated = await cfg.accountStore.generatePasskeyAuthenticationOptions?.(userId);
|
|
79
|
+
if (!generated) {
|
|
80
|
+
return ctx.response.notFound({
|
|
81
|
+
message: translate(cfg.messages, 'errors.no_passkey_registered'),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
ctx.session.put(CONFIRM_PASSKEY_CHALLENGE_KEY, generated.challenge);
|
|
85
|
+
return generated.options;
|
|
86
|
+
}
|
|
87
|
+
async passkeyConfirm(ctx) {
|
|
88
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
89
|
+
const cfg = service.config;
|
|
90
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
91
|
+
const challenge = ctx.session.get(CONFIRM_PASSKEY_CHALLENGE_KEY);
|
|
92
|
+
const rawReturnTo = ctx.request.input?.('return_to');
|
|
93
|
+
const returnTo = validateReturnTo(rawReturnTo);
|
|
94
|
+
if (!challenge) {
|
|
95
|
+
ctx.session.flash('confirmError', translate(cfg.messages, 'account.confirm.passkey_error'));
|
|
96
|
+
return ctx.response.redirect(`/account/confirm${returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : ''}`);
|
|
97
|
+
}
|
|
98
|
+
const raw = ctx.request.input('response');
|
|
99
|
+
let parsed = null;
|
|
100
|
+
try {
|
|
101
|
+
parsed = raw ? JSON.parse(raw) : null;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
parsed = null;
|
|
105
|
+
}
|
|
106
|
+
const ok = parsed
|
|
107
|
+
? ((await cfg.accountStore.verifyPasskeyAuthentication?.(userId, parsed, challenge)) ?? false)
|
|
108
|
+
: false;
|
|
109
|
+
ctx.session.forget(CONFIRM_PASSKEY_CHALLENGE_KEY);
|
|
110
|
+
if (!ok) {
|
|
111
|
+
ctx.session.flash('confirmError', translate(cfg.messages, 'account.confirm.passkey_error'));
|
|
112
|
+
return ctx.response.redirect(`/account/confirm${returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : ''}`);
|
|
113
|
+
}
|
|
114
|
+
// Passkey confirmada: marca o sudo.
|
|
115
|
+
markSudo(ctx);
|
|
116
|
+
await cfg.audit?.record({
|
|
117
|
+
type: 'sudo.confirmed',
|
|
118
|
+
accountId: userId,
|
|
119
|
+
ip: ctx.request.ip?.() ?? null,
|
|
120
|
+
metadata: { method: 'passkey' },
|
|
121
|
+
});
|
|
122
|
+
return ctx.response.redirect(returnTo ?? accountHome(cfg));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Verifica se a conta é "passwordless" (sem hash de senha definido).
|
|
126
|
+
* Fail-safe: retorna `false` quando não é possível determinar.
|
|
127
|
+
*/
|
|
128
|
+
async isPasswordless(cfg, accountId) {
|
|
129
|
+
try {
|
|
130
|
+
// Se o store expõe __getRawRow, verificamos se o hash de senha está vazio.
|
|
131
|
+
const row = await cfg.accountStore.__getRawRow?.(accountId);
|
|
132
|
+
if (row) {
|
|
133
|
+
const pw = row.password;
|
|
134
|
+
// Hash vazio ou nulo → passwordless.
|
|
135
|
+
if (!pw || pw === '')
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import '../augmentations.js';
|
|
2
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
+
/**
|
|
4
|
+
* Console de MFA da conta (atrás do account_auth middleware). Enrollment TOTP
|
|
5
|
+
* com QR, confirmação com código, exibição única dos recovery codes e disable.
|
|
6
|
+
*/
|
|
7
|
+
export default class AccountMfaController {
|
|
8
|
+
/** GET /account/mfa — estado atual; oferece enroll se desligado. */
|
|
9
|
+
index(ctx: HttpContext): Promise<any>;
|
|
10
|
+
/**
|
|
11
|
+
* POST /account/mfa/passkeys/options — gera as opções de registro de passkey
|
|
12
|
+
* (JSON), guarda o challenge na sessão e devolve as opções para o browser.
|
|
13
|
+
*/
|
|
14
|
+
passkeyRegisterOptions(ctx: HttpContext): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* POST /account/mfa/passkeys/verify — verifica a resposta de registro do browser
|
|
17
|
+
* contra o challenge guardado; em caso de sucesso persiste a credencial e habilita MFA.
|
|
18
|
+
*/
|
|
19
|
+
passkeyRegisterVerify(ctx: HttpContext): Promise<unknown>;
|
|
20
|
+
/** POST /account/mfa/passkeys/:id/remove — remove uma passkey da conta. */
|
|
21
|
+
passkeyRemove(ctx: HttpContext): Promise<unknown>;
|
|
22
|
+
/** POST /account/mfa/enroll — gera segredo pendente + QR e mostra a confirmação. */
|
|
23
|
+
enroll(ctx: HttpContext): Promise<any>;
|
|
24
|
+
/** POST /account/mfa/confirm — confirma o código; sucesso = ativa e mostra recovery codes. */
|
|
25
|
+
confirm(ctx: HttpContext): Promise<any>;
|
|
26
|
+
/** POST /account/mfa/disable — desliga o MFA. */
|
|
27
|
+
disable(ctx: HttpContext): Promise<unknown>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import '../augmentations.js';
|
|
2
|
+
import QRCode from 'qrcode';
|
|
3
|
+
import { ACCOUNT_SESSION_KEY } from '../middleware/account_auth.js';
|
|
4
|
+
import { translate } from '../i18n.js';
|
|
5
|
+
import { supportsPasskeys } from '../../accounts/account_store.js';
|
|
6
|
+
import { dispatchSecurityNotice } from '../security_notice_service.js';
|
|
7
|
+
import { resolveRuntimeSettings } from '../runtime_settings.js';
|
|
8
|
+
import { requireSudo } from '../sudo_mode.js';
|
|
9
|
+
/** Desafio WebAuthn pendente (registro) guardado na sessão entre begin/finish. */
|
|
10
|
+
const PASSKEY_REG_CHALLENGE_KEY = 'authkit_passkey_reg_challenge';
|
|
11
|
+
/**
|
|
12
|
+
* Console de MFA da conta (atrás do account_auth middleware). Enrollment TOTP
|
|
13
|
+
* com QR, confirmação com código, exibição única dos recovery codes e disable.
|
|
14
|
+
*/
|
|
15
|
+
export default class AccountMfaController {
|
|
16
|
+
/** GET /account/mfa — estado atual; oferece enroll se desligado. */
|
|
17
|
+
async index(ctx) {
|
|
18
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
19
|
+
const cfg = service.config;
|
|
20
|
+
const render = cfg.render;
|
|
21
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
22
|
+
const state = (await cfg.accountStore.getMfaState?.(userId)) ?? { enabled: false };
|
|
23
|
+
const recoveryCodes = ctx.session.flashMessages.get('recoveryCodes');
|
|
24
|
+
// Passkeys disponíveis quando o store as suporta (model de credenciais wired).
|
|
25
|
+
const passkeysSupported = supportsPasskeys(cfg.accountStore);
|
|
26
|
+
const passkeys = passkeysSupported ? await cfg.accountStore.listPasskeys(userId) : [];
|
|
27
|
+
return render(ctx, 'account/mfa', {
|
|
28
|
+
csrfToken: ctx.request.csrfToken,
|
|
29
|
+
enabled: state.enabled,
|
|
30
|
+
recoveryCodes: recoveryCodes ?? null,
|
|
31
|
+
passkeysSupported,
|
|
32
|
+
passkeys,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* POST /account/mfa/passkeys/options — gera as opções de registro de passkey
|
|
37
|
+
* (JSON), guarda o challenge na sessão e devolve as opções para o browser.
|
|
38
|
+
*/
|
|
39
|
+
async passkeyRegisterOptions(ctx) {
|
|
40
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
41
|
+
const cfg = service.config;
|
|
42
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
43
|
+
const generated = await cfg.accountStore.generatePasskeyRegistrationOptions?.(userId);
|
|
44
|
+
if (!generated) {
|
|
45
|
+
return ctx.response.notFound({
|
|
46
|
+
message: translate(cfg.messages, 'errors.passkeys_unavailable'),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
ctx.session.put(PASSKEY_REG_CHALLENGE_KEY, generated.challenge);
|
|
50
|
+
return generated.options;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* POST /account/mfa/passkeys/verify — verifica a resposta de registro do browser
|
|
54
|
+
* contra o challenge guardado; em caso de sucesso persiste a credencial e habilita MFA.
|
|
55
|
+
*/
|
|
56
|
+
async passkeyRegisterVerify(ctx) {
|
|
57
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
58
|
+
const cfg = service.config;
|
|
59
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
60
|
+
// Sudo mode gate.
|
|
61
|
+
const sudoSettingsPkAdd = await resolveRuntimeSettings(ctx);
|
|
62
|
+
const sudoResultPkAdd = await requireSudo(ctx, sudoSettingsPkAdd);
|
|
63
|
+
if (sudoResultPkAdd !== true)
|
|
64
|
+
return sudoResultPkAdd;
|
|
65
|
+
const challenge = ctx.session.get(PASSKEY_REG_CHALLENGE_KEY);
|
|
66
|
+
if (!challenge) {
|
|
67
|
+
return ctx.response.badRequest({
|
|
68
|
+
message: translate(cfg.messages, 'errors.challenge_expired'),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const body = ctx.request.input('response', ctx.request.body());
|
|
72
|
+
const ok = (await cfg.accountStore.verifyPasskeyRegistration?.(userId, body, challenge)) ?? false;
|
|
73
|
+
ctx.session.forget(PASSKEY_REG_CHALLENGE_KEY);
|
|
74
|
+
if (!ok) {
|
|
75
|
+
return ctx.response.badRequest({ message: translate(cfg.messages, 'errors.invalid_code') });
|
|
76
|
+
}
|
|
77
|
+
await cfg.audit?.record({
|
|
78
|
+
type: 'mfa.enabled',
|
|
79
|
+
accountId: userId,
|
|
80
|
+
ip: ctx.request.ip?.() ?? null,
|
|
81
|
+
metadata: { method: 'webauthn' },
|
|
82
|
+
});
|
|
83
|
+
await cfg.audit?.record({
|
|
84
|
+
type: 'passkey.registered',
|
|
85
|
+
accountId: userId,
|
|
86
|
+
ip: ctx.request.ip?.() ?? null,
|
|
87
|
+
});
|
|
88
|
+
// Notificações de segurança: passkey_added + mfa_enabled (best-effort).
|
|
89
|
+
const accountForNotice = await cfg.accountStore.findById(userId);
|
|
90
|
+
if (accountForNotice) {
|
|
91
|
+
const ts = new Date().toISOString();
|
|
92
|
+
const ip = ctx.request.ip?.() ?? null;
|
|
93
|
+
await dispatchSecurityNotice(ctx, { account: { id: userId, email: accountForNotice.email }, kind: 'passkey_added', ip, timestamp: ts }, cfg.mail, cfg.audit);
|
|
94
|
+
await dispatchSecurityNotice(ctx, { account: { id: userId, email: accountForNotice.email }, kind: 'mfa_enabled', ip, timestamp: ts }, cfg.mail, cfg.audit);
|
|
95
|
+
}
|
|
96
|
+
return { ok: true };
|
|
97
|
+
}
|
|
98
|
+
/** POST /account/mfa/passkeys/:id/remove — remove uma passkey da conta. */
|
|
99
|
+
async passkeyRemove(ctx) {
|
|
100
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
101
|
+
const cfg = service.config;
|
|
102
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
103
|
+
// Sudo mode gate.
|
|
104
|
+
const sudoSettingsPkRm = await resolveRuntimeSettings(ctx);
|
|
105
|
+
const sudoResultPkRm = await requireSudo(ctx, sudoSettingsPkRm);
|
|
106
|
+
if (sudoResultPkRm !== true)
|
|
107
|
+
return sudoResultPkRm;
|
|
108
|
+
const credentialId = ctx.request.param('id');
|
|
109
|
+
await cfg.accountStore.removePasskey?.(userId, credentialId);
|
|
110
|
+
await cfg.audit?.record({
|
|
111
|
+
type: 'passkey.removed',
|
|
112
|
+
accountId: userId,
|
|
113
|
+
ip: ctx.request.ip?.() ?? null,
|
|
114
|
+
metadata: { credentialId },
|
|
115
|
+
});
|
|
116
|
+
// Notificação de segurança: passkey_removed (best-effort).
|
|
117
|
+
const accountForNotice = await cfg.accountStore.findById(userId);
|
|
118
|
+
if (accountForNotice) {
|
|
119
|
+
await dispatchSecurityNotice(ctx, { account: { id: userId, email: accountForNotice.email }, kind: 'passkey_removed', ip: ctx.request.ip?.() ?? null, timestamp: new Date().toISOString() }, cfg.mail, cfg.audit);
|
|
120
|
+
}
|
|
121
|
+
return ctx.response.redirect('/account/mfa');
|
|
122
|
+
}
|
|
123
|
+
/** POST /account/mfa/enroll — gera segredo pendente + QR e mostra a confirmação. */
|
|
124
|
+
async enroll(ctx) {
|
|
125
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
126
|
+
const cfg = service.config;
|
|
127
|
+
const render = cfg.render;
|
|
128
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
129
|
+
// Sudo mode gate.
|
|
130
|
+
const sudoSettingsEnroll = await resolveRuntimeSettings(ctx);
|
|
131
|
+
const sudoResultEnroll = await requireSudo(ctx, sudoSettingsEnroll);
|
|
132
|
+
if (sudoResultEnroll !== true)
|
|
133
|
+
return sudoResultEnroll;
|
|
134
|
+
const started = await cfg.accountStore.startTotpEnrollment?.(userId);
|
|
135
|
+
if (!started) {
|
|
136
|
+
return ctx.response.redirect('/account/mfa');
|
|
137
|
+
}
|
|
138
|
+
// QR renderizado server-side como data-URL e passado como prop.
|
|
139
|
+
const qrDataUrl = await QRCode.toDataURL(started.otpauthUri);
|
|
140
|
+
return render(ctx, 'account/mfa', {
|
|
141
|
+
csrfToken: ctx.request.csrfToken,
|
|
142
|
+
enabled: false,
|
|
143
|
+
enrolling: true,
|
|
144
|
+
secret: started.secret,
|
|
145
|
+
qrDataUrl,
|
|
146
|
+
recoveryCodes: null,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/** POST /account/mfa/confirm — confirma o código; sucesso = ativa e mostra recovery codes. */
|
|
150
|
+
async confirm(ctx) {
|
|
151
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
152
|
+
const cfg = service.config;
|
|
153
|
+
const render = cfg.render;
|
|
154
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
155
|
+
const { code } = ctx.request.only(['code']);
|
|
156
|
+
const result = (await cfg.accountStore.confirmTotpEnrollment?.(userId, code)) ?? { ok: false };
|
|
157
|
+
if (!result.ok) {
|
|
158
|
+
// Reenvia o passo de confirmação com erro SEM regenerar o segredo pendente
|
|
159
|
+
// (o usuário já escaneou o QR; um novo segredo invalidaria o app autenticador).
|
|
160
|
+
// Mostra só o campo de código para nova tentativa.
|
|
161
|
+
return render(ctx, 'account/mfa', {
|
|
162
|
+
csrfToken: ctx.request.csrfToken,
|
|
163
|
+
enabled: false,
|
|
164
|
+
enrolling: true,
|
|
165
|
+
secret: null,
|
|
166
|
+
qrDataUrl: null,
|
|
167
|
+
error: translate(cfg.messages, 'errors.invalid_code'),
|
|
168
|
+
recoveryCodes: null,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
await cfg.audit?.record({
|
|
172
|
+
type: 'mfa.enabled',
|
|
173
|
+
accountId: userId,
|
|
174
|
+
ip: ctx.request.ip?.() ?? null,
|
|
175
|
+
});
|
|
176
|
+
// Notificação de segurança: mfa_enabled (best-effort).
|
|
177
|
+
const accountForMfaNotice = await cfg.accountStore.findById(userId);
|
|
178
|
+
if (accountForMfaNotice) {
|
|
179
|
+
await dispatchSecurityNotice(ctx, { account: { id: userId, email: accountForMfaNotice.email }, kind: 'mfa_enabled', ip: ctx.request.ip?.() ?? null, timestamp: new Date().toISOString() }, cfg.mail, cfg.audit);
|
|
180
|
+
}
|
|
181
|
+
// Mostra os recovery codes UMA vez (flash) e volta pro estado "ativado".
|
|
182
|
+
ctx.session.flash('recoveryCodes', result.recoveryCodes ?? []);
|
|
183
|
+
return ctx.response.redirect('/account/mfa');
|
|
184
|
+
}
|
|
185
|
+
/** POST /account/mfa/disable — desliga o MFA. */
|
|
186
|
+
async disable(ctx) {
|
|
187
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
188
|
+
const cfg = service.config;
|
|
189
|
+
const userId = ctx.session.get(ACCOUNT_SESSION_KEY);
|
|
190
|
+
// Sudo mode gate.
|
|
191
|
+
const sudoSettingsDisable = await resolveRuntimeSettings(ctx);
|
|
192
|
+
const sudoResultDisable = await requireSudo(ctx, sudoSettingsDisable);
|
|
193
|
+
if (sudoResultDisable !== true)
|
|
194
|
+
return sudoResultDisable;
|
|
195
|
+
await cfg.accountStore.disableMfa?.(userId);
|
|
196
|
+
await cfg.audit?.record({
|
|
197
|
+
type: 'mfa.disabled',
|
|
198
|
+
accountId: userId,
|
|
199
|
+
ip: ctx.request.ip?.() ?? null,
|
|
200
|
+
});
|
|
201
|
+
// Notificação de segurança: mfa_disabled (best-effort).
|
|
202
|
+
const accountForDisableNotice = await cfg.accountStore.findById(userId);
|
|
203
|
+
if (accountForDisableNotice) {
|
|
204
|
+
await dispatchSecurityNotice(ctx, { account: { id: userId, email: accountForDisableNotice.email }, kind: 'mfa_disabled', ip: ctx.request.ip?.() ?? null, timestamp: new Date().toISOString() }, cfg.mail, cfg.audit);
|
|
205
|
+
}
|
|
206
|
+
return ctx.response.redirect('/account/mfa');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import '../augmentations.js';
|
|
2
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
+
/**
|
|
4
|
+
* Console de conta — Organizations. Server-rendered, padrão dos outros controllers
|
|
5
|
+
* de conta (account_tokens_controller, account_security_controller, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Rotas montadas em register_auth_host quando supportsOrganizations(store) — capability-probed.
|
|
8
|
+
* O guard `accountGuard` (já existente) protege todas as rotas de /account/* abaixo.
|
|
9
|
+
*/
|
|
10
|
+
export default class AccountOrgsController {
|
|
11
|
+
index(ctx: HttpContext): Promise<any>;
|
|
12
|
+
/** POST /account/orgs — criar nova org (requer allowSelfCreate). */
|
|
13
|
+
store(ctx: HttpContext): Promise<void>;
|
|
14
|
+
/** POST /account/orgs/:id/activate — define org ativa (valida membership). */
|
|
15
|
+
activate(ctx: HttpContext): Promise<void>;
|
|
16
|
+
/** POST /account/orgs/deactivate — remove org ativa. */
|
|
17
|
+
deactivate(ctx: HttpContext): Promise<void>;
|
|
18
|
+
/** POST /account/orgs/:id/leave — sai da org (verifica last_owner). */
|
|
19
|
+
leave(ctx: HttpContext): Promise<void>;
|
|
20
|
+
/** POST /account/orgs/:id/invite — convida membro por e-mail. */
|
|
21
|
+
invite(ctx: HttpContext): Promise<void>;
|
|
22
|
+
/** GET /account/orgs/invitations/:token/accept — mostra tela de aceite. */
|
|
23
|
+
showAcceptInvitation(ctx: HttpContext): Promise<any>;
|
|
24
|
+
/** POST /account/orgs/invitations/:token/accept — processa aceite. */
|
|
25
|
+
acceptInvitation(ctx: HttpContext): Promise<void>;
|
|
26
|
+
/** POST /account/orgs/:id/members/:accountId/remove */
|
|
27
|
+
removeMember(ctx: HttpContext): Promise<void>;
|
|
28
|
+
/** POST /account/orgs/:id/invitations/:invId/revoke */
|
|
29
|
+
revokeInvitation(ctx: HttpContext): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* GET /account/orgs/json — lista as orgs do usuário logado com papel + se ativa.
|
|
32
|
+
* Usado pelo hook `useOrganizations()`.
|
|
33
|
+
*/
|
|
34
|
+
listJson(ctx: HttpContext): Promise<void | {
|
|
35
|
+
supported: boolean;
|
|
36
|
+
activeOrgId: any;
|
|
37
|
+
orgs: {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
slug: string;
|
|
41
|
+
logoUrl: string | null;
|
|
42
|
+
role: string;
|
|
43
|
+
isActive: boolean;
|
|
44
|
+
}[];
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* GET /account/orgs/:id/json — detalhes da org ativa (para uso pelo hook `useOrganization()`).
|
|
48
|
+
* Só retorna se o usuário é membro.
|
|
49
|
+
*/
|
|
50
|
+
showJson(ctx: HttpContext): Promise<void | {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
slug: string;
|
|
54
|
+
logoUrl: string | null;
|
|
55
|
+
role: string;
|
|
56
|
+
canManage: boolean;
|
|
57
|
+
members: {
|
|
58
|
+
accountId: string;
|
|
59
|
+
email: string | null;
|
|
60
|
+
role: string;
|
|
61
|
+
joinedAt: string;
|
|
62
|
+
}[];
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* GET /account/orgs/invitations/json — lista convites pendentes pro e-mail do usuário logado.
|
|
66
|
+
* Usado pelo hook `useOrgInvitations()`.
|
|
67
|
+
*/
|
|
68
|
+
listInvitationsJson(ctx: HttpContext): Promise<void | {
|
|
69
|
+
invitations: {
|
|
70
|
+
id: string;
|
|
71
|
+
organizationId: string;
|
|
72
|
+
orgName: string;
|
|
73
|
+
orgSlug: string;
|
|
74
|
+
email: string;
|
|
75
|
+
role: string;
|
|
76
|
+
expiresAt: string;
|
|
77
|
+
createdAt: string;
|
|
78
|
+
}[];
|
|
79
|
+
}>;
|
|
80
|
+
}
|