@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,858 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Funções puras de verificação para `node ace authkit:doctor`. Não dependem do
|
|
3
|
+
* Ace nem do container — recebem objetos simples para serem testáveis em
|
|
4
|
+
* isolamento. O comando `authkit:doctor` só coleta o ambiente e imprime os
|
|
5
|
+
* resultados destas funções.
|
|
6
|
+
*/
|
|
7
|
+
/** Type guard estrutural: o store expõe um método (capacidade presente). */
|
|
8
|
+
function has(store, method) {
|
|
9
|
+
return !!store && typeof store[method] === 'function';
|
|
10
|
+
}
|
|
11
|
+
/** config('authkit') resolve? */
|
|
12
|
+
export function checkConfigResolves(input) {
|
|
13
|
+
if (!input.authkitConfig) {
|
|
14
|
+
return {
|
|
15
|
+
level: 'error',
|
|
16
|
+
message: "config('authkit') did not resolve — config/authkit.ts is missing or invalid.",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return { level: 'ok', message: "config('authkit') resolved." };
|
|
20
|
+
}
|
|
21
|
+
/** issuer é uma URL válida e seu pathname casa com o mountPath. */
|
|
22
|
+
export function checkIssuer(input) {
|
|
23
|
+
const cfg = input.authkitConfig;
|
|
24
|
+
if (!cfg)
|
|
25
|
+
return [];
|
|
26
|
+
const issuer = cfg.issuer;
|
|
27
|
+
const mountPath = cfg.mountPath ?? '/oidc';
|
|
28
|
+
if (typeof issuer !== 'string' || issuer.length === 0) {
|
|
29
|
+
return [{ level: 'error', message: 'issuer missing in config.' }];
|
|
30
|
+
}
|
|
31
|
+
let url;
|
|
32
|
+
try {
|
|
33
|
+
url = new URL(issuer);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return [{ level: 'error', message: `issuer is not a valid URL: "${issuer}".` }];
|
|
37
|
+
}
|
|
38
|
+
const findings = [{ level: 'ok', message: `valid issuer: ${url.origin}${url.pathname}` }];
|
|
39
|
+
const normalize = (p) => (p.endsWith('/') ? p.slice(0, -1) : p) || '/';
|
|
40
|
+
if (normalize(url.pathname) !== normalize(mountPath)) {
|
|
41
|
+
findings.push({
|
|
42
|
+
level: 'warn',
|
|
43
|
+
message: `issuer pathname ("${url.pathname}") differs from mountPath ("${mountPath}"). OIDC routes may not match the URLs announced in discovery.`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return findings;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clients: verifica que não há clients estáticos no config (clients são 100%
|
|
50
|
+
* runtime via console admin / Admin API).
|
|
51
|
+
*/
|
|
52
|
+
export function checkClients(input) {
|
|
53
|
+
const cfg = input.authkitConfig;
|
|
54
|
+
if (!cfg)
|
|
55
|
+
return { level: 'error', message: 'no config to validate clients.' };
|
|
56
|
+
// clients sempre é [] no config resolvido — info apenas.
|
|
57
|
+
return {
|
|
58
|
+
level: 'ok',
|
|
59
|
+
message: 'clients are managed at runtime via admin console / Admin API — use `node ace authkit:clients:create` to add clients.',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Aviso de adapter volátil. Como clients são 100% runtime (sem config estático),
|
|
64
|
+
* um adapter volátil (Redis sem persistência, in-memory) pode perder os clients
|
|
65
|
+
* num restart sem aviso prévio.
|
|
66
|
+
*
|
|
67
|
+
* Detecção de volatilidade: o `AdapterClass` é inspecionado estruturalmente:
|
|
68
|
+
* - `DatabaseAdapter` (ou subclasse) → persistente (sem warn)
|
|
69
|
+
* - qualquer outra classe → pode ser volátil → warn informativo
|
|
70
|
+
*/
|
|
71
|
+
export function checkAdapterVolatility(input) {
|
|
72
|
+
const cfg = input.authkitConfig;
|
|
73
|
+
if (!cfg)
|
|
74
|
+
return null;
|
|
75
|
+
const AdapterClass = cfg.AdapterClass;
|
|
76
|
+
if (!AdapterClass)
|
|
77
|
+
return null;
|
|
78
|
+
// Verifica se é um DatabaseAdapter (persistente). Usamos a cadeia de protótipos
|
|
79
|
+
// para detectar subclasses (o factory retorna uma subclasse anônima de DatabaseAdapter).
|
|
80
|
+
let isPersistent = false;
|
|
81
|
+
try {
|
|
82
|
+
const { DatabaseAdapter } = input.__adapterClasses ?? {};
|
|
83
|
+
if (DatabaseAdapter && AdapterClass.prototype instanceof DatabaseAdapter) {
|
|
84
|
+
isPersistent = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// sem __adapterClasses disponível — trata como desconhecido
|
|
89
|
+
}
|
|
90
|
+
if (isPersistent) {
|
|
91
|
+
return {
|
|
92
|
+
level: 'ok',
|
|
93
|
+
message: 'adapter is DatabaseAdapter (persistent) — clients managed via console/API survive restarts.',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Adapter desconhecido ou volátil (Redis, memory, custom) — warn informativo.
|
|
97
|
+
return {
|
|
98
|
+
level: 'warn',
|
|
99
|
+
message: 'No static clients in config: if the OIDC adapter is volatile (Redis without AOF/RDB, in-memory, etc.), ' +
|
|
100
|
+
'clients managed via console/API will be lost on restart. ' +
|
|
101
|
+
'Use a persistent adapter (DatabaseAdapter) or keep static clients as a fallback.',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** accountStore presente + quais capacidades implementa. */
|
|
105
|
+
export function checkAccountStore(input) {
|
|
106
|
+
const cfg = input.authkitConfig;
|
|
107
|
+
if (!cfg)
|
|
108
|
+
return [];
|
|
109
|
+
const store = cfg.accountStore;
|
|
110
|
+
if (!store) {
|
|
111
|
+
return [{ level: 'error', message: 'accountStore missing — required.' }];
|
|
112
|
+
}
|
|
113
|
+
const findings = [{ level: 'ok', message: 'accountStore present.' }];
|
|
114
|
+
const caps = [];
|
|
115
|
+
if (has(store, 'getMfaState'))
|
|
116
|
+
caps.push('MFA');
|
|
117
|
+
if (has(store, 'listPasskeys'))
|
|
118
|
+
caps.push('passkeys/WebAuthn');
|
|
119
|
+
if (has(store, 'findByProviderIdentity'))
|
|
120
|
+
caps.push('account-linking');
|
|
121
|
+
if (has(store, 'changePassword'))
|
|
122
|
+
caps.push('account-security');
|
|
123
|
+
if (has(store, 'isEmailVerified'))
|
|
124
|
+
caps.push('email-verification-status');
|
|
125
|
+
if (has(store, 'deleteAccount'))
|
|
126
|
+
caps.push('account-deletion');
|
|
127
|
+
findings.push({
|
|
128
|
+
level: 'ok',
|
|
129
|
+
message: caps.length
|
|
130
|
+
? `Optional capabilities: ${caps.join(', ')}.`
|
|
131
|
+
: 'accountStore core only (no MFA/passkeys/linking/security).',
|
|
132
|
+
});
|
|
133
|
+
return findings;
|
|
134
|
+
}
|
|
135
|
+
/** session provider configurado + warn se cookie store com tokenSets grandes. */
|
|
136
|
+
export function checkSession(input) {
|
|
137
|
+
if (!input.peers.session) {
|
|
138
|
+
return [
|
|
139
|
+
{
|
|
140
|
+
level: 'error',
|
|
141
|
+
message: '@adonisjs/session is not importable — install it (required peer).',
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
if (!input.sessionConfig) {
|
|
146
|
+
return [{ level: 'warn', message: "config('session') missing — the session provider may not be configured." }];
|
|
147
|
+
}
|
|
148
|
+
const findings = [{ level: 'ok', message: 'session provider configured.' }];
|
|
149
|
+
const driver = input.sessionConfig.store ?? input.sessionConfig.driver;
|
|
150
|
+
if (driver === 'cookie') {
|
|
151
|
+
findings.push({
|
|
152
|
+
level: 'warn',
|
|
153
|
+
message: 'session store = cookie: large token sets may exceed the 4KB cookie limit. Prefer `redis`/`file` in production.',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return findings;
|
|
157
|
+
}
|
|
158
|
+
/** Hint de exceções de CSRF do shield para o mountPath. */
|
|
159
|
+
export function checkShield(input) {
|
|
160
|
+
if (!input.peers.shield) {
|
|
161
|
+
return { level: 'error', message: '@adonisjs/shield is not importable — install it (required peer).' };
|
|
162
|
+
}
|
|
163
|
+
const mountPath = input.authkitConfig?.mountPath ?? '/oidc';
|
|
164
|
+
return {
|
|
165
|
+
level: 'warn',
|
|
166
|
+
message: `Make sure the IdP POST routes under "${mountPath}" are in the shield CSRF exceptions (e.g. the /token endpoint), otherwise server-to-server calls fail.`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** ally só é necessário quando social está configurado. */
|
|
170
|
+
export function checkAlly(input) {
|
|
171
|
+
const social = input.authkitConfig?.social;
|
|
172
|
+
const usesSocial = !!social && (Array.isArray(social.providers) ? social.providers.length > 0 : Object.keys(social).length > 0);
|
|
173
|
+
if (!usesSocial) {
|
|
174
|
+
return { level: 'ok', message: 'social login not configured — @adonisjs/ally is optional.' };
|
|
175
|
+
}
|
|
176
|
+
if (!input.peers.ally) {
|
|
177
|
+
return { level: 'error', message: 'social login configured, but @adonisjs/ally is not importable.' };
|
|
178
|
+
}
|
|
179
|
+
return { level: 'ok', message: 'social login configured and @adonisjs/ally available.' };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* OTP lockout: informativa. Avisa quando enabled mas limiter ausente (no-op).
|
|
183
|
+
* Não emite nada quando OTP lockout está desligado por setting (runtime).
|
|
184
|
+
*/
|
|
185
|
+
export function checkOtpLockout(input) {
|
|
186
|
+
// O OTP lockout usa o mesmo limiter do lockout de conta.
|
|
187
|
+
// Sem limiter → OTP lockout é no-op.
|
|
188
|
+
if (!input.peers.limiter) {
|
|
189
|
+
return {
|
|
190
|
+
level: 'warn',
|
|
191
|
+
message: 'otp_lockout is enabled by default but @adonisjs/limiter is not installed — OTP factor lockout will be a no-op. Install @adonisjs/limiter to enable it.',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return { level: 'ok', message: 'otp_lockout: @adonisjs/limiter available.' };
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Sudo mode: informativa. O sudo mode requer sessões Adonis (sempre disponíveis
|
|
198
|
+
* no console de conta). Apenas informa o estado.
|
|
199
|
+
*/
|
|
200
|
+
export function checkSudoMode(_input) {
|
|
201
|
+
return { level: 'ok', message: 'sudo_mode: enabled by default (15 min grace). Configure via admin settings or sudo_mode runtime setting.' };
|
|
202
|
+
}
|
|
203
|
+
/** rateLimit ligado mas @adonisjs/limiter ausente → warn. */
|
|
204
|
+
export function checkRateLimit(input) {
|
|
205
|
+
const cfg = input.authkitConfig;
|
|
206
|
+
const rateLimit = cfg?.rateLimit;
|
|
207
|
+
const enabled = rateLimit === undefined ? true : rateLimit?.enabled !== false;
|
|
208
|
+
if (!enabled) {
|
|
209
|
+
return { level: 'ok', message: 'rate-limiting disabled by config.' };
|
|
210
|
+
}
|
|
211
|
+
if (!input.peers.limiter) {
|
|
212
|
+
return {
|
|
213
|
+
level: 'warn',
|
|
214
|
+
message: 'rate-limiting is on (default), but @adonisjs/limiter is not importable — becomes a no-op (no anti-brute-force protection).',
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return { level: 'ok', message: 'rate-limiting on and @adonisjs/limiter available.' };
|
|
218
|
+
}
|
|
219
|
+
/** admin.enabled mas sem roles → warn. Reporta o modo de UI ativo. */
|
|
220
|
+
export function checkAdmin(input) {
|
|
221
|
+
const admin = input.authkitConfig?.admin;
|
|
222
|
+
if (!admin || admin.enabled !== true)
|
|
223
|
+
return null;
|
|
224
|
+
const roles = Array.isArray(admin.roles) ? admin.roles : [];
|
|
225
|
+
if (roles.length === 0) {
|
|
226
|
+
return {
|
|
227
|
+
level: 'warn',
|
|
228
|
+
message: 'admin console on, but no `admin.roles` — nobody will have access (the default ["ADMIN"] was not resolved here).',
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
level: 'ok',
|
|
233
|
+
message: `admin console on for roles: ${roles.join(', ')} (React SPA self-contained — JSON API under {prefix}/api/*).`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** requireVerifiedEmail ligado mas o store não sabe checar verificação → warn. */
|
|
237
|
+
export function checkRequireVerifiedEmail(input) {
|
|
238
|
+
const cfg = input.authkitConfig;
|
|
239
|
+
const login = cfg?.login;
|
|
240
|
+
if (!login || login.requireVerifiedEmail !== true)
|
|
241
|
+
return null;
|
|
242
|
+
const store = cfg?.accountStore;
|
|
243
|
+
if (!has(store, 'isEmailVerified')) {
|
|
244
|
+
return {
|
|
245
|
+
level: 'warn',
|
|
246
|
+
message: 'login.requireVerifiedEmail is on, but the accountStore has no `isEmailVerified` capability — the check is a no-op (nobody is blocked). Add an `email_verified_at` column (or a store that tracks it).',
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return { level: 'ok', message: 'login.requireVerifiedEmail on and the accountStore can check it.' };
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Bot protection (informativo): ativo quando `botProtection.verify` é uma função.
|
|
253
|
+
* Reporta em quais ações está ligado e lembra da semântica fail-safe. Silencioso
|
|
254
|
+
* quando não configurado.
|
|
255
|
+
*/
|
|
256
|
+
export function checkBotProtection(input) {
|
|
257
|
+
const bot = input.authkitConfig?.botProtection;
|
|
258
|
+
if (!bot)
|
|
259
|
+
return null;
|
|
260
|
+
if (typeof bot.verify !== 'function') {
|
|
261
|
+
return {
|
|
262
|
+
level: 'warn',
|
|
263
|
+
message: 'botProtection is set but `verify` is not a function — the check is skipped (no protection).',
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const on = Array.isArray(bot.on) && bot.on.length > 0 ? bot.on : ['login', 'signup'];
|
|
267
|
+
return {
|
|
268
|
+
level: 'ok',
|
|
269
|
+
message: `bot protection on for: ${on.join(', ')} — fail-safe (verify errors/timeouts allow the request, availability over protection).`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/** webauthn rpId deve casar com o host do issuer. */
|
|
273
|
+
export function checkWebauthn(input) {
|
|
274
|
+
const cfg = input.authkitConfig;
|
|
275
|
+
const webauthn = cfg?.webauthn;
|
|
276
|
+
if (!webauthn || !webauthn.rpId)
|
|
277
|
+
return null;
|
|
278
|
+
const issuer = cfg.issuer;
|
|
279
|
+
if (typeof issuer !== 'string')
|
|
280
|
+
return null;
|
|
281
|
+
let host;
|
|
282
|
+
try {
|
|
283
|
+
host = new URL(issuer).hostname;
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
if (webauthn.rpId !== host) {
|
|
289
|
+
return {
|
|
290
|
+
level: 'warn',
|
|
291
|
+
message: `webauthn.rpId ("${webauthn.rpId}") differs from the issuer host ("${host}") — passkeys will not validate in the browser.`,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return { level: 'ok', message: `webauthn.rpId matches the issuer host (${host}).` };
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Política de senha + checagem de vazamento (config do accountStore — opção
|
|
298
|
+
* `password`). Valida o shape da policy e informa quando o HIBP está ligado. A
|
|
299
|
+
* config vive no store (não no nível raiz da config authkit), então lemos de
|
|
300
|
+
* `accountStore` quando o host a expõe via `__passwordConfig` (best-effort) — na
|
|
301
|
+
* ausência, este check é silencioso (não falha).
|
|
302
|
+
*/
|
|
303
|
+
export function checkPasswordPolicy(input) {
|
|
304
|
+
const store = input.authkitConfig?.accountStore;
|
|
305
|
+
const pwConfig = store?.__passwordConfig;
|
|
306
|
+
if (!pwConfig)
|
|
307
|
+
return null;
|
|
308
|
+
const policy = pwConfig.policy;
|
|
309
|
+
if (policy) {
|
|
310
|
+
const minLength = policy.minLength;
|
|
311
|
+
if (minLength !== undefined && (typeof minLength !== 'number' || minLength < 1)) {
|
|
312
|
+
return {
|
|
313
|
+
level: 'warn',
|
|
314
|
+
message: `password.policy.minLength is invalid (${String(minLength)}) — expected a positive number.`,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
if (typeof minLength === 'number' && minLength < 8) {
|
|
318
|
+
return {
|
|
319
|
+
level: 'warn',
|
|
320
|
+
message: `password.policy.minLength is ${minLength} — values below 8 are discouraged.`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (pwConfig.checkPwned?.enabled) {
|
|
325
|
+
return {
|
|
326
|
+
level: 'ok',
|
|
327
|
+
message: 'password.checkPwned is on — new passwords are checked against HaveIBeenPwned (k-anonymity, fail-safe on network errors).',
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
return { level: 'ok', message: 'password policy configured.' };
|
|
331
|
+
}
|
|
332
|
+
/** info sobre rotação quando jwks é managed; warn se managed sem store (sem rotação real). */
|
|
333
|
+
export function checkJwks(input) {
|
|
334
|
+
// No config RESOLVIDO o `jwks` é o keyset materializado ({ keys }) e perde
|
|
335
|
+
// source/store — o shape de input fica ecoado em `jwksConfig`. Prefira-o.
|
|
336
|
+
const jwks = input.authkitConfig?.jwksConfig ?? input.authkitConfig?.jwks;
|
|
337
|
+
if (!jwks)
|
|
338
|
+
return null;
|
|
339
|
+
if (jwks.source === 'managed') {
|
|
340
|
+
if (!jwks.store) {
|
|
341
|
+
return {
|
|
342
|
+
level: 'warn',
|
|
343
|
+
message: 'jwks managed WITHOUT a `store` — a fresh ephemeral key is generated each boot (tokens stop validating after a restart and `node ace authkit:keys:rotate` has no effect). Set `jwks.store` to persist and enable real rotation.',
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
level: 'ok',
|
|
348
|
+
message: 'jwks managed with a persisted store — rotate the signing keys with `node ace authkit:keys:rotate` (--dry-run to preview, --retire to drop old keys, --keep=N for the grace window).',
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return { level: 'ok', message: 'jwks provided inline (source=jwks).' };
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Formato dos Access Tokens (RFC 9068). Informa o formato configurado e, no modo
|
|
355
|
+
* JWT, lembra que o JWKS precisa ser estável (store persistido) para que os RPs
|
|
356
|
+
* validem os ATs via jwks_uri através de reinícios/rotação.
|
|
357
|
+
*/
|
|
358
|
+
export function checkAccessTokens(input) {
|
|
359
|
+
const cfg = input.authkitConfig;
|
|
360
|
+
const at = cfg?.accessTokens;
|
|
361
|
+
if (!at)
|
|
362
|
+
return null;
|
|
363
|
+
const resources = at.resources ?? {};
|
|
364
|
+
const resourceCount = Object.keys(resources).length;
|
|
365
|
+
const anyJwt = at.anyJwt ?? (at.format === 'jwt' || Object.values(resources).some((r) => r?.format === 'jwt'));
|
|
366
|
+
if (!anyJwt) {
|
|
367
|
+
return { level: 'ok', message: 'access tokens are opaque (default) — introspect them at the introspection endpoint.' };
|
|
368
|
+
}
|
|
369
|
+
const detail = resourceCount
|
|
370
|
+
? `format=${at.format}, ${resourceCount} resource(s) configured`
|
|
371
|
+
: `format=jwt, audience=${at.audience}`;
|
|
372
|
+
const jwks = cfg?.jwks;
|
|
373
|
+
if (jwks?.source === 'managed' && !jwks.store) {
|
|
374
|
+
return {
|
|
375
|
+
level: 'warn',
|
|
376
|
+
message: `JWT access tokens (RFC 9068) are on (${detail}), but jwks is managed WITHOUT a store — the signing key changes every boot, so issued JWT ATs stop validating after a restart. Set jwks.store.`,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
level: 'ok',
|
|
381
|
+
message: `JWT access tokens (RFC 9068) are on (${detail}) — signed with the JWKS key, validable via jwks_uri (typ "at+jwt").`,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Organizations (multi-tenancy). Informa se a capacidade está disponível
|
|
386
|
+
* (store expõe createOrg) e avisa se `organizations.enabled: true` no config mas
|
|
387
|
+
* a capacidade não está presente no store (organizationModels não foram passados).
|
|
388
|
+
*/
|
|
389
|
+
export function checkOrganizations(input) {
|
|
390
|
+
const cfg = input.authkitConfig;
|
|
391
|
+
if (!cfg)
|
|
392
|
+
return null;
|
|
393
|
+
const store = cfg.accountStore;
|
|
394
|
+
const orgsEnabled = cfg.organizations?.enabled;
|
|
395
|
+
const storeSupports = has(store, 'createOrg');
|
|
396
|
+
if (orgsEnabled === true && !storeSupports) {
|
|
397
|
+
return {
|
|
398
|
+
level: 'warn',
|
|
399
|
+
message: 'organizations.enabled: true, but the accountStore has no OrganizationsCapability — ' +
|
|
400
|
+
'pass `organizationModels: { OrgModel, MemberModel, InvitationModel }` to `lucidAccountStore()`. ' +
|
|
401
|
+
'Expected tables: auth_organizations, auth_organization_members, auth_organization_invitations.',
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
if (storeSupports) {
|
|
405
|
+
const roles = cfg.organizations?.roles ?? ['owner', 'admin', 'member'];
|
|
406
|
+
return {
|
|
407
|
+
level: 'ok',
|
|
408
|
+
message: `organizations capability present (roles: ${roles.join(', ')}).`,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
// Auto mode (enabled === undefined) and store doesn't support — silently ok (opt-in).
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Runtime settings: informa se a tabela `auth_settings` está presente.
|
|
416
|
+
* Quando ausente, é silencioso (a feature é opt-in). Quando presente mas
|
|
417
|
+
* `botProtection.verify` NÃO está no config, alerta que a setting em banco
|
|
418
|
+
* é órfã e não tem efeito.
|
|
419
|
+
*/
|
|
420
|
+
export function checkSettings(input) {
|
|
421
|
+
const cfg = input.authkitConfig;
|
|
422
|
+
if (!cfg)
|
|
423
|
+
return null;
|
|
424
|
+
const tablePresent = input.settingsTablePresent;
|
|
425
|
+
if (tablePresent === undefined) {
|
|
426
|
+
// Doctor did not check — silently skip.
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
if (!tablePresent) {
|
|
430
|
+
// Table absent — opt-in feature, silently ok.
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
// Informa a conexão usada quando nomeada (ajuda a diagnosticar bugs de searchPath).
|
|
434
|
+
const connectionName = cfg.accountStore?.connectionName;
|
|
435
|
+
const connectionHint = connectionName ? ` (connection: '${connectionName}')` : '';
|
|
436
|
+
// Table present — check if botProtection.verify is configured.
|
|
437
|
+
const hasBotVerify = typeof cfg.botProtection?.verify === 'function';
|
|
438
|
+
if (!hasBotVerify) {
|
|
439
|
+
return {
|
|
440
|
+
level: 'warn',
|
|
441
|
+
message: `The \`auth_settings\` table is present${connectionHint}, but \`botProtection.verify\` is not configured in config — any \`bot_protection\` setting stored in \`auth_settings\` is an orphan and has no effect. Add \`botProtection.verify\` to config/authkit.ts or drop the row.`,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
level: 'ok',
|
|
446
|
+
message: `auth_settings table present${connectionHint} — runtime settings (including bot-protection toggle) are active.`,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* auth_methods setting: verifica se o valor persistido tem forma válida.
|
|
451
|
+
* O input `authMethodsSetting` é injetado pelo doctor command quando a tabela
|
|
452
|
+
* está presente — similar ao padrão do checkSettings mas focado na setting específica.
|
|
453
|
+
*
|
|
454
|
+
* Warns quando:
|
|
455
|
+
* - Todos os métodos estão desligados (fail-safe será acionado em runtime).
|
|
456
|
+
* - A lista `social` referencia um provider não presente em `config.social.providers`.
|
|
457
|
+
*/
|
|
458
|
+
export function checkAuthMethodsSetting(input) {
|
|
459
|
+
const cfg = input.authkitConfig;
|
|
460
|
+
if (!cfg)
|
|
461
|
+
return null;
|
|
462
|
+
// Só verificamos quando a tabela existe e o setting foi injetado no input.
|
|
463
|
+
const raw = input.authMethodsSetting;
|
|
464
|
+
if (raw === undefined || raw === null)
|
|
465
|
+
return null;
|
|
466
|
+
if (typeof raw !== 'object' || Array.isArray(raw)) {
|
|
467
|
+
return {
|
|
468
|
+
level: 'warn',
|
|
469
|
+
message: 'auth_methods setting has an invalid shape — expected an object. The setting will be ignored (config defaults apply).',
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
const s = raw;
|
|
473
|
+
// Check all-off scenario.
|
|
474
|
+
const allOff = s.password === false &&
|
|
475
|
+
s.magicLink === false &&
|
|
476
|
+
s.passkey === false &&
|
|
477
|
+
Array.isArray(s.social) && s.social.length === 0;
|
|
478
|
+
if (allOff) {
|
|
479
|
+
return {
|
|
480
|
+
level: 'warn',
|
|
481
|
+
message: 'auth_methods setting disables all login methods — a fail-safe will revert to config defaults at runtime. ' +
|
|
482
|
+
'Enable at least one method in the admin console (/admin/settings) to avoid the fallback.',
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
// Check social references unknown providers.
|
|
486
|
+
if (Array.isArray(s.social) && s.social.length > 0) {
|
|
487
|
+
const configuredProviders = cfg.social?.providers ?? [];
|
|
488
|
+
const unknown = s.social.filter((p) => !configuredProviders.includes(p));
|
|
489
|
+
if (unknown.length > 0) {
|
|
490
|
+
return {
|
|
491
|
+
level: 'warn',
|
|
492
|
+
message: `auth_methods setting references social provider(s) not in config.social.providers: [${unknown.join(', ')}]. ` +
|
|
493
|
+
'These providers will be silently filtered out (intersection rule). ' +
|
|
494
|
+
'Remove them from the setting or add them to config.social.providers.',
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return {
|
|
499
|
+
level: 'ok',
|
|
500
|
+
message: 'auth_methods setting is valid.',
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Verifica se o fluxo de troca de e-mail verificada está disponível.
|
|
505
|
+
* Reporta se o store suporta a capability de security (requestEmailChange/confirmEmailChange).
|
|
506
|
+
*/
|
|
507
|
+
export function checkEmailChange(input) {
|
|
508
|
+
const cfg = input.authkitConfig;
|
|
509
|
+
if (!cfg)
|
|
510
|
+
return null;
|
|
511
|
+
const store = cfg.accountStore;
|
|
512
|
+
// A capability de security é identificada pelo método changePassword no store.
|
|
513
|
+
if (!has(store, 'changePassword')) {
|
|
514
|
+
return {
|
|
515
|
+
level: 'warn',
|
|
516
|
+
message: 'accountStore does not implement AccountSecurityCapability (changePassword/requestEmailChange/confirmEmailChange) — verified email-change flow is unavailable. The /account/security email-change form will be hidden.',
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
return {
|
|
520
|
+
level: 'ok',
|
|
521
|
+
message: 'accountStore supports AccountSecurityCapability — verified email-change flow available.',
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Verifica a capability de notificações de segurança:
|
|
526
|
+
* - mail configurado (para envio dos alertas)
|
|
527
|
+
* - store com suporte a AccountSecurityCapability
|
|
528
|
+
*/
|
|
529
|
+
export function checkSecurityNotifications(input) {
|
|
530
|
+
const cfg = input.authkitConfig;
|
|
531
|
+
if (!cfg)
|
|
532
|
+
return null;
|
|
533
|
+
// Notificações de segurança são best-effort; reportamos apenas informativo.
|
|
534
|
+
const hasMail = !!(cfg.mail || cfg.mailer);
|
|
535
|
+
const hasStore = has(cfg.accountStore, 'changePassword');
|
|
536
|
+
if (!hasMail) {
|
|
537
|
+
return {
|
|
538
|
+
level: 'warn',
|
|
539
|
+
message: 'No mail hook (mail.onSecurityNotice) or @adonisjs/mail configured — security notifications will fall back to dev-mode logging. Configure mail or provide mail.onSecurityNotice in config/authkit.ts.',
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
if (!hasStore) {
|
|
543
|
+
return {
|
|
544
|
+
level: 'warn',
|
|
545
|
+
message: 'accountStore does not implement AccountSecurityCapability — security notification triggers in the account console are unavailable.',
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
return null; // Silencioso quando tudo está ok (não-obrigatório).
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Verifica a capability de histórico de senhas.
|
|
552
|
+
* - Informa se a tabela `auth_password_history` está presente.
|
|
553
|
+
* - Avisa quando pepper está configurado como string (não array) — rotation recomendada.
|
|
554
|
+
*/
|
|
555
|
+
export function checkPasswordPepper(input) {
|
|
556
|
+
const store = input.authkitConfig?.accountStore;
|
|
557
|
+
const pepper = store?.__pepper;
|
|
558
|
+
if (!pepper)
|
|
559
|
+
return null;
|
|
560
|
+
if (typeof pepper === 'string') {
|
|
561
|
+
return {
|
|
562
|
+
level: 'ok',
|
|
563
|
+
message: 'password.pepper is configured (HMAC-SHA256 before hashing). ' +
|
|
564
|
+
'Consider using an array `[newPepper, oldPepper]` for rotation without downtime.',
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
if (Array.isArray(pepper)) {
|
|
568
|
+
return {
|
|
569
|
+
level: 'ok',
|
|
570
|
+
message: `password.pepper rotation configured (${pepper.length} pepper(s)). ` +
|
|
571
|
+
'First pepper is current; subsequent peppers are tried on verify (lazy re-hash).',
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Verifica a capability de histórico de senhas (disallow_password_reuse).
|
|
578
|
+
* Informa se a tabela `auth_password_history` está presente e a capability está disponível.
|
|
579
|
+
* Avisa quando a setting está ligada mas a capability não está presente.
|
|
580
|
+
*/
|
|
581
|
+
export function checkPasswordHistory(input) {
|
|
582
|
+
const cfg = input.authkitConfig;
|
|
583
|
+
if (!cfg)
|
|
584
|
+
return null;
|
|
585
|
+
const store = cfg.accountStore;
|
|
586
|
+
// Capability presente quando o store tem isPasswordReused.
|
|
587
|
+
const hasCapability = has(store, 'isPasswordReused');
|
|
588
|
+
// Verifica se a setting está ativa (injetada no input pelo doctor command).
|
|
589
|
+
const histSetting = input.passwordHistorySetting;
|
|
590
|
+
if (histSetting?.enabled && !hasCapability) {
|
|
591
|
+
return {
|
|
592
|
+
level: 'warn',
|
|
593
|
+
message: 'password_history setting is enabled but the accountStore lacks PasswordHistoryCapability — ' +
|
|
594
|
+
'the `auth_password_history` table may be missing. Create it: ' +
|
|
595
|
+
'`id UUID/SERIAL PK, account_id TEXT NOT NULL, password_hash TEXT NOT NULL, created_at TIMESTAMP NOT NULL`.',
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
if (hasCapability) {
|
|
599
|
+
return {
|
|
600
|
+
level: 'ok',
|
|
601
|
+
message: 'password history capability present (auth_password_history table detected).',
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
return null; // Silencioso quando opt-in não configurado.
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Verifica a capability de expiração de senha.
|
|
608
|
+
* Informa se a coluna `password_changed_at` está presente. Avisa quando a setting
|
|
609
|
+
* está ligada mas a coluna não existe.
|
|
610
|
+
*/
|
|
611
|
+
export function checkPasswordExpiration(input) {
|
|
612
|
+
const cfg = input.authkitConfig;
|
|
613
|
+
if (!cfg)
|
|
614
|
+
return null;
|
|
615
|
+
const store = cfg.accountStore;
|
|
616
|
+
// Capability presente quando o store tem getPasswordChangedAt.
|
|
617
|
+
const hasCapability = has(store, 'getPasswordChangedAt');
|
|
618
|
+
// Verifica se a setting está ativa (injetada no input pelo doctor command).
|
|
619
|
+
const expSetting = input.passwordExpirationSetting;
|
|
620
|
+
if (expSetting?.enabled && !hasCapability) {
|
|
621
|
+
return {
|
|
622
|
+
level: 'warn',
|
|
623
|
+
message: 'password_expiration setting is enabled but the accountStore lacks PasswordExpirationCapability — ' +
|
|
624
|
+
'the `password_changed_at` column may be missing from the auth users table. ' +
|
|
625
|
+
'Add it: `password_changed_at TIMESTAMP NULL`.',
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
if (hasCapability) {
|
|
629
|
+
const maxAge = expSetting?.maxAgeDays ?? 90;
|
|
630
|
+
return {
|
|
631
|
+
level: 'ok',
|
|
632
|
+
message: expSetting?.enabled
|
|
633
|
+
? `password expiration is on (max ${maxAge} days).`
|
|
634
|
+
: 'password_changed_at column detected — password expiration capability available (currently off in settings).',
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return null; // Silencioso quando opt-in não configurado.
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Verifica a setting `session_policy` para valores absurdos ou inconsistentes.
|
|
641
|
+
*
|
|
642
|
+
* Checks:
|
|
643
|
+
* - idleTimeoutMinutes > defaultSessionHours*60: idle timeout nunca irá disparar.
|
|
644
|
+
* - rememberDays > 365: incomumente longo (warn).
|
|
645
|
+
* - idleTimeoutMinutes > 0 mas defaultSessionHours = 0: impossível (error).
|
|
646
|
+
*/
|
|
647
|
+
export function checkSessionPolicy(input) {
|
|
648
|
+
const policy = input.sessionPolicySetting;
|
|
649
|
+
if (!policy || typeof policy !== 'object')
|
|
650
|
+
return null;
|
|
651
|
+
const idleMin = typeof policy.idleTimeoutMinutes === 'number' ? policy.idleTimeoutMinutes : 0;
|
|
652
|
+
const defaultHours = typeof policy.defaultSessionHours === 'number' ? policy.defaultSessionHours : 168;
|
|
653
|
+
const rememberDays = typeof policy.rememberDays === 'number' ? policy.rememberDays : 30;
|
|
654
|
+
if (idleMin > 0 && defaultHours > 0 && idleMin > defaultHours * 60) {
|
|
655
|
+
return {
|
|
656
|
+
level: 'warn',
|
|
657
|
+
message: `session_policy: idleTimeoutMinutes (${idleMin}) exceeds defaultSessionHours*60 (${defaultHours * 60}). ` +
|
|
658
|
+
'The idle timeout will never trigger — increase defaultSessionHours or reduce idleTimeoutMinutes.',
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
if (rememberDays > 365) {
|
|
662
|
+
return {
|
|
663
|
+
level: 'warn',
|
|
664
|
+
message: `session_policy: rememberDays (${rememberDays}) exceeds 365. This is an unusually long session duration.`,
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
level: 'ok',
|
|
669
|
+
message: `session_policy: rememberEnabled=${policy.rememberEnabled ?? true}, ` +
|
|
670
|
+
`rememberDays=${rememberDays}, defaultSessionHours=${defaultHours}, ` +
|
|
671
|
+
`singleSession=${policy.singleSession ?? false}, idleTimeoutMinutes=${idleMin}.`,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Verifica o catálogo de roles globais (informativo).
|
|
676
|
+
*
|
|
677
|
+
* Checks:
|
|
678
|
+
* - Informa o número de roles no catálogo quando a setting está presente.
|
|
679
|
+
* - Avisa se `cfg.admin.roles` contém role(s) fora do catálogo (o gate do console
|
|
680
|
+
* pode não funcionar como esperado se a role não existir no catálogo).
|
|
681
|
+
*/
|
|
682
|
+
export function checkRolesCatalog(input) {
|
|
683
|
+
const cfg = input.authkitConfig;
|
|
684
|
+
if (!cfg)
|
|
685
|
+
return null;
|
|
686
|
+
const raw = input.rolesCatalogSetting;
|
|
687
|
+
if (raw === undefined || raw === null)
|
|
688
|
+
return null; // setting não presente — silencioso
|
|
689
|
+
if (typeof raw !== 'object' || !Array.isArray(raw.roles)) {
|
|
690
|
+
return {
|
|
691
|
+
level: 'warn',
|
|
692
|
+
message: 'roles_catalog setting has an invalid shape — expected { roles: [...] }. The setting will be ignored (default catalog applies).',
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
const catalogRoles = raw.roles
|
|
696
|
+
.filter((r) => typeof r === 'object' && typeof r.name === 'string')
|
|
697
|
+
.map((r) => r.name);
|
|
698
|
+
// Verifica se admin.roles referencia roles fora do catálogo.
|
|
699
|
+
const adminRoles = Array.isArray(cfg.admin?.roles) ? cfg.admin.roles : ['ADMIN'];
|
|
700
|
+
const outOfCatalog = adminRoles.filter((r) => !catalogRoles.includes(r));
|
|
701
|
+
if (outOfCatalog.length > 0) {
|
|
702
|
+
return {
|
|
703
|
+
level: 'warn',
|
|
704
|
+
message: `roles_catalog: ${catalogRoles.length} role(s) in catalog, but cfg.admin.roles references [${outOfCatalog.join(', ')}] which are not in the catalog. ` +
|
|
705
|
+
'Admin access depends on these roles — add them to the catalog at /admin/roles.',
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
return {
|
|
709
|
+
level: 'ok',
|
|
710
|
+
message: `roles_catalog: ${catalogRoles.length} role(s) in catalog (${catalogRoles.join(', ')}).`,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Verifica a feature de expiração de conta por inatividade.
|
|
715
|
+
*
|
|
716
|
+
* - Capability-probed: sem audit com `list` → a feature fica indisponível; explica o motivo.
|
|
717
|
+
* - Quando a setting `account_expiration` está presente, valida a coerência dos campos.
|
|
718
|
+
*/
|
|
719
|
+
export function checkAccountExpiration(input) {
|
|
720
|
+
const cfg = input.authkitConfig;
|
|
721
|
+
if (!cfg)
|
|
722
|
+
return null;
|
|
723
|
+
// Sem audit configurado → feature completamente indisponível.
|
|
724
|
+
if (!cfg.audit)
|
|
725
|
+
return null;
|
|
726
|
+
// Verifica se o audit implementa `list` (capability-probed).
|
|
727
|
+
const auditHasList = typeof cfg.audit.list === 'function';
|
|
728
|
+
if (!auditHasList) {
|
|
729
|
+
return {
|
|
730
|
+
level: 'warn',
|
|
731
|
+
message: 'account_expiration: the configured audit sink does not implement the `list` method. ' +
|
|
732
|
+
'Account inactivity expiration requires a queryable audit sink (e.g. lucidAuditSink). ' +
|
|
733
|
+
'The feature is unavailable until you configure a queryable audit sink.',
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
return {
|
|
737
|
+
level: 'ok',
|
|
738
|
+
message: 'account_expiration: audit sink supports list() — feature is available when enabled via auth_settings.',
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Verifica a disponibilidade do WebAuthn passkey autofill (conditional mediation).
|
|
743
|
+
*
|
|
744
|
+
* Informativo: se webauthn não estiver configurado, o autofill nunca será exibido.
|
|
745
|
+
*/
|
|
746
|
+
export function checkPasskeyAutofill(input) {
|
|
747
|
+
const cfg = input.authkitConfig;
|
|
748
|
+
if (!cfg)
|
|
749
|
+
return null;
|
|
750
|
+
if (!cfg.webauthn) {
|
|
751
|
+
// WebAuthn não configurado → autofill nunca ativo. Só info quando webauthn ausente.
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
level: 'ok',
|
|
756
|
+
message: 'passkey_autofill: WebAuthn is configured — conditional mediation (passkey autofill) is supported. ' +
|
|
757
|
+
'Control via auth_methods.passkeyAutofill setting (default on when passkey is on). ' +
|
|
758
|
+
'Requires browsers with PublicKeyCredential.isConditionalMediationAvailable() support.',
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Finding da idade da chave de assinatura managed. `ageDays === null` (sem
|
|
763
|
+
* keystore em arquivo/cofre) → no-op `ok`. Acima de `maxAgeDays` → `warn`.
|
|
764
|
+
*/
|
|
765
|
+
export function signingKeyAgeFinding(ageDays, maxAgeDays) {
|
|
766
|
+
if (ageDays === null)
|
|
767
|
+
return { level: 'ok', message: 'jwks: idade da chave não aplicável (sem keystore persistido).' };
|
|
768
|
+
if (ageDays > maxAgeDays) {
|
|
769
|
+
return {
|
|
770
|
+
level: 'warn',
|
|
771
|
+
message: `jwks: chave de assinatura tem ~${ageDays}d (> ${maxAgeDays}d) — considere rotacionar (authkit:keys:rotate).`,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
return { level: 'ok', message: `jwks: chave de assinatura tem ~${ageDays}d.` };
|
|
775
|
+
}
|
|
776
|
+
/** Roda todos os checks e devolve a lista plana de findings. */
|
|
777
|
+
export function runAllChecks(input) {
|
|
778
|
+
const findings = [];
|
|
779
|
+
findings.push(checkConfigResolves(input));
|
|
780
|
+
findings.push(...checkIssuer(input));
|
|
781
|
+
findings.push(checkClients(input));
|
|
782
|
+
const volatility = checkAdapterVolatility(input);
|
|
783
|
+
if (volatility)
|
|
784
|
+
findings.push(volatility);
|
|
785
|
+
findings.push(...checkAccountStore(input));
|
|
786
|
+
findings.push(...checkSession(input));
|
|
787
|
+
findings.push(checkShield(input));
|
|
788
|
+
findings.push(checkAlly(input));
|
|
789
|
+
findings.push(checkRateLimit(input));
|
|
790
|
+
const admin = checkAdmin(input);
|
|
791
|
+
if (admin)
|
|
792
|
+
findings.push(admin);
|
|
793
|
+
const requireVerified = checkRequireVerifiedEmail(input);
|
|
794
|
+
if (requireVerified)
|
|
795
|
+
findings.push(requireVerified);
|
|
796
|
+
const botProtection = checkBotProtection(input);
|
|
797
|
+
if (botProtection)
|
|
798
|
+
findings.push(botProtection);
|
|
799
|
+
const webauthn = checkWebauthn(input);
|
|
800
|
+
if (webauthn)
|
|
801
|
+
findings.push(webauthn);
|
|
802
|
+
const passwordPolicy = checkPasswordPolicy(input);
|
|
803
|
+
if (passwordPolicy)
|
|
804
|
+
findings.push(passwordPolicy);
|
|
805
|
+
const jwks = checkJwks(input);
|
|
806
|
+
if (jwks)
|
|
807
|
+
findings.push(jwks);
|
|
808
|
+
const accessTokens = checkAccessTokens(input);
|
|
809
|
+
if (accessTokens)
|
|
810
|
+
findings.push(accessTokens);
|
|
811
|
+
const orgs = checkOrganizations(input);
|
|
812
|
+
if (orgs)
|
|
813
|
+
findings.push(orgs);
|
|
814
|
+
const settings = checkSettings(input);
|
|
815
|
+
if (settings)
|
|
816
|
+
findings.push(settings);
|
|
817
|
+
const authMethods = checkAuthMethodsSetting(input);
|
|
818
|
+
if (authMethods)
|
|
819
|
+
findings.push(authMethods);
|
|
820
|
+
const emailChange = checkEmailChange(input);
|
|
821
|
+
if (emailChange)
|
|
822
|
+
findings.push(emailChange);
|
|
823
|
+
const securityNotifications = checkSecurityNotifications(input);
|
|
824
|
+
if (securityNotifications)
|
|
825
|
+
findings.push(securityNotifications);
|
|
826
|
+
const pepper = checkPasswordPepper(input);
|
|
827
|
+
if (pepper)
|
|
828
|
+
findings.push(pepper);
|
|
829
|
+
const passwordHistory = checkPasswordHistory(input);
|
|
830
|
+
if (passwordHistory)
|
|
831
|
+
findings.push(passwordHistory);
|
|
832
|
+
const passwordExpiration = checkPasswordExpiration(input);
|
|
833
|
+
if (passwordExpiration)
|
|
834
|
+
findings.push(passwordExpiration);
|
|
835
|
+
const sessionPolicy = checkSessionPolicy(input);
|
|
836
|
+
if (sessionPolicy)
|
|
837
|
+
findings.push(sessionPolicy);
|
|
838
|
+
const rolesCatalog = checkRolesCatalog(input);
|
|
839
|
+
if (rolesCatalog)
|
|
840
|
+
findings.push(rolesCatalog);
|
|
841
|
+
const otpLockout = checkOtpLockout(input);
|
|
842
|
+
if (otpLockout)
|
|
843
|
+
findings.push(otpLockout);
|
|
844
|
+
const sudoMode = checkSudoMode(input);
|
|
845
|
+
if (sudoMode)
|
|
846
|
+
findings.push(sudoMode);
|
|
847
|
+
const accountExpiration = checkAccountExpiration(input);
|
|
848
|
+
if (accountExpiration)
|
|
849
|
+
findings.push(accountExpiration);
|
|
850
|
+
const passkeyAutofill = checkPasskeyAutofill(input);
|
|
851
|
+
if (passkeyAutofill)
|
|
852
|
+
findings.push(passkeyAutofill);
|
|
853
|
+
return findings;
|
|
854
|
+
}
|
|
855
|
+
/** Há algum finding de nível 'error'? (define o exit code). */
|
|
856
|
+
export function hasErrors(findings) {
|
|
857
|
+
return findings.some((f) => f.level === 'error');
|
|
858
|
+
}
|