@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,119 @@
|
|
|
1
|
+
import type { OidcService } from '../provider/oidc_service.js';
|
|
2
|
+
/** Uma sessão ativa do IdP (login do usuário no provider), apresentada ao admin. */
|
|
3
|
+
export interface AdminSession {
|
|
4
|
+
/** Id do artefato `Session` no adapter. */
|
|
5
|
+
id: string;
|
|
6
|
+
accountId: string;
|
|
7
|
+
/**
|
|
8
|
+
* Email da conta — resolvido pelo `listAllSessions()` na listagem global.
|
|
9
|
+
* Ausente em `listSessions(accountId)` (já é implícito pelo contexto).
|
|
10
|
+
*/
|
|
11
|
+
email?: string | null;
|
|
12
|
+
/** Epoch (segundos) do login, quando presente no payload. */
|
|
13
|
+
loginTs?: number;
|
|
14
|
+
/** Métodos de autenticação registrados na sessão (amr), quando presentes. */
|
|
15
|
+
amr?: string[];
|
|
16
|
+
/**
|
|
17
|
+
* User-agent bruto do login, recuperado do audit `login.success` por join
|
|
18
|
+
* accountId+loginTs ({@link enrichSessionsWithContext}). Ausente quando o sink de
|
|
19
|
+
* auditoria não consulta ou não há evento correlacionável.
|
|
20
|
+
*/
|
|
21
|
+
userAgent?: string | null;
|
|
22
|
+
/** Família do browser derivada do user-agent (ex.: 'Chrome'). */
|
|
23
|
+
browser?: string | null;
|
|
24
|
+
/** Sistema operacional derivado do user-agent (ex.: 'macOS'). */
|
|
25
|
+
os?: string | null;
|
|
26
|
+
/** IP do login (do mesmo audit `login.success`). */
|
|
27
|
+
ip?: string | null;
|
|
28
|
+
/** Localização legível resolvida via o hook `resolveGeo` (null sem hook/resolução). */
|
|
29
|
+
location?: string | null;
|
|
30
|
+
}
|
|
31
|
+
/** Um grant (autorização concedida a um client), com a contagem de tokens vivos. */
|
|
32
|
+
export interface AdminGrant {
|
|
33
|
+
/** Id do artefato `Grant` no adapter (== grantId dos tokens). */
|
|
34
|
+
id: string;
|
|
35
|
+
accountId: string;
|
|
36
|
+
clientId?: string;
|
|
37
|
+
/** Tokens de acesso vivos que referenciam este grant. */
|
|
38
|
+
accessTokens: number;
|
|
39
|
+
/** Refresh tokens vivos que referenciam este grant. */
|
|
40
|
+
refreshTokens: number;
|
|
41
|
+
}
|
|
42
|
+
/** Resultado de uma revogação em massa das sessões/grants de uma conta. */
|
|
43
|
+
export interface RevokeResult {
|
|
44
|
+
sessions: number;
|
|
45
|
+
grants: number;
|
|
46
|
+
accessTokens: number;
|
|
47
|
+
refreshTokens: number;
|
|
48
|
+
}
|
|
49
|
+
export declare class AdminSessionsService {
|
|
50
|
+
#private;
|
|
51
|
+
constructor(oidc: OidcService);
|
|
52
|
+
/**
|
|
53
|
+
* Grava uma revogação por `sub` na tabela compartilhada `auth_session_revocations`,
|
|
54
|
+
* para que clients COOKIE-BASED (que não têm store de sessão server-side) derrubem
|
|
55
|
+
* a sessão na próxima request — INSTANTÂNEO, sem esperar o refresh token falhar.
|
|
56
|
+
*
|
|
57
|
+
* Best-effort: a destruição de grants/tokens acima já é a fonte da verdade; esta
|
|
58
|
+
* linha só acelera o efeito nos clients. Falha (tabela ausente) é silenciosa.
|
|
59
|
+
*
|
|
60
|
+
* @param accountId Conta cujas sessões devem ser derrubadas (gravado em `sub`).
|
|
61
|
+
* @param revokedAt Timestamp da revogação. Default: agora. A checagem do client
|
|
62
|
+
* é `revoked_at >= iat(id_token)` (em segundos): uma sessão só é derrubada se
|
|
63
|
+
* foi estabelecida ANTES (ou no mesmo segundo) da revogação. O
|
|
64
|
+
* {@link revokeAllExcept} passa um `revokedAt` ANTERIOR ao `iat` da sessão
|
|
65
|
+
* PRESERVADA, para que esta NÃO se auto-derrube (ver lá).
|
|
66
|
+
*/
|
|
67
|
+
protected recordSubRevocation(accountId: string, revokedAt?: Date): Promise<void>;
|
|
68
|
+
/** Indica se o adapter suporta enumeração (capacidade opcional). */
|
|
69
|
+
get canList(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Conta TODAS as sessões ativas do IdP (todas as contas). 0 quando o adapter não
|
|
72
|
+
* enumera. Usado pelo dashboard de métricas.
|
|
73
|
+
*/
|
|
74
|
+
countActiveSessions(): Promise<number>;
|
|
75
|
+
/** Lista as sessões ativas da conta (vazio quando o adapter não enumera). */
|
|
76
|
+
listSessions(accountId: string): Promise<AdminSession[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Lista TODAS as sessões ativas de TODAS as contas — usada pela listagem global
|
|
79
|
+
* do console admin (sem `accountId`). Resolve o email de cada conta via
|
|
80
|
+
* `accountStore.findById` com cache por id (evita N+1). Limita a
|
|
81
|
+
* {@link GLOBAL_SESSION_LIMIT} entradas; quando truncado, inclui `truncated:true`
|
|
82
|
+
* nos metadados (accessível via `result.truncated`). Retorna vazio quando o
|
|
83
|
+
* adapter não enumera.
|
|
84
|
+
*/
|
|
85
|
+
listAllSessions(): Promise<{
|
|
86
|
+
sessions: AdminSession[];
|
|
87
|
+
truncated: boolean;
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Lista os grants da conta, com a contagem de access/refresh tokens vivos que
|
|
91
|
+
* referenciam cada grant (`payload.grantId`). As contagens são baratas (uma
|
|
92
|
+
* enumeração de cada model token), feitas só quando o adapter enumera.
|
|
93
|
+
*/
|
|
94
|
+
listGrants(accountId: string): Promise<AdminGrant[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Revoga todas as sessões e grants da conta EXCETO a sessão corrente (pelo id).
|
|
97
|
+
* Usado pela política single-session: após login, revoga todas as outras sessões
|
|
98
|
+
* preservando a recém-criada. Retorna as contagens do que foi removido.
|
|
99
|
+
*
|
|
100
|
+
* @param accountId Id da conta.
|
|
101
|
+
* @param exceptSessionId Id da sessão OIDC a preservar (a sessão corrente).
|
|
102
|
+
*/
|
|
103
|
+
revokeAllExcept(accountId: string, exceptSessionId: string): Promise<RevokeResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Revoga TODAS as sessões e grants da conta. Destruir os grants já invalida os
|
|
106
|
+
* tokens (cascata via `grant not found`); ainda assim, quando o adapter enumera,
|
|
107
|
+
* destruímos explicitamente as linhas de AT/RT desses grants (belt-and-braces),
|
|
108
|
+
* deixando o store limpo. Retorna as contagens do que foi removido.
|
|
109
|
+
*/
|
|
110
|
+
revokeAll(accountId: string): Promise<RevokeResult>;
|
|
111
|
+
/**
|
|
112
|
+
* Revoga os grants de uma conta para UM client específico (+ tokens ligados),
|
|
113
|
+
* deixando os demais clients intactos. Reaproveita a lógica de {@link revokeAll}
|
|
114
|
+
* restrita ao `clientId`. Usado pelo self-service de consentimento
|
|
115
|
+
* (/account/apps) e por qualquer revogação granular do admin. Retorna as
|
|
116
|
+
* contagens do que foi removido.
|
|
117
|
+
*/
|
|
118
|
+
revokeClientGrants(accountId: string, clientId: string): Promise<RevokeResult>;
|
|
119
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serviço de inspeção/revogação das SESSÕES e GRANTS ativos de uma conta,
|
|
3
|
+
* persistidos pelo oidc-provider via o MESMO `AdapterClass` (mesmo padrão do
|
|
4
|
+
* {@link AdminClientsService}). Encapsula:
|
|
5
|
+
* - a enumeração via a capacidade opcional `list` do adapter (degrada quando
|
|
6
|
+
* ausente, igual ao CRUD de clients);
|
|
7
|
+
* - a destruição das sessões + grants da conta. Destruir um grant CASCATEIA a
|
|
8
|
+
* invalidação dos tokens no oidc-provider: os consumidores de access/refresh
|
|
9
|
+
* token carregam `Grant.find(token.grantId)` e lançam `InvalidToken('grant not
|
|
10
|
+
* found')` quando o grant some (verificado em oidc-provider v9). Mesmo assim,
|
|
11
|
+
* por garantia (belt-and-braces), também destruímos as linhas de AT/RT que
|
|
12
|
+
* referenciam os grants revogados quando o adapter enumera.
|
|
13
|
+
*/
|
|
14
|
+
/** Limite máximo de sessões retornadas na listagem global (proteção contra explosão de memória). */
|
|
15
|
+
const GLOBAL_SESSION_LIMIT = 500;
|
|
16
|
+
export class AdminSessionsService {
|
|
17
|
+
#AdapterClass;
|
|
18
|
+
#accountStore;
|
|
19
|
+
/** Conexão Lucid das tabelas authkit (schema `auth`) — onde vive auth_session_revocations. */
|
|
20
|
+
#schemaConnection;
|
|
21
|
+
constructor(oidc) {
|
|
22
|
+
this.#AdapterClass = oidc.config.AdapterClass;
|
|
23
|
+
this.#accountStore = oidc.config.accountStore;
|
|
24
|
+
this.#schemaConnection = oidc.config.schema?.connection;
|
|
25
|
+
}
|
|
26
|
+
#adapter(model) {
|
|
27
|
+
return new this.#AdapterClass(model);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Grava uma revogação por `sub` na tabela compartilhada `auth_session_revocations`,
|
|
31
|
+
* para que clients COOKIE-BASED (que não têm store de sessão server-side) derrubem
|
|
32
|
+
* a sessão na próxima request — INSTANTÂNEO, sem esperar o refresh token falhar.
|
|
33
|
+
*
|
|
34
|
+
* Best-effort: a destruição de grants/tokens acima já é a fonte da verdade; esta
|
|
35
|
+
* linha só acelera o efeito nos clients. Falha (tabela ausente) é silenciosa.
|
|
36
|
+
*
|
|
37
|
+
* @param accountId Conta cujas sessões devem ser derrubadas (gravado em `sub`).
|
|
38
|
+
* @param revokedAt Timestamp da revogação. Default: agora. A checagem do client
|
|
39
|
+
* é `revoked_at >= iat(id_token)` (em segundos): uma sessão só é derrubada se
|
|
40
|
+
* foi estabelecida ANTES (ou no mesmo segundo) da revogação. O
|
|
41
|
+
* {@link revokeAllExcept} passa um `revokedAt` ANTERIOR ao `iat` da sessão
|
|
42
|
+
* PRESERVADA, para que esta NÃO se auto-derrube (ver lá).
|
|
43
|
+
*/
|
|
44
|
+
async recordSubRevocation(accountId, revokedAt = new Date()) {
|
|
45
|
+
try {
|
|
46
|
+
const db = (await import('@adonisjs/lucid/services/db')).default;
|
|
47
|
+
const conn = this.#schemaConnection
|
|
48
|
+
? db.connection(this.#schemaConnection)
|
|
49
|
+
: db.connection();
|
|
50
|
+
await conn.insertQuery().table('auth_session_revocations').insert({
|
|
51
|
+
sid: null,
|
|
52
|
+
sub: accountId,
|
|
53
|
+
revoked_at: revokedAt,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
/* tabela ausente / lucid indisponível — a invalidação server-side ainda vale */
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Indica se o adapter suporta enumeração (capacidade opcional). */
|
|
61
|
+
get canList() {
|
|
62
|
+
return typeof this.#adapter('Session').list === 'function';
|
|
63
|
+
}
|
|
64
|
+
async #listModel(model) {
|
|
65
|
+
const adapter = this.#adapter(model);
|
|
66
|
+
if (!adapter.list)
|
|
67
|
+
return [];
|
|
68
|
+
return adapter.list();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Conta TODAS as sessões ativas do IdP (todas as contas). 0 quando o adapter não
|
|
72
|
+
* enumera. Usado pelo dashboard de métricas.
|
|
73
|
+
*/
|
|
74
|
+
async countActiveSessions() {
|
|
75
|
+
const rows = await this.#listModel('Session');
|
|
76
|
+
return rows.length;
|
|
77
|
+
}
|
|
78
|
+
/** Lista as sessões ativas da conta (vazio quando o adapter não enumera). */
|
|
79
|
+
async listSessions(accountId) {
|
|
80
|
+
const rows = await this.#listModel('Session');
|
|
81
|
+
return rows
|
|
82
|
+
.filter((r) => r.payload.accountId === accountId)
|
|
83
|
+
.map((r) => ({
|
|
84
|
+
id: r.id,
|
|
85
|
+
accountId,
|
|
86
|
+
loginTs: r.payload.loginTs,
|
|
87
|
+
amr: r.payload.amr ?? undefined,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Lista TODAS as sessões ativas de TODAS as contas — usada pela listagem global
|
|
92
|
+
* do console admin (sem `accountId`). Resolve o email de cada conta via
|
|
93
|
+
* `accountStore.findById` com cache por id (evita N+1). Limita a
|
|
94
|
+
* {@link GLOBAL_SESSION_LIMIT} entradas; quando truncado, inclui `truncated:true`
|
|
95
|
+
* nos metadados (accessível via `result.truncated`). Retorna vazio quando o
|
|
96
|
+
* adapter não enumera.
|
|
97
|
+
*/
|
|
98
|
+
async listAllSessions() {
|
|
99
|
+
const rows = await this.#listModel('Session');
|
|
100
|
+
const truncated = rows.length > GLOBAL_SESSION_LIMIT;
|
|
101
|
+
const slice = truncated ? rows.slice(0, GLOBAL_SESSION_LIMIT) : rows;
|
|
102
|
+
// Cache accountId → email para evitar N+1
|
|
103
|
+
const emailCache = new Map();
|
|
104
|
+
const resolveEmail = async (accountId) => {
|
|
105
|
+
if (emailCache.has(accountId))
|
|
106
|
+
return emailCache.get(accountId);
|
|
107
|
+
const account = await this.#accountStore.findById(accountId);
|
|
108
|
+
const email = account?.email ?? null;
|
|
109
|
+
emailCache.set(accountId, email);
|
|
110
|
+
return email;
|
|
111
|
+
};
|
|
112
|
+
const sessions = await Promise.all(slice.map(async (r) => {
|
|
113
|
+
const accountId = r.payload.accountId ?? '';
|
|
114
|
+
const email = accountId ? await resolveEmail(accountId) : null;
|
|
115
|
+
return {
|
|
116
|
+
id: r.id,
|
|
117
|
+
accountId,
|
|
118
|
+
email,
|
|
119
|
+
loginTs: r.payload.loginTs,
|
|
120
|
+
amr: r.payload.amr ?? undefined,
|
|
121
|
+
};
|
|
122
|
+
}));
|
|
123
|
+
return { sessions, truncated };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Lista os grants da conta, com a contagem de access/refresh tokens vivos que
|
|
127
|
+
* referenciam cada grant (`payload.grantId`). As contagens são baratas (uma
|
|
128
|
+
* enumeração de cada model token), feitas só quando o adapter enumera.
|
|
129
|
+
*/
|
|
130
|
+
async listGrants(accountId) {
|
|
131
|
+
const rows = await this.#listModel('Grant');
|
|
132
|
+
const grants = rows.filter((r) => r.payload.accountId === accountId);
|
|
133
|
+
if (grants.length === 0)
|
|
134
|
+
return [];
|
|
135
|
+
const atByGrant = await this.#countByGrant('AccessToken');
|
|
136
|
+
const rtByGrant = await this.#countByGrant('RefreshToken');
|
|
137
|
+
return grants.map((g) => ({
|
|
138
|
+
id: g.id,
|
|
139
|
+
accountId,
|
|
140
|
+
clientId: g.payload.clientId,
|
|
141
|
+
accessTokens: atByGrant.get(g.id) ?? 0,
|
|
142
|
+
refreshTokens: rtByGrant.get(g.id) ?? 0,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
/** Conta artefatos de um model token agrupados por `grantId`. */
|
|
146
|
+
async #countByGrant(model) {
|
|
147
|
+
const rows = await this.#listModel(model);
|
|
148
|
+
const map = new Map();
|
|
149
|
+
for (const r of rows) {
|
|
150
|
+
const gid = r.payload.grantId;
|
|
151
|
+
if (!gid)
|
|
152
|
+
continue;
|
|
153
|
+
map.set(gid, (map.get(gid) ?? 0) + 1);
|
|
154
|
+
}
|
|
155
|
+
return map;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Revoga todas as sessões e grants da conta EXCETO a sessão corrente (pelo id).
|
|
159
|
+
* Usado pela política single-session: após login, revoga todas as outras sessões
|
|
160
|
+
* preservando a recém-criada. Retorna as contagens do que foi removido.
|
|
161
|
+
*
|
|
162
|
+
* @param accountId Id da conta.
|
|
163
|
+
* @param exceptSessionId Id da sessão OIDC a preservar (a sessão corrente).
|
|
164
|
+
*/
|
|
165
|
+
async revokeAllExcept(accountId, exceptSessionId) {
|
|
166
|
+
const sessionAdapter = this.#adapter('Session');
|
|
167
|
+
const grantAdapter = this.#adapter('Grant');
|
|
168
|
+
const sessions = await this.listSessions(accountId);
|
|
169
|
+
const preserved = sessions.find((s) => s.id === exceptSessionId);
|
|
170
|
+
const sessionsToRevoke = sessions.filter((s) => s.id !== exceptSessionId);
|
|
171
|
+
for (const s of sessionsToRevoke) {
|
|
172
|
+
await sessionAdapter.destroy(s.id);
|
|
173
|
+
}
|
|
174
|
+
// Revogamos todos os grants da conta (que pertencem à conta, não à sessão
|
|
175
|
+
// específica). A sessão corrente gerará novos grants no próximo authorize.
|
|
176
|
+
// Isso garante que sessões antigas não mantenham tokens vivos.
|
|
177
|
+
const grants = await this.listGrants(accountId);
|
|
178
|
+
const grantIds = new Set(grants.map((g) => g.id));
|
|
179
|
+
let accessTokens = 0;
|
|
180
|
+
let refreshTokens = 0;
|
|
181
|
+
accessTokens = await this.#destroyTokensOfGrants('AccessToken', grantIds);
|
|
182
|
+
refreshTokens = await this.#destroyTokensOfGrants('RefreshToken', grantIds);
|
|
183
|
+
for (const g of grants) {
|
|
184
|
+
await grantAdapter.revokeByGrantId(g.id);
|
|
185
|
+
await grantAdapter.destroy(g.id);
|
|
186
|
+
}
|
|
187
|
+
// M7: propaga a revogação por `sub` para clients COOKIE-BASED (instantâneo),
|
|
188
|
+
// igual ao revokeAll. Sem isto, o 1º dispositivo só cai quando o AT expira.
|
|
189
|
+
//
|
|
190
|
+
// Ordem do `iat` (CUIDADO): a sessão PRESERVADA já existe aqui (foi criada no
|
|
191
|
+
// completeLogin ANTES desta revogação), com `loginTs` (== iat do id_token) em
|
|
192
|
+
// segundos. A checagem do client é `revoked_at >= iat`. Se gravássemos
|
|
193
|
+
// `revoked_at = now`, como `now >= iat_preservada`, a sessão NOVA se
|
|
194
|
+
// auto-derrubaria. Por isso ancoramos `revoked_at` ESTRITAMENTE ANTES do
|
|
195
|
+
// `iat` da sessão preservada (`loginTs - 1s`): as sessões antigas (iat menor)
|
|
196
|
+
// continuam sendo apanhadas (`revoked_at >= iat_antiga`), enquanto a nova
|
|
197
|
+
// (iat = loginTs) sobrevive (`revoked_at < iat_nova`).
|
|
198
|
+
//
|
|
199
|
+
// Sem sessão preservada (exceptSessionId não encontrado / sem loginTs), caímos
|
|
200
|
+
// no default (`now`) — não há sessão nova a proteger nesse caminho.
|
|
201
|
+
const cutoff = typeof preserved?.loginTs === 'number'
|
|
202
|
+
? new Date((preserved.loginTs - 1) * 1000)
|
|
203
|
+
: undefined;
|
|
204
|
+
await this.recordSubRevocation(accountId, cutoff);
|
|
205
|
+
return {
|
|
206
|
+
sessions: sessionsToRevoke.length,
|
|
207
|
+
grants: grants.length,
|
|
208
|
+
accessTokens,
|
|
209
|
+
refreshTokens,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Revoga TODAS as sessões e grants da conta. Destruir os grants já invalida os
|
|
214
|
+
* tokens (cascata via `grant not found`); ainda assim, quando o adapter enumera,
|
|
215
|
+
* destruímos explicitamente as linhas de AT/RT desses grants (belt-and-braces),
|
|
216
|
+
* deixando o store limpo. Retorna as contagens do que foi removido.
|
|
217
|
+
*/
|
|
218
|
+
async revokeAll(accountId) {
|
|
219
|
+
const sessionAdapter = this.#adapter('Session');
|
|
220
|
+
const grantAdapter = this.#adapter('Grant');
|
|
221
|
+
const sessions = await this.listSessions(accountId);
|
|
222
|
+
for (const s of sessions) {
|
|
223
|
+
await sessionAdapter.destroy(s.id);
|
|
224
|
+
}
|
|
225
|
+
const grants = await this.listGrants(accountId);
|
|
226
|
+
const grantIds = new Set(grants.map((g) => g.id));
|
|
227
|
+
let accessTokens = 0;
|
|
228
|
+
let refreshTokens = 0;
|
|
229
|
+
// Belt-and-braces: destrói as linhas de token que referenciam os grants alvo
|
|
230
|
+
// ANTES de destruir os grants (quando o adapter enumera).
|
|
231
|
+
accessTokens = await this.#destroyTokensOfGrants('AccessToken', grantIds);
|
|
232
|
+
refreshTokens = await this.#destroyTokensOfGrants('RefreshToken', grantIds);
|
|
233
|
+
for (const g of grants) {
|
|
234
|
+
// `revokeByGrantId` derruba os artefatos ligados ao grant (no Redis isso
|
|
235
|
+
// limpa a lista do grant; no DB apaga as linhas com `grant_id`); `destroy`
|
|
236
|
+
// remove o próprio artefato `Grant`.
|
|
237
|
+
await grantAdapter.revokeByGrantId(g.id);
|
|
238
|
+
await grantAdapter.destroy(g.id);
|
|
239
|
+
}
|
|
240
|
+
// Revogação total → propaga p/ clients cookie-based via tabela compartilhada (instantâneo).
|
|
241
|
+
await this.recordSubRevocation(accountId);
|
|
242
|
+
return {
|
|
243
|
+
sessions: sessions.length,
|
|
244
|
+
grants: grants.length,
|
|
245
|
+
accessTokens,
|
|
246
|
+
refreshTokens,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Revoga os grants de uma conta para UM client específico (+ tokens ligados),
|
|
251
|
+
* deixando os demais clients intactos. Reaproveita a lógica de {@link revokeAll}
|
|
252
|
+
* restrita ao `clientId`. Usado pelo self-service de consentimento
|
|
253
|
+
* (/account/apps) e por qualquer revogação granular do admin. Retorna as
|
|
254
|
+
* contagens do que foi removido.
|
|
255
|
+
*/
|
|
256
|
+
async revokeClientGrants(accountId, clientId) {
|
|
257
|
+
const grantAdapter = this.#adapter('Grant');
|
|
258
|
+
const grants = (await this.listGrants(accountId)).filter((g) => g.clientId === clientId);
|
|
259
|
+
const grantIds = new Set(grants.map((g) => g.id));
|
|
260
|
+
const accessTokens = await this.#destroyTokensOfGrants('AccessToken', grantIds);
|
|
261
|
+
const refreshTokens = await this.#destroyTokensOfGrants('RefreshToken', grantIds);
|
|
262
|
+
for (const g of grants) {
|
|
263
|
+
await grantAdapter.revokeByGrantId(g.id);
|
|
264
|
+
await grantAdapter.destroy(g.id);
|
|
265
|
+
}
|
|
266
|
+
return { sessions: 0, grants: grants.length, accessTokens, refreshTokens };
|
|
267
|
+
}
|
|
268
|
+
/** Destrói (quando enumerável) os artefatos de um model token cujos grantId estão em `grantIds`. */
|
|
269
|
+
async #destroyTokensOfGrants(model, grantIds) {
|
|
270
|
+
const adapter = this.#adapter(model);
|
|
271
|
+
if (!adapter.list)
|
|
272
|
+
return 0;
|
|
273
|
+
const rows = await adapter.list();
|
|
274
|
+
let count = 0;
|
|
275
|
+
for (const r of rows) {
|
|
276
|
+
const gid = r.payload.grantId;
|
|
277
|
+
if (gid && grantIds.has(gid)) {
|
|
278
|
+
await adapter.destroy(r.id);
|
|
279
|
+
count++;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return count;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ResolvedServerConfig } from '../define_config.js';
|
|
2
|
+
/** Um ponto de série diária (dia ISO `YYYY-MM-DD` + contagem). */
|
|
3
|
+
export interface DailyPoint {
|
|
4
|
+
/** Data no formato `YYYY-MM-DD` (UTC). */
|
|
5
|
+
date: string;
|
|
6
|
+
count: number;
|
|
7
|
+
}
|
|
8
|
+
/** Métricas-resumo do IdP para o dashboard do console admin. */
|
|
9
|
+
export interface AdminStats {
|
|
10
|
+
/** Total de contas (do accountStore). */
|
|
11
|
+
totalUsers: number;
|
|
12
|
+
/** Sessões ativas (Session enumeradas no adapter); null quando o adapter não enumera. */
|
|
13
|
+
activeSessions: number | null;
|
|
14
|
+
/** Monthly Active Users: contas únicas com login.success nos últimos 30 dias. */
|
|
15
|
+
mau: number;
|
|
16
|
+
/** Sign-ins por dia (login.success) nos últimos 30 dias. */
|
|
17
|
+
signInsPerDay: DailyPoint[];
|
|
18
|
+
/** Sign-ups por dia (signup) nos últimos 30 dias. */
|
|
19
|
+
signUpsPerDay: DailyPoint[];
|
|
20
|
+
/** Total de sign-ins na janela de 30 dias. */
|
|
21
|
+
signInsTotal: number;
|
|
22
|
+
/** Total de sign-ups na janela de 30 dias. */
|
|
23
|
+
signUpsTotal: number;
|
|
24
|
+
/** Indica se o audit suporta consulta (`list`). Quando false, as séries vêm vazias. */
|
|
25
|
+
auditSupported: boolean;
|
|
26
|
+
/** Quantos dias a janela cobre (30). */
|
|
27
|
+
windowDays: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Agrega métricas do IdP para o dashboard. CAPABILITY-PROBED: a fonte das séries é
|
|
31
|
+
* o audit store via `list` — quando ausente, as séries/MAU degradam para vazio/0 e
|
|
32
|
+
* `auditSupported=false` (a UI mostra "consulta não suportada"). As sessões ativas
|
|
33
|
+
* vêm da enumeração do adapter OIDC (null quando o adapter não enumera).
|
|
34
|
+
*
|
|
35
|
+
* LIMITAÇÃO: a agregação é em memória sobre as {@link MAX_EVENTS} linhas mais
|
|
36
|
+
* recentes de cada tipo (o `AuditSink` não expõe agregação por dia/distinct). Em
|
|
37
|
+
* volumes muito altos a janela pode não cobrir os 30 dias inteiros; documentado e
|
|
38
|
+
* suficiente para um dashboard. Um sink customizado pode implementar agregação
|
|
39
|
+
* nativa e expor um `stats()` próprio no futuro.
|
|
40
|
+
*/
|
|
41
|
+
export declare function computeAdminStats(cfg: Pick<ResolvedServerConfig, 'audit' | 'accountStore'>, sessionsService: {
|
|
42
|
+
canList: boolean;
|
|
43
|
+
countActiveSessions(): Promise<number>;
|
|
44
|
+
}): Promise<AdminStats>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/** Janela de agregação (dias). */
|
|
2
|
+
const WINDOW_DAYS = 30;
|
|
3
|
+
/**
|
|
4
|
+
* Teto de eventos lidos do audit por tipo na agregação em memória. O sink default
|
|
5
|
+
* (Lucid) não tem agregação SQL exposta, então listamos as N linhas mais recentes e
|
|
6
|
+
* agregamos aqui. 10000 cobre ~333 logins/dia por 30 dias com folga.
|
|
7
|
+
*/
|
|
8
|
+
const MAX_EVENTS = 10000;
|
|
9
|
+
/**
|
|
10
|
+
* Agrega métricas do IdP para o dashboard. CAPABILITY-PROBED: a fonte das séries é
|
|
11
|
+
* o audit store via `list` — quando ausente, as séries/MAU degradam para vazio/0 e
|
|
12
|
+
* `auditSupported=false` (a UI mostra "consulta não suportada"). As sessões ativas
|
|
13
|
+
* vêm da enumeração do adapter OIDC (null quando o adapter não enumera).
|
|
14
|
+
*
|
|
15
|
+
* LIMITAÇÃO: a agregação é em memória sobre as {@link MAX_EVENTS} linhas mais
|
|
16
|
+
* recentes de cada tipo (o `AuditSink` não expõe agregação por dia/distinct). Em
|
|
17
|
+
* volumes muito altos a janela pode não cobrir os 30 dias inteiros; documentado e
|
|
18
|
+
* suficiente para um dashboard. Um sink customizado pode implementar agregação
|
|
19
|
+
* nativa e expor um `stats()` próprio no futuro.
|
|
20
|
+
*/
|
|
21
|
+
export async function computeAdminStats(cfg, sessionsService) {
|
|
22
|
+
const totalUsers = (await cfg.accountStore.listAccounts({ page: 1, limit: 1 })).total;
|
|
23
|
+
const activeSessions = sessionsService.canList
|
|
24
|
+
? await sessionsService.countActiveSessions()
|
|
25
|
+
: null;
|
|
26
|
+
const auditSupported = typeof cfg.audit?.list === 'function';
|
|
27
|
+
if (!auditSupported) {
|
|
28
|
+
return {
|
|
29
|
+
totalUsers,
|
|
30
|
+
activeSessions,
|
|
31
|
+
mau: 0,
|
|
32
|
+
signInsPerDay: emptySeries(),
|
|
33
|
+
signUpsPerDay: emptySeries(),
|
|
34
|
+
signInsTotal: 0,
|
|
35
|
+
signUpsTotal: 0,
|
|
36
|
+
auditSupported: false,
|
|
37
|
+
windowDays: WINDOW_DAYS,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const windowStartMs = startOfWindowMs();
|
|
41
|
+
const signIns = await loadEventsInWindow(cfg.audit, 'login.success', windowStartMs);
|
|
42
|
+
const signUps = await loadEventsInWindow(cfg.audit, 'signup', windowStartMs);
|
|
43
|
+
// MAU: contas únicas com algum login.success na janela.
|
|
44
|
+
const mauSet = new Set();
|
|
45
|
+
for (const e of signIns) {
|
|
46
|
+
if (e.accountId)
|
|
47
|
+
mauSet.add(e.accountId);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
totalUsers,
|
|
51
|
+
activeSessions,
|
|
52
|
+
mau: mauSet.size,
|
|
53
|
+
signInsPerDay: bucketByDay(signIns),
|
|
54
|
+
signUpsPerDay: bucketByDay(signUps),
|
|
55
|
+
signInsTotal: signIns.length,
|
|
56
|
+
signUpsTotal: signUps.length,
|
|
57
|
+
auditSupported: true,
|
|
58
|
+
windowDays: WINDOW_DAYS,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Carrega (paginando) os eventos de um tipo dentro da janela, com teto de
|
|
63
|
+
* {@link MAX_EVENTS}. Para assim que a página vier mais antiga que a janela (o sink
|
|
64
|
+
* lista desc por createdAt) ou ao atingir o teto.
|
|
65
|
+
*/
|
|
66
|
+
async function loadEventsInWindow(audit, type, windowStartMs) {
|
|
67
|
+
const out = [];
|
|
68
|
+
const limit = 200;
|
|
69
|
+
let page = 1;
|
|
70
|
+
while (out.length < MAX_EVENTS) {
|
|
71
|
+
const result = await audit.list({ type, page, limit });
|
|
72
|
+
if (result.data.length === 0)
|
|
73
|
+
break;
|
|
74
|
+
let allBelowWindow = true;
|
|
75
|
+
for (const e of result.data) {
|
|
76
|
+
const tsMs = toMs(e.createdAt);
|
|
77
|
+
if (tsMs === null)
|
|
78
|
+
continue;
|
|
79
|
+
if (tsMs >= windowStartMs) {
|
|
80
|
+
allBelowWindow = false;
|
|
81
|
+
out.push({ accountId: e.accountId ?? null, tsMs });
|
|
82
|
+
if (out.length >= MAX_EVENTS)
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Página inteira anterior à janela → não há mais nada relevante (ordem desc).
|
|
87
|
+
if (allBelowWindow)
|
|
88
|
+
break;
|
|
89
|
+
if (result.data.length < limit)
|
|
90
|
+
break;
|
|
91
|
+
page += 1;
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/** Agrupa eventos por dia (UTC `YYYY-MM-DD`), preenchendo TODOS os dias da janela com 0. */
|
|
96
|
+
function bucketByDay(events) {
|
|
97
|
+
const counts = new Map();
|
|
98
|
+
for (const e of events) {
|
|
99
|
+
const day = dayKey(e.tsMs);
|
|
100
|
+
counts.set(day, (counts.get(day) ?? 0) + 1);
|
|
101
|
+
}
|
|
102
|
+
return seriesDays().map((date) => ({ date, count: counts.get(date) ?? 0 }));
|
|
103
|
+
}
|
|
104
|
+
/** Série de 30 dias vazia (todos os dias com 0), p/ o degrade sem audit. */
|
|
105
|
+
function emptySeries() {
|
|
106
|
+
return seriesDays().map((date) => ({ date, count: 0 }));
|
|
107
|
+
}
|
|
108
|
+
/** Os WINDOW_DAYS dias da janela (do mais antigo ao hoje), `YYYY-MM-DD` UTC. */
|
|
109
|
+
function seriesDays() {
|
|
110
|
+
const days = [];
|
|
111
|
+
const todayMs = Date.now();
|
|
112
|
+
for (let i = WINDOW_DAYS - 1; i >= 0; i--) {
|
|
113
|
+
days.push(dayKey(todayMs - i * 86400000));
|
|
114
|
+
}
|
|
115
|
+
return days;
|
|
116
|
+
}
|
|
117
|
+
function startOfWindowMs() {
|
|
118
|
+
// Início (00:00 UTC) do primeiro dia da janela.
|
|
119
|
+
const firstDay = seriesDays()[0];
|
|
120
|
+
return Date.parse(`${firstDay}T00:00:00.000Z`);
|
|
121
|
+
}
|
|
122
|
+
function dayKey(ms) {
|
|
123
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
124
|
+
}
|
|
125
|
+
function toMs(createdAt) {
|
|
126
|
+
if (!createdAt)
|
|
127
|
+
return null;
|
|
128
|
+
const ms = createdAt instanceof Date ? createdAt.getTime() : Date.parse(createdAt);
|
|
129
|
+
return Number.isFinite(ms) ? ms : null;
|
|
130
|
+
}
|