@portaidentity/server 1.7.3 → 1.8.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/CHANGELOG.md +5 -0
- package/dist/applications/index.d.ts +2 -2
- package/dist/applications/index.d.ts.map +1 -1
- package/dist/applications/index.js +2 -2
- package/dist/applications/index.js.map +1 -1
- package/dist/applications/repository.d.ts +49 -4
- package/dist/applications/repository.d.ts.map +1 -1
- package/dist/applications/repository.js +148 -10
- package/dist/applications/repository.js.map +1 -1
- package/dist/applications/service.d.ts +35 -17
- package/dist/applications/service.d.ts.map +1 -1
- package/dist/applications/service.js +144 -35
- package/dist/applications/service.js.map +1 -1
- package/dist/applications/types.d.ts +1 -1
- package/dist/applications/types.d.ts.map +1 -1
- package/dist/applications/validators.d.ts +14 -0
- package/dist/applications/validators.d.ts.map +1 -0
- package/dist/applications/validators.js +14 -0
- package/dist/applications/validators.js.map +1 -0
- package/dist/auth/effective-branding.d.ts +35 -0
- package/dist/auth/effective-branding.d.ts.map +1 -0
- package/dist/auth/effective-branding.js +81 -0
- package/dist/auth/effective-branding.js.map +1 -0
- package/dist/auth/email-service.d.ts +3 -8
- package/dist/auth/email-service.d.ts.map +1 -1
- package/dist/auth/email-service.js +22 -30
- package/dist/auth/email-service.js.map +1 -1
- package/dist/auth/i18n.d.ts +5 -0
- package/dist/auth/i18n.d.ts.map +1 -1
- package/dist/auth/i18n.js +6 -5
- package/dist/auth/i18n.js.map +1 -1
- package/dist/auth/rate-limiter.d.ts +6 -10
- package/dist/auth/rate-limiter.d.ts.map +1 -1
- package/dist/auth/rate-limiter.js +12 -16
- package/dist/auth/rate-limiter.js.map +1 -1
- package/dist/auth/recovery-job-processor.d.ts.map +1 -1
- package/dist/auth/recovery-job-processor.js +1 -1
- package/dist/auth/recovery-job-processor.js.map +1 -1
- package/dist/auth/template-engine.d.ts +3 -1
- package/dist/auth/template-engine.d.ts.map +1 -1
- package/dist/auth/template-engine.js +1 -1
- package/dist/auth/template-engine.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +12 -12
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/error-handler.d.ts +3 -2
- package/dist/cli/error-handler.d.ts.map +1 -1
- package/dist/cli/error-handler.js +9 -2
- package/dist/cli/error-handler.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/clients/index.d.ts +1 -1
- package/dist/clients/index.js +1 -1
- package/dist/clients/repository.d.ts +18 -0
- package/dist/clients/repository.d.ts.map +1 -1
- package/dist/clients/repository.js +36 -0
- package/dist/clients/repository.js.map +1 -1
- package/dist/clients/secret-repository.d.ts +35 -8
- package/dist/clients/secret-repository.d.ts.map +1 -1
- package/dist/clients/secret-repository.js +69 -16
- package/dist/clients/secret-repository.js.map +1 -1
- package/dist/clients/secret-service.d.ts +5 -9
- package/dist/clients/secret-service.d.ts.map +1 -1
- package/dist/clients/secret-service.js +13 -22
- package/dist/clients/secret-service.js.map +1 -1
- package/dist/clients/service.d.ts +10 -13
- package/dist/clients/service.d.ts.map +1 -1
- package/dist/clients/service.js +112 -40
- package/dist/clients/service.js.map +1 -1
- package/dist/clients/types.d.ts +1 -1
- package/dist/clients/types.d.ts.map +1 -1
- package/dist/clients/validators.d.ts +83 -1
- package/dist/clients/validators.d.ts.map +1 -1
- package/dist/clients/validators.js +110 -0
- package/dist/clients/validators.js.map +1 -1
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +23 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/custom-claims/repository.d.ts +14 -9
- package/dist/custom-claims/repository.d.ts.map +1 -1
- package/dist/custom-claims/repository.js +38 -11
- package/dist/custom-claims/repository.js.map +1 -1
- package/dist/custom-claims/service.d.ts +11 -6
- package/dist/custom-claims/service.d.ts.map +1 -1
- package/dist/custom-claims/service.js +43 -20
- package/dist/custom-claims/service.js.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/admin-permissions.d.ts +12 -7
- package/dist/lib/admin-permissions.d.ts.map +1 -1
- package/dist/lib/admin-permissions.js +26 -16
- package/dist/lib/admin-permissions.js.map +1 -1
- package/dist/lib/audit-log.d.ts +2 -2
- package/dist/lib/audit-log.d.ts.map +1 -1
- package/dist/lib/audit-log.js +1 -1
- package/dist/lib/audit-log.js.map +1 -1
- package/dist/lib/authority-revocation.d.ts +18 -0
- package/dist/lib/authority-revocation.d.ts.map +1 -0
- package/dist/lib/authority-revocation.js +37 -0
- package/dist/lib/authority-revocation.js.map +1 -0
- package/dist/lib/branding-assets.d.ts +35 -5
- package/dist/lib/branding-assets.d.ts.map +1 -1
- package/dist/lib/branding-assets.js +33 -26
- package/dist/lib/branding-assets.js.map +1 -1
- package/dist/lib/bulk-operations.d.ts +1 -1
- package/dist/lib/bulk-operations.d.ts.map +1 -1
- package/dist/lib/bulk-operations.js +1 -13
- package/dist/lib/bulk-operations.js.map +1 -1
- package/dist/lib/cursor.d.ts +2 -0
- package/dist/lib/cursor.d.ts.map +1 -1
- package/dist/lib/cursor.js +2 -7
- package/dist/lib/cursor.js.map +1 -1
- package/dist/lib/database.d.ts.map +1 -1
- package/dist/lib/database.js +5 -0
- package/dist/lib/database.js.map +1 -1
- package/dist/lib/deletion-cleanup.d.ts +43 -0
- package/dist/lib/deletion-cleanup.d.ts.map +1 -0
- package/dist/lib/deletion-cleanup.js +207 -0
- package/dist/lib/deletion-cleanup.js.map +1 -0
- package/dist/lib/image-validator.d.ts +3 -1
- package/dist/lib/image-validator.d.ts.map +1 -1
- package/dist/lib/image-validator.js +32 -19
- package/dist/lib/image-validator.js.map +1 -1
- package/dist/lib/log-format.d.ts +20 -0
- package/dist/lib/log-format.d.ts.map +1 -0
- package/dist/lib/log-format.js +22 -0
- package/dist/lib/log-format.js.map +1 -0
- package/dist/lib/logger.d.ts +3 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +21 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/redis.d.ts.map +1 -1
- package/dist/lib/redis.js +3 -0
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/session-tracking.d.ts +73 -11
- package/dist/lib/session-tracking.d.ts.map +1 -1
- package/dist/lib/session-tracking.js +76 -32
- package/dist/lib/session-tracking.js.map +1 -1
- package/dist/lib/signing-key-crypto.d.ts.map +1 -1
- package/dist/lib/signing-key-crypto.js +4 -5
- package/dist/lib/signing-key-crypto.js.map +1 -1
- package/dist/lib/signing-keys.d.ts +3 -4
- package/dist/lib/signing-keys.d.ts.map +1 -1
- package/dist/lib/signing-keys.js +66 -41
- package/dist/lib/signing-keys.js.map +1 -1
- package/dist/lib/super-admin-protection.d.ts +5 -5
- package/dist/lib/super-admin-protection.d.ts.map +1 -1
- package/dist/lib/super-admin-protection.js +6 -9
- package/dist/lib/super-admin-protection.js.map +1 -1
- package/dist/lib/system-config-catalog.d.ts +268 -0
- package/dist/lib/system-config-catalog.d.ts.map +1 -0
- package/dist/lib/system-config-catalog.js +90 -0
- package/dist/lib/system-config-catalog.js.map +1 -0
- package/dist/lib/system-config.d.ts +30 -33
- package/dist/lib/system-config.d.ts.map +1 -1
- package/dist/lib/system-config.js +78 -93
- package/dist/lib/system-config.js.map +1 -1
- package/dist/lib/with-timeout.d.ts +32 -0
- package/dist/lib/with-timeout.d.ts.map +1 -0
- package/dist/lib/with-timeout.js +45 -0
- package/dist/lib/with-timeout.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +6 -5
- package/dist/middleware/admin-auth.d.ts.map +1 -1
- package/dist/middleware/admin-auth.js +30 -20
- package/dist/middleware/admin-auth.js.map +1 -1
- package/dist/middleware/admin-cors.d.ts +3 -3
- package/dist/middleware/admin-cors.js +3 -3
- package/dist/middleware/admin-mutation-audit.d.ts +3 -2
- package/dist/middleware/admin-mutation-audit.d.ts.map +1 -1
- package/dist/middleware/admin-mutation-audit.js +12 -5
- package/dist/middleware/admin-mutation-audit.js.map +1 -1
- package/dist/middleware/admin-rate-limiter.d.ts +7 -8
- package/dist/middleware/admin-rate-limiter.d.ts.map +1 -1
- package/dist/middleware/admin-rate-limiter.js +7 -8
- package/dist/middleware/admin-rate-limiter.js.map +1 -1
- package/dist/middleware/client-secret-hash.d.ts +10 -29
- package/dist/middleware/client-secret-hash.d.ts.map +1 -1
- package/dist/middleware/client-secret-hash.js +161 -59
- package/dist/middleware/client-secret-hash.js.map +1 -1
- package/dist/middleware/health.d.ts +17 -0
- package/dist/middleware/health.d.ts.map +1 -1
- package/dist/middleware/health.js +25 -21
- package/dist/middleware/health.js.map +1 -1
- package/dist/middleware/ready.d.ts.map +1 -1
- package/dist/middleware/ready.js +1 -12
- package/dist/middleware/ready.js.map +1 -1
- package/dist/middleware/require-existing-organization.d.ts +18 -0
- package/dist/middleware/require-existing-organization.d.ts.map +1 -0
- package/dist/middleware/require-existing-organization.js +38 -0
- package/dist/middleware/require-existing-organization.js.map +1 -0
- package/dist/middleware/require-permission.d.ts.map +1 -1
- package/dist/middleware/require-permission.js +35 -1
- package/dist/middleware/require-permission.js.map +1 -1
- package/dist/middleware/require-user-organization.d.ts.map +1 -1
- package/dist/middleware/require-user-organization.js +4 -2
- package/dist/middleware/require-user-organization.js.map +1 -1
- package/dist/middleware/security-headers.d.ts +18 -0
- package/dist/middleware/security-headers.d.ts.map +1 -1
- package/dist/middleware/security-headers.js +32 -1
- package/dist/middleware/security-headers.js.map +1 -1
- package/dist/middleware/tenant-resolver.d.ts +1 -2
- package/dist/middleware/tenant-resolver.d.ts.map +1 -1
- package/dist/middleware/tenant-resolver.js +1 -5
- package/dist/middleware/tenant-resolver.js.map +1 -1
- package/dist/middleware/token-rate-limiter.d.ts +37 -16
- package/dist/middleware/token-rate-limiter.d.ts.map +1 -1
- package/dist/middleware/token-rate-limiter.js +126 -54
- package/dist/middleware/token-rate-limiter.js.map +1 -1
- package/dist/oidc/account-finder.d.ts +5 -5
- package/dist/oidc/account-finder.d.ts.map +1 -1
- package/dist/oidc/account-finder.js +31 -23
- package/dist/oidc/account-finder.js.map +1 -1
- package/dist/oidc/adapter-factory.d.ts.map +1 -1
- package/dist/oidc/adapter-factory.js +83 -3
- package/dist/oidc/adapter-factory.js.map +1 -1
- package/dist/oidc/configuration.d.ts +3 -8
- package/dist/oidc/configuration.d.ts.map +1 -1
- package/dist/oidc/configuration.js +64 -50
- package/dist/oidc/configuration.js.map +1 -1
- package/dist/oidc/provider.d.ts.map +1 -1
- package/dist/oidc/provider.js +7 -0
- package/dist/oidc/provider.js.map +1 -1
- package/dist/oidc/redis-adapter.d.ts +2 -3
- package/dist/oidc/redis-adapter.d.ts.map +1 -1
- package/dist/oidc/redis-adapter.js +54 -46
- package/dist/oidc/redis-adapter.js.map +1 -1
- package/dist/organizations/branding-url.d.ts +17 -0
- package/dist/organizations/branding-url.d.ts.map +1 -0
- package/dist/organizations/branding-url.js +38 -0
- package/dist/organizations/branding-url.js.map +1 -0
- package/dist/organizations/index.d.ts +2 -2
- package/dist/organizations/index.d.ts.map +1 -1
- package/dist/organizations/index.js +1 -1
- package/dist/organizations/index.js.map +1 -1
- package/dist/organizations/repository.d.ts +22 -32
- package/dist/organizations/repository.d.ts.map +1 -1
- package/dist/organizations/repository.js +64 -45
- package/dist/organizations/repository.js.map +1 -1
- package/dist/organizations/service.d.ts +14 -46
- package/dist/organizations/service.d.ts.map +1 -1
- package/dist/organizations/service.js +60 -112
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +1 -15
- package/dist/organizations/types.d.ts.map +1 -1
- package/dist/organizations/validators.d.ts +41 -0
- package/dist/organizations/validators.d.ts.map +1 -0
- package/dist/organizations/validators.js +48 -0
- package/dist/organizations/validators.js.map +1 -0
- package/dist/portability/apply.d.ts +15 -0
- package/dist/portability/apply.d.ts.map +1 -0
- package/dist/portability/apply.js +274 -0
- package/dist/portability/apply.js.map +1 -0
- package/dist/portability/authorization.d.ts +30 -0
- package/dist/portability/authorization.d.ts.map +1 -0
- package/dist/portability/authorization.js +130 -0
- package/dist/portability/authorization.js.map +1 -0
- package/dist/portability/cleanup.d.ts +29 -0
- package/dist/portability/cleanup.d.ts.map +1 -0
- package/dist/portability/cleanup.js +167 -0
- package/dist/portability/cleanup.js.map +1 -0
- package/dist/portability/export.d.ts +18 -0
- package/dist/portability/export.d.ts.map +1 -0
- package/dist/portability/export.js +125 -0
- package/dist/portability/export.js.map +1 -0
- package/dist/portability/import-repository.d.ts +204 -0
- package/dist/portability/import-repository.d.ts.map +1 -0
- package/dist/portability/import-repository.js +347 -0
- package/dist/portability/import-repository.js.map +1 -0
- package/dist/portability/import-user-client-writers.d.ts +40 -0
- package/dist/portability/import-user-client-writers.d.ts.map +1 -0
- package/dist/portability/import-user-client-writers.js +168 -0
- package/dist/portability/import-user-client-writers.js.map +1 -0
- package/dist/portability/index.d.ts +8 -0
- package/dist/portability/index.d.ts.map +1 -0
- package/dist/portability/index.js +8 -0
- package/dist/portability/index.js.map +1 -0
- package/dist/portability/plan-support.d.ts +137 -0
- package/dist/portability/plan-support.d.ts.map +1 -0
- package/dist/portability/plan-support.js +336 -0
- package/dist/portability/plan-support.js.map +1 -0
- package/dist/portability/plan.d.ts +34 -0
- package/dist/portability/plan.d.ts.map +1 -0
- package/dist/portability/plan.js +450 -0
- package/dist/portability/plan.js.map +1 -0
- package/dist/portability/repository.d.ts +95 -0
- package/dist/portability/repository.d.ts.map +1 -0
- package/dist/portability/repository.js +388 -0
- package/dist/portability/repository.js.map +1 -0
- package/dist/portability/schema.d.ts +589 -0
- package/dist/portability/schema.d.ts.map +1 -0
- package/dist/portability/schema.js +458 -0
- package/dist/portability/schema.js.map +1 -0
- package/dist/portability/types.d.ts +381 -0
- package/dist/portability/types.d.ts.map +1 -0
- package/dist/portability/types.js +19 -0
- package/dist/portability/types.js.map +1 -0
- package/dist/rbac/errors.d.ts +4 -0
- package/dist/rbac/errors.d.ts.map +1 -1
- package/dist/rbac/errors.js +7 -0
- package/dist/rbac/errors.js.map +1 -1
- package/dist/rbac/index.d.ts +3 -3
- package/dist/rbac/index.d.ts.map +1 -1
- package/dist/rbac/index.js +3 -3
- package/dist/rbac/index.js.map +1 -1
- package/dist/rbac/mapping-repository.d.ts +84 -9
- package/dist/rbac/mapping-repository.d.ts.map +1 -1
- package/dist/rbac/mapping-repository.js +222 -55
- package/dist/rbac/mapping-repository.js.map +1 -1
- package/dist/rbac/permission-repository.d.ts +36 -19
- package/dist/rbac/permission-repository.d.ts.map +1 -1
- package/dist/rbac/permission-repository.js +93 -35
- package/dist/rbac/permission-repository.js.map +1 -1
- package/dist/rbac/permission-service.d.ts +18 -19
- package/dist/rbac/permission-service.d.ts.map +1 -1
- package/dist/rbac/permission-service.js +100 -57
- package/dist/rbac/permission-service.js.map +1 -1
- package/dist/rbac/role-repository.d.ts +29 -24
- package/dist/rbac/role-repository.d.ts.map +1 -1
- package/dist/rbac/role-repository.js +66 -43
- package/dist/rbac/role-repository.js.map +1 -1
- package/dist/rbac/role-service.d.ts +35 -32
- package/dist/rbac/role-service.d.ts.map +1 -1
- package/dist/rbac/role-service.js +210 -96
- package/dist/rbac/role-service.js.map +1 -1
- package/dist/rbac/slugs.d.ts +16 -27
- package/dist/rbac/slugs.d.ts.map +1 -1
- package/dist/rbac/slugs.js +36 -59
- package/dist/rbac/slugs.js.map +1 -1
- package/dist/rbac/types.d.ts +2 -4
- package/dist/rbac/types.d.ts.map +1 -1
- package/dist/rbac/types.js.map +1 -1
- package/dist/rbac/user-role-service.d.ts +23 -24
- package/dist/rbac/user-role-service.d.ts.map +1 -1
- package/dist/rbac/user-role-service.js +117 -61
- package/dist/rbac/user-role-service.js.map +1 -1
- package/dist/routes/applications.d.ts +4 -2
- package/dist/routes/applications.d.ts.map +1 -1
- package/dist/routes/applications.js +57 -19
- package/dist/routes/applications.js.map +1 -1
- package/dist/routes/audit.js +1 -1
- package/dist/routes/audit.js.map +1 -1
- package/dist/routes/branding.d.ts +3 -3
- package/dist/routes/branding.d.ts.map +1 -1
- package/dist/routes/branding.js +44 -16
- package/dist/routes/branding.js.map +1 -1
- package/dist/routes/bulk.d.ts +0 -5
- package/dist/routes/bulk.d.ts.map +1 -1
- package/dist/routes/bulk.js +3 -5
- package/dist/routes/bulk.js.map +1 -1
- package/dist/routes/clients.d.ts +4 -4
- package/dist/routes/clients.d.ts.map +1 -1
- package/dist/routes/clients.js +111 -52
- package/dist/routes/clients.js.map +1 -1
- package/dist/routes/config.d.ts +17 -12
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +165 -64
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/custom-claims.d.ts.map +1 -1
- package/dist/routes/custom-claims.js +8 -2
- package/dist/routes/custom-claims.js.map +1 -1
- package/dist/routes/exports.d.ts +2 -1
- package/dist/routes/exports.d.ts.map +1 -1
- package/dist/routes/exports.js +57 -1
- package/dist/routes/exports.js.map +1 -1
- package/dist/routes/imports.d.ts +2 -2
- package/dist/routes/imports.d.ts.map +1 -1
- package/dist/routes/imports.js +95 -40
- package/dist/routes/imports.js.map +1 -1
- package/dist/routes/interactions.d.ts.map +1 -1
- package/dist/routes/interactions.js +16 -34
- package/dist/routes/interactions.js.map +1 -1
- package/dist/routes/invitation.d.ts.map +1 -1
- package/dist/routes/invitation.js +10 -23
- package/dist/routes/invitation.js.map +1 -1
- package/dist/routes/keys.d.ts.map +1 -1
- package/dist/routes/keys.js +26 -13
- package/dist/routes/keys.js.map +1 -1
- package/dist/routes/magic-link.d.ts.map +1 -1
- package/dist/routes/magic-link.js +5 -17
- package/dist/routes/magic-link.js.map +1 -1
- package/dist/routes/organizations.d.ts +1 -2
- package/dist/routes/organizations.d.ts.map +1 -1
- package/dist/routes/organizations.js +43 -104
- package/dist/routes/organizations.js.map +1 -1
- package/dist/routes/password-reset.d.ts.map +1 -1
- package/dist/routes/password-reset.js +13 -35
- package/dist/routes/password-reset.js.map +1 -1
- package/dist/routes/permissions.d.ts +1 -1
- package/dist/routes/permissions.d.ts.map +1 -1
- package/dist/routes/permissions.js +58 -17
- package/dist/routes/permissions.js.map +1 -1
- package/dist/routes/public-branding.d.ts +16 -0
- package/dist/routes/public-branding.d.ts.map +1 -0
- package/dist/routes/public-branding.js +52 -0
- package/dist/routes/public-branding.js.map +1 -0
- package/dist/routes/roles.d.ts +1 -1
- package/dist/routes/roles.d.ts.map +1 -1
- package/dist/routes/roles.js +63 -21
- package/dist/routes/roles.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +23 -12
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/two-factor.d.ts.map +1 -1
- package/dist/routes/two-factor.js +91 -38
- package/dist/routes/two-factor.js.map +1 -1
- package/dist/routes/user-roles.d.ts.map +1 -1
- package/dist/routes/user-roles.js +56 -9
- package/dist/routes/user-roles.js.map +1 -1
- package/dist/routes/users.d.ts +4 -8
- package/dist/routes/users.d.ts.map +1 -1
- package/dist/routes/users.js +108 -265
- package/dist/routes/users.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +53 -37
- package/dist/server.js.map +1 -1
- package/dist/two-factor/errors.d.ts +9 -0
- package/dist/two-factor/errors.d.ts.map +1 -1
- package/dist/two-factor/errors.js +12 -0
- package/dist/two-factor/errors.js.map +1 -1
- package/dist/two-factor/index.d.ts +5 -4
- package/dist/two-factor/index.d.ts.map +1 -1
- package/dist/two-factor/index.js +4 -4
- package/dist/two-factor/index.js.map +1 -1
- package/dist/two-factor/repository.d.ts +17 -6
- package/dist/two-factor/repository.d.ts.map +1 -1
- package/dist/two-factor/repository.js +37 -9
- package/dist/two-factor/repository.js.map +1 -1
- package/dist/two-factor/service.d.ts.map +1 -1
- package/dist/two-factor/service.js +26 -19
- package/dist/two-factor/service.js.map +1 -1
- package/dist/two-factor/totp.d.ts +13 -2
- package/dist/two-factor/totp.d.ts.map +1 -1
- package/dist/two-factor/totp.js +20 -7
- package/dist/two-factor/totp.js.map +1 -1
- package/dist/two-factor/types.d.ts +3 -0
- package/dist/two-factor/types.d.ts.map +1 -1
- package/dist/two-factor/types.js +5 -0
- package/dist/two-factor/types.js.map +1 -1
- package/dist/users/gdpr.d.ts +2 -40
- package/dist/users/gdpr.d.ts.map +1 -1
- package/dist/users/gdpr.js +3 -110
- package/dist/users/gdpr.js.map +1 -1
- package/dist/users/index.d.ts +5 -4
- package/dist/users/index.d.ts.map +1 -1
- package/dist/users/index.js +5 -4
- package/dist/users/index.js.map +1 -1
- package/dist/users/repository.d.ts +49 -3
- package/dist/users/repository.d.ts.map +1 -1
- package/dist/users/repository.js +169 -18
- package/dist/users/repository.js.map +1 -1
- package/dist/users/service.d.ts +19 -51
- package/dist/users/service.d.ts.map +1 -1
- package/dist/users/service.js +72 -122
- package/dist/users/service.js.map +1 -1
- package/dist/users/types.d.ts +4 -5
- package/dist/users/types.d.ts.map +1 -1
- package/dist/users/types.js.map +1 -1
- package/dist/users/validators.d.ts +28 -0
- package/dist/users/validators.d.ts.map +1 -0
- package/dist/users/validators.js +25 -0
- package/dist/users/validators.js.map +1 -0
- package/locales/default/en/errors.json +2 -1
- package/migrations/024_application_client_correction.sql +39 -0
- package/migrations/025_record_deletion_lifecycle.sql +26 -0
- package/migrations/026_simplify_user_lifecycle.sql +33 -0
- package/migrations/027_branding_asset_size_limits.sql +19 -0
- package/migrations/028_totp_replay_protection.sql +17 -0
- package/migrations/029_public_session_identifiers.sql +16 -0
- package/migrations/030_global_configuration_catalog.sql +39 -0
- package/migrations/031_monotonic_updated_at.sql +28 -0
- package/package.json +2 -2
- package/dist/lib/data-import-plan.d.ts +0 -50
- package/dist/lib/data-import-plan.d.ts.map +0 -1
- package/dist/lib/data-import-plan.js +0 -235
- package/dist/lib/data-import-plan.js.map +0 -1
- package/dist/lib/data-import.d.ts +0 -276
- package/dist/lib/data-import.d.ts.map +0 -1
- package/dist/lib/data-import.js +0 -1694
- package/dist/lib/data-import.js.map +0 -1
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Liveness probe handler — GET /health.
|
|
3
|
+
*
|
|
4
|
+
* Reports whether the server process can still reach its dependencies. Or
|
|
5
|
+
* container orchestration uses this as a liveness probe, so every dependency
|
|
6
|
+
* check is bounded: a hung database or cache must fail the probe quickly
|
|
7
|
+
* (503) instead of holding the response open.
|
|
8
|
+
*
|
|
9
|
+
* Returns 200 + { status: 'healthy', checks } when both backends respond, or
|
|
10
|
+
* 503 + { status: 'unhealthy', checks } when either is degraded or too slow.
|
|
11
|
+
*/
|
|
1
12
|
import type { Middleware } from 'koa';
|
|
13
|
+
/**
|
|
14
|
+
* Create the liveness probe middleware.
|
|
15
|
+
*
|
|
16
|
+
* Both checks run concurrently under an individual timeout, so one slow
|
|
17
|
+
* dependency cannot delay the other and a hang cannot keep the probe pending.
|
|
18
|
+
*/
|
|
2
19
|
export declare function healthCheck(): Middleware;
|
|
3
20
|
//# sourceMappingURL=health.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/middleware/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/middleware/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAKtC;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,UAAU,CAqBxC"}
|
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Liveness probe handler — GET /health.
|
|
3
|
+
*
|
|
4
|
+
* Reports whether the server process can still reach its dependencies. Or
|
|
5
|
+
* container orchestration uses this as a liveness probe, so every dependency
|
|
6
|
+
* check is bounded: a hung database or cache must fail the probe quickly
|
|
7
|
+
* (503) instead of holding the response open.
|
|
8
|
+
*
|
|
9
|
+
* Returns 200 + { status: 'healthy', checks } when both backends respond, or
|
|
10
|
+
* 503 + { status: 'unhealthy', checks } when either is degraded or too slow.
|
|
11
|
+
*/
|
|
1
12
|
import { getPool } from '../lib/database.js';
|
|
2
13
|
import { getRedis } from '../lib/redis.js';
|
|
14
|
+
import { withTimeout } from '../lib/with-timeout.js';
|
|
15
|
+
/**
|
|
16
|
+
* Create the liveness probe middleware.
|
|
17
|
+
*
|
|
18
|
+
* Both checks run concurrently under an individual timeout, so one slow
|
|
19
|
+
* dependency cannot delay the other and a hang cannot keep the probe pending.
|
|
20
|
+
*/
|
|
3
21
|
export function healthCheck() {
|
|
4
22
|
return async (ctx) => {
|
|
5
23
|
const checks = { server: 'ok' };
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
catch {
|
|
14
|
-
checks.database = 'error';
|
|
15
|
-
healthy = false;
|
|
16
|
-
}
|
|
17
|
-
// Check Redis
|
|
18
|
-
try {
|
|
19
|
-
const redis = getRedis();
|
|
20
|
-
await redis.ping();
|
|
21
|
-
checks.redis = 'ok';
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
checks.redis = 'error';
|
|
25
|
-
healthy = false;
|
|
26
|
-
}
|
|
24
|
+
const [dbResult, redisResult] = await Promise.allSettled([
|
|
25
|
+
withTimeout(getPool().query('SELECT 1'), 'database'),
|
|
26
|
+
withTimeout(getRedis().ping(), 'redis'),
|
|
27
|
+
]);
|
|
28
|
+
checks.database = dbResult.status === 'fulfilled' ? 'ok' : 'error';
|
|
29
|
+
checks.redis = redisResult.status === 'fulfilled' ? 'ok' : 'error';
|
|
30
|
+
const healthy = dbResult.status === 'fulfilled' && redisResult.status === 'fulfilled';
|
|
27
31
|
ctx.status = healthy ? 200 : 503;
|
|
28
32
|
ctx.body = {
|
|
29
33
|
status: healthy ? 'healthy' : 'unhealthy',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/middleware/health.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/middleware/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,MAAM,GAA2B,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAExD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YACvD,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;YACpD,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC;SACxC,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;QACnE,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;QAEnE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,WAAW,CAAC;QAEtF,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACjC,GAAG,CAAC,IAAI,GAAG;YACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;YACzC,MAAM;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAMtC;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,UAAU,CA6BzC"}
|
package/dist/middleware/ready.js
CHANGED
|
@@ -15,18 +15,7 @@
|
|
|
15
15
|
import { getPool } from '../lib/database.js';
|
|
16
16
|
import { getRedis } from '../lib/redis.js';
|
|
17
17
|
import { logger } from '../lib/logger.js';
|
|
18
|
-
|
|
19
|
-
const TIMEOUT_MS = 2000;
|
|
20
|
-
/**
|
|
21
|
-
* Race a promise against a timeout. Rejects with a descriptive error
|
|
22
|
-
* if the promise doesn't resolve within `TIMEOUT_MS`.
|
|
23
|
-
*/
|
|
24
|
-
function withTimeout(promise, label) {
|
|
25
|
-
return Promise.race([
|
|
26
|
-
promise,
|
|
27
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(`${label} timeout after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)),
|
|
28
|
-
]);
|
|
29
|
-
}
|
|
18
|
+
import { withTimeout } from '../lib/with-timeout.js';
|
|
30
19
|
/**
|
|
31
20
|
* Create the readiness probe middleware.
|
|
32
21
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ready.js","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ready.js","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,MAAM,GAAoD,EAAE,CAAC;QAEnE,qEAAqE;QACrE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YACvD,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;YAC9C,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC;SACxC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,MAAM,KAAK,WAAW;gBAC7B,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE;gBACd,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAEpD,MAAM,CAAC,KAAK;YACV,WAAW,CAAC,MAAM,KAAK,WAAW;gBAChC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE;gBACd,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAEvD,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAE9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAC7E,CAAC;QAED,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/B,GAAG,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAC/D,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Organization-existence guard for organization-prefixed administrative routes.
|
|
3
|
+
*
|
|
4
|
+
* A route value that is not a canonical UUID, or that names no organization, must produce one
|
|
5
|
+
* non-enumerating not-found response. Without this guard the identifier reaches the database and a
|
|
6
|
+
* malformed value surfaces as an internal error instead of a client-visible rejection.
|
|
7
|
+
*
|
|
8
|
+
* Place this middleware after `requirePermission(...)` so a caller without the operation's
|
|
9
|
+
* permission still receives the permission denial before any organization lookup.
|
|
10
|
+
*/
|
|
11
|
+
import type { Middleware } from 'koa';
|
|
12
|
+
/**
|
|
13
|
+
* Require the organization named in the route path to exist.
|
|
14
|
+
*
|
|
15
|
+
* @returns Koa middleware that continues only for an existing organization.
|
|
16
|
+
*/
|
|
17
|
+
export declare function requireExistingOrganization(): Middleware;
|
|
18
|
+
//# sourceMappingURL=require-existing-organization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-existing-organization.d.ts","sourceRoot":"","sources":["../../src/middleware/require-existing-organization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAQtC;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,UAAU,CAiBxD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Organization-existence guard for organization-prefixed administrative routes.
|
|
3
|
+
*
|
|
4
|
+
* A route value that is not a canonical UUID, or that names no organization, must produce one
|
|
5
|
+
* non-enumerating not-found response. Without this guard the identifier reaches the database and a
|
|
6
|
+
* malformed value surfaces as an internal error instead of a client-visible rejection.
|
|
7
|
+
*
|
|
8
|
+
* Place this middleware after `requirePermission(...)` so a caller without the operation's
|
|
9
|
+
* permission still receives the permission denial before any organization lookup.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { getOrganizationById } from '../organizations/service.js';
|
|
13
|
+
import { recordSecurityDecision } from '../security/decision-context.js';
|
|
14
|
+
const organizationParamSchema = z.object({ orgId: z.string().uuid() });
|
|
15
|
+
/**
|
|
16
|
+
* Require the organization named in the route path to exist.
|
|
17
|
+
*
|
|
18
|
+
* @returns Koa middleware that continues only for an existing organization.
|
|
19
|
+
*/
|
|
20
|
+
export function requireExistingOrganization() {
|
|
21
|
+
return async function requireExistingOrganizationMiddleware(ctx, next) {
|
|
22
|
+
const parsed = organizationParamSchema.safeParse(ctx.params);
|
|
23
|
+
const organization = parsed.success ? await getOrganizationById(parsed.data.orgId) : null;
|
|
24
|
+
if (organization === null) {
|
|
25
|
+
recordSecurityDecision(ctx, {
|
|
26
|
+
decisionPoint: 'resource',
|
|
27
|
+
reasonCode: 'resource-not-found',
|
|
28
|
+
outcome: 'deny',
|
|
29
|
+
detail: { resourceType: 'organization' },
|
|
30
|
+
});
|
|
31
|
+
ctx.status = 404;
|
|
32
|
+
ctx.body = { error: 'Organization not found' };
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
await next();
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=require-existing-organization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-existing-organization.js","sourceRoot":"","sources":["../../src/middleware/require-existing-organization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,KAAK,UAAU,qCAAqC,CAAC,GAAG,EAAE,IAAI;QACnE,MAAM,MAAM,GAAG,uBAAuB,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1F,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE;aACzC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;YAC/C,OAAO;QACT,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-permission.d.ts","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"require-permission.d.ts","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,KAAK,CAAC;AAmC/C;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,mBAAmB,EAAE,MAAM,EAAE,GAAG,UAAU,CAyC9E"}
|
|
@@ -15,7 +15,37 @@
|
|
|
15
15
|
* @module middleware/require-permission
|
|
16
16
|
*/
|
|
17
17
|
import { hasPermissions } from '../lib/admin-permissions.js';
|
|
18
|
-
import { recordSecurityDecision } from '../security/decision-context.js';
|
|
18
|
+
import { recordSecurityDecision, recordSecurityReference } from '../security/decision-context.js';
|
|
19
|
+
/**
|
|
20
|
+
* Route parameter names, in priority order, that identify the target of an
|
|
21
|
+
* administrative action. The most specific identifier wins so the recorded
|
|
22
|
+
* digest names the acted-on resource rather than a generic container.
|
|
23
|
+
*/
|
|
24
|
+
const TARGET_PARAMETER_KEYS = ['userId', 'id', 'key', 'type', 'organizationId'];
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the target identifier for a denied administrative action.
|
|
27
|
+
*
|
|
28
|
+
* Entity routes expose the acted-on resource id in a route parameter. List and
|
|
29
|
+
* collection routes have none, so the actor's organization is the acted-on
|
|
30
|
+
* scope. The value is always protected before it reaches any event.
|
|
31
|
+
*
|
|
32
|
+
* @param ctx - Request context carrying the matched route parameters.
|
|
33
|
+
* @returns A raw identifier for privacy-preserving protection, or `undefined`.
|
|
34
|
+
*/
|
|
35
|
+
function denialTargetIdentifier(ctx) {
|
|
36
|
+
const params = Reflect.get(ctx, 'params');
|
|
37
|
+
if (params !== undefined) {
|
|
38
|
+
for (const key of TARGET_PARAMETER_KEYS) {
|
|
39
|
+
const value = params[key];
|
|
40
|
+
if (typeof value === 'string' && value.length > 0)
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const organizationId = ctx.state.adminUser?.organizationId;
|
|
45
|
+
return typeof organizationId === 'string' && organizationId.length > 0
|
|
46
|
+
? organizationId
|
|
47
|
+
: undefined;
|
|
48
|
+
}
|
|
19
49
|
/**
|
|
20
50
|
* Create middleware that requires specific admin permission(s).
|
|
21
51
|
*
|
|
@@ -50,6 +80,10 @@ export function requirePermission(...requiredPermissions) {
|
|
|
50
80
|
outcome: 'deny',
|
|
51
81
|
detail: { permissions: requiredPermissions },
|
|
52
82
|
});
|
|
83
|
+
const target = denialTargetIdentifier(ctx);
|
|
84
|
+
if (target !== undefined) {
|
|
85
|
+
recordSecurityReference(ctx, 'resource', target);
|
|
86
|
+
}
|
|
53
87
|
ctx.status = 403;
|
|
54
88
|
ctx.body = {
|
|
55
89
|
error: 'Forbidden',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-permission.js","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"require-permission.js","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAElG;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAU,CAAC;AAEzF;;;;;;;;;GASG;AACH,SAAS,sBAAsB,CAAC,GAAY;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAwC,CAAC;IACjF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC;QAClE,CAAC;IACH,CAAC;IACD,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC;IAC3D,OAAO,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;QACpE,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,mBAA6B;IAChE,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;QAEtC,uDAAuD;QACvD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,gBAAgB;gBAC/B,UAAU,EAAE,yBAAyB;gBACrC,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,yBAAyB;gBAChC,OAAO,EAAE,uDAAuD;aACjE,CAAC;YACF,OAAO;QACT,CAAC;QAED,iDAAiD;QACjD,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC,EAAE,CAAC;YACrE,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,YAAY;gBAC3B,UAAU,EAAE,qBAAqB;gBACjC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE;aAC7C,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YACD,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,0CAA0C;aACpD,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-user-organization.d.ts","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAWtC;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,UAAU,
|
|
1
|
+
{"version":3,"file":"require-user-organization.d.ts","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAWtC;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,UAAU,CAkCpD"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* organization-prefixed API from becoming a cross-tenant object lookup or membership oracle.
|
|
7
7
|
*/
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import {
|
|
9
|
+
import { findUserById } from '../users/repository.js';
|
|
10
10
|
import { recordSecurityDecision, recordSecurityReference } from '../security/decision-context.js';
|
|
11
11
|
const organizationUserParamsSchema = z.object({
|
|
12
12
|
orgId: z.string().uuid(),
|
|
@@ -34,7 +34,9 @@ export function requireUserOrganization() {
|
|
|
34
34
|
ctx.body = { error: 'User not found' };
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
// Authorization must use the live row. A cache miss inside a mutation transaction would
|
|
38
|
+
// otherwise register a post-commit cache write for a user the same request may delete.
|
|
39
|
+
const user = await findUserById(parsed.data.userId);
|
|
38
40
|
if (user === null || user.organizationId !== parsed.data.orgId) {
|
|
39
41
|
recordSecurityDecision(ctx, {
|
|
40
42
|
decisionPoint: 'resource',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-user-organization.js","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"require-user-organization.js","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAElG,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC1B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,KAAK,UAAU,iCAAiC,CAAC,GAAG,EAAE,IAAI;QAC/D,MAAM,MAAM,GAAG,4BAA4B,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,wFAAwF;QACxF,uFAAuF;QACvF,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/D,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7D,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
* inject custom branding CSS via `{{{branding.customCss}}}`, hence
|
|
34
34
|
* `style-src 'unsafe-inline'` is required. Login pages must never
|
|
35
35
|
* be embedded in iframes (`frame-ancestors 'none'`).
|
|
36
|
+
* The final HTML policy also permits same-origin images, data-backed QR images, and only the
|
|
37
|
+
* validated external origins required by effective organization branding.
|
|
36
38
|
*
|
|
37
39
|
* Note: `form-action` is intentionally omitted. Chrome enforces
|
|
38
40
|
* `form-action` on the entire redirect chain of a form submission,
|
|
@@ -51,6 +53,12 @@
|
|
|
51
53
|
* ensures headers are present even on error responses.
|
|
52
54
|
*/
|
|
53
55
|
import type { Middleware } from 'koa';
|
|
56
|
+
declare module 'koa' {
|
|
57
|
+
interface DefaultState {
|
|
58
|
+
/** Validated image origins required by the authentication HTML response. */
|
|
59
|
+
brandingImageSources?: readonly string[];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
54
62
|
/**
|
|
55
63
|
* Static security headers applied to every response regardless of
|
|
56
64
|
* content type or route.
|
|
@@ -79,6 +87,16 @@ export declare const DEFAULT_CSP = "default-src 'none'";
|
|
|
79
87
|
* `form-action` is intentionally omitted — see module-level doc comment.
|
|
80
88
|
*/
|
|
81
89
|
export declare const HTML_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'";
|
|
90
|
+
/**
|
|
91
|
+
* Build the authentication-page CSP with only validated image origins.
|
|
92
|
+
*
|
|
93
|
+
* Same-origin uploads and data-backed QR images are always permitted for authentication HTML.
|
|
94
|
+
* Additional external sources must be exact origins accepted by the branding URL validator.
|
|
95
|
+
*
|
|
96
|
+
* @param imageSources - Candidate image sources from effective organization branding.
|
|
97
|
+
* @returns Complete HTML Content-Security-Policy value.
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildHtmlCsp(imageSources?: readonly string[]): string;
|
|
82
100
|
/**
|
|
83
101
|
* HSTS header value — one year, include subdomains.
|
|
84
102
|
* Only emitted when the configured issuer URL uses https.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAItC,OAAO,QAAQ,KAAK,CAAC;IACnB,UAAU,YAAY;QACpB,4EAA4E;QAC5E,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC1C;CACF;AAOD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,sGACgF,CAAC;AAatG;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,YAAY,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAOzE;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,wCAAwC,CAAC;AAsBhE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAqC5C"}
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
* inject custom branding CSS via `{{{branding.customCss}}}`, hence
|
|
34
34
|
* `style-src 'unsafe-inline'` is required. Login pages must never
|
|
35
35
|
* be embedded in iframes (`frame-ancestors 'none'`).
|
|
36
|
+
* The final HTML policy also permits same-origin images, data-backed QR images, and only the
|
|
37
|
+
* validated external origins required by effective organization branding.
|
|
36
38
|
*
|
|
37
39
|
* Note: `form-action` is intentionally omitted. Chrome enforces
|
|
38
40
|
* `form-action` on the entire redirect chain of a form submission,
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
* ensures headers are present even on error responses.
|
|
52
54
|
*/
|
|
53
55
|
import { config } from '../config/index.js';
|
|
56
|
+
import { validateBrandingImageUrl } from '../organizations/branding-url.js';
|
|
54
57
|
// ---------------------------------------------------------------------------
|
|
55
58
|
// Exported constants — consumed by tests and by other middleware that may
|
|
56
59
|
// need to reference or override specific values.
|
|
@@ -89,6 +92,34 @@ export const DEFAULT_CSP = "default-src 'none'";
|
|
|
89
92
|
* `form-action` is intentionally omitted — see module-level doc comment.
|
|
90
93
|
*/
|
|
91
94
|
export const HTML_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'";
|
|
95
|
+
/** Return one safe external origin, rejecting paths and malformed or disallowed URLs. */
|
|
96
|
+
function validatedExternalImageOrigin(candidate) {
|
|
97
|
+
try {
|
|
98
|
+
const validated = validateBrandingImageUrl(candidate);
|
|
99
|
+
const origin = new URL(validated).origin;
|
|
100
|
+
return validated === origin ? origin : null;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Build the authentication-page CSP with only validated image origins.
|
|
108
|
+
*
|
|
109
|
+
* Same-origin uploads and data-backed QR images are always permitted for authentication HTML.
|
|
110
|
+
* Additional external sources must be exact origins accepted by the branding URL validator.
|
|
111
|
+
*
|
|
112
|
+
* @param imageSources - Candidate image sources from effective organization branding.
|
|
113
|
+
* @returns Complete HTML Content-Security-Policy value.
|
|
114
|
+
*/
|
|
115
|
+
export function buildHtmlCsp(imageSources = []) {
|
|
116
|
+
const externalOrigins = imageSources
|
|
117
|
+
.map(validatedExternalImageOrigin)
|
|
118
|
+
.filter((origin) => origin !== null)
|
|
119
|
+
.sort();
|
|
120
|
+
const sources = ["'self'", 'data:', ...new Set(externalOrigins)];
|
|
121
|
+
return `${HTML_CSP}; img-src ${sources.join(' ')}`;
|
|
122
|
+
}
|
|
92
123
|
/**
|
|
93
124
|
* HSTS header value — one year, include subdomains.
|
|
94
125
|
* Only emitted when the configured issuer URL uses https.
|
|
@@ -152,7 +183,7 @@ export function securityHeaders() {
|
|
|
152
183
|
// -----------------------------------------------------------------------
|
|
153
184
|
const contentType = ctx.response.get('Content-Type') || '';
|
|
154
185
|
if (contentType.includes('text/html')) {
|
|
155
|
-
ctx.set('Content-Security-Policy',
|
|
186
|
+
ctx.set('Content-Security-Policy', buildHtmlCsp(ctx.state?.brandingImageSources));
|
|
156
187
|
}
|
|
157
188
|
};
|
|
158
189
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAS5E,8EAA8E;AAC9E,0EAA0E;AAC1E,iDAAiD;AACjD,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAqC,MAAM,CAAC,MAAM,CAAC;IACrF,wBAAwB,EAAE,SAAS;IACnC,iBAAiB,EAAE,MAAM;IACzB,iBAAiB,EAAE,iCAAiC;IACpD,kBAAkB,EAAE,GAAG;IACvB,oBAAoB,EAAE,sDAAsD;CAC7E,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,QAAQ,GACnB,mGAAmG,CAAC;AAEtG,yFAAyF;AACzF,SAAS,4BAA4B,CAAC,SAAiB;IACrD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QACzC,OAAO,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,YAAY,GAAsB,EAAE;IAC/D,MAAM,eAAe,GAAG,YAAY;SACjC,GAAG,CAAC,4BAA4B,CAAC;SACjC,MAAM,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC;SACrD,IAAI,EAAE,CAAC;IACV,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;IACjE,OAAO,GAAG,QAAQ,aAAa,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,qCAAqC,CAAC;AAEhE,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,OAAO,KAAK,UAAU,yBAAyB,CAAC,GAAG,EAAE,IAAI;QACvD,0EAA0E;QAC1E,iEAAiE;QACjE,kEAAkE;QAClE,6DAA6D;QAC7D,0EAA0E;QAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;QAED,gEAAgE;QAChE,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,WAAW,CAAC,CAAC;QAEhD,8CAA8C;QAC9C,IAAI,QAAQ,EAAE,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,2BAA2B,EAAE,UAAU,CAAC,CAAC;QACnD,CAAC;QAED,0EAA0E;QAC1E,wDAAwD;QACxD,0EAA0E;QAC1E,MAAM,IAAI,EAAE,CAAC;QAEb,0EAA0E;QAC1E,2CAA2C;QAC3C,sEAAsE;QACtE,mEAAmE;QACnE,kDAAkD;QAClD,0EAA0E;QAC1E,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QAC3D,IAAI,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACpF,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -14,14 +14,13 @@
|
|
|
14
14
|
* 3. If cache miss, query DB: findOrganizationBySlug(orgSlug)
|
|
15
15
|
* 4. If found from DB, cache it: cacheOrganization(org)
|
|
16
16
|
* 5. Validate status:
|
|
17
|
-
* - archived → 404 "Organization not found"
|
|
18
17
|
* - suspended → 403 "Organization is suspended"
|
|
19
18
|
* - active → continue
|
|
20
19
|
* 6. Set ctx.state.organization (full Organization object)
|
|
21
20
|
* 7. Set ctx.state.issuer
|
|
22
21
|
*
|
|
23
22
|
* Returns:
|
|
24
|
-
* - 404 if organization not found
|
|
23
|
+
* - 404 if organization is not found
|
|
25
24
|
* - 403 if organization is suspended
|
|
26
25
|
*/
|
|
27
26
|
import type { Middleware } from 'koa';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-resolver.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tenant-resolver.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAStC;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAqC3C"}
|
|
@@ -14,14 +14,13 @@
|
|
|
14
14
|
* 3. If cache miss, query DB: findOrganizationBySlug(orgSlug)
|
|
15
15
|
* 4. If found from DB, cache it: cacheOrganization(org)
|
|
16
16
|
* 5. Validate status:
|
|
17
|
-
* - archived → 404 "Organization not found"
|
|
18
17
|
* - suspended → 403 "Organization is suspended"
|
|
19
18
|
* - active → continue
|
|
20
19
|
* 6. Set ctx.state.organization (full Organization object)
|
|
21
20
|
* 7. Set ctx.state.issuer
|
|
22
21
|
*
|
|
23
22
|
* Returns:
|
|
24
|
-
* - 404 if organization not found
|
|
23
|
+
* - 404 if organization is not found
|
|
25
24
|
* - 403 if organization is suspended
|
|
26
25
|
*/
|
|
27
26
|
import { config } from '../config/index.js';
|
|
@@ -56,9 +55,6 @@ export function tenantResolver() {
|
|
|
56
55
|
return ctx.throw(404, 'Organization not found');
|
|
57
56
|
}
|
|
58
57
|
// 5. Status-dependent responses
|
|
59
|
-
if (org.status === 'archived') {
|
|
60
|
-
return ctx.throw(404, 'Organization not found');
|
|
61
|
-
}
|
|
62
58
|
if (org.status === 'suspended') {
|
|
63
59
|
return ctx.throw(403, 'Organization is suspended');
|
|
64
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-resolver.js","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tenant-resolver.js","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAGxE;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAC3C,CAAC;QAED,2BAA2B;QAC3B,IAAI,GAAG,GAAwB,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAE1E,wDAAwD;QACxD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE5C,8CAA8C;YAC9C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAClD,CAAC;QAED,gCAAgC;QAChC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;QACrD,CAAC;QAED,oEAAoE;QACpE,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC;QAC7B,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAEzD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token and introspection endpoint rate limiter middleware.
|
|
3
3
|
*
|
|
4
|
-
* Protects the OAuth token endpoint (`POST /:orgSlug/
|
|
5
|
-
* token introspection endpoint (`POST /:orgSlug/
|
|
4
|
+
* Protects the OAuth token endpoint (`POST /:orgSlug/token`) and
|
|
5
|
+
* token introspection endpoint (`POST /:orgSlug/token/introspection`)
|
|
6
6
|
* against abuse: client-credentials flooding, authorization-code
|
|
7
7
|
* brute-forcing, token enumeration, and general endpoint spam.
|
|
8
8
|
*
|
|
9
|
-
* Rate limiting is per-IP + per-client_id composite key.
|
|
10
|
-
* is
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Rate limiting is per-IP + per-client_id composite key. The client
|
|
10
|
+
* identifier is read from the parsed body or from HTTP Basic credentials;
|
|
11
|
+
* when neither is present (unauthenticated spam) the key falls back to
|
|
12
|
+
* `unknown`. Because that identifier is unauthenticated and caller-controlled,
|
|
13
|
+
* an aggregate per-IP counter runs alongside it, so one address cannot flood
|
|
14
|
+
* the endpoint by varying the client identifier.
|
|
13
15
|
*
|
|
14
16
|
* Reuses the existing `checkRateLimit()` infrastructure from
|
|
15
17
|
* `src/auth/rate-limiter.ts` which provides Redis INCR+EXPIRE sliding
|
|
16
18
|
* window and graceful degradation on Redis failure.
|
|
17
19
|
*
|
|
18
|
-
* Placement:
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* Placement: mounted on the OIDC router **after** the request body parser so
|
|
21
|
+
* the client identifier is available, and before the provider callback. The
|
|
22
|
+
* path regex ensures only the token and introspection endpoints are limited —
|
|
23
|
+
* every other path passes through untouched.
|
|
21
24
|
*
|
|
22
25
|
* @module middleware/token-rate-limiter
|
|
23
26
|
*/
|
|
@@ -26,22 +29,32 @@ import type { RateLimitConfig } from '../auth/rate-limiter.js';
|
|
|
26
29
|
/**
|
|
27
30
|
* Regex matching the OIDC token endpoint path.
|
|
28
31
|
*
|
|
29
|
-
* Pattern: `/<orgSlug>/
|
|
32
|
+
* Pattern: `/<orgSlug>/token` where orgSlug starts with a
|
|
30
33
|
* lowercase alphanumeric character followed by zero or more lowercase
|
|
31
34
|
* alphanumeric or hyphen characters.
|
|
32
35
|
*
|
|
33
|
-
* Matches: `/acme/
|
|
34
|
-
* Rejects: `/api/admin/something`, `/acme/
|
|
36
|
+
* Matches: `/acme/token`, `/my-org/token`
|
|
37
|
+
* Rejects: `/api/admin/something`, `/acme/token/extra`
|
|
35
38
|
*/
|
|
36
39
|
export declare const TOKEN_PATH_REGEX: RegExp;
|
|
37
40
|
/**
|
|
38
|
-
* Rate limit configuration for the token endpoint.
|
|
41
|
+
* Rate limit configuration for the token endpoint, per client.
|
|
39
42
|
*
|
|
40
43
|
* 30 requests per 5-minute window — generous enough for legitimate
|
|
41
44
|
* applications (SPAs refreshing tokens, server-side token exchanges)
|
|
42
45
|
* while catching automated abuse.
|
|
43
46
|
*/
|
|
44
47
|
export declare const TOKEN_RATE_LIMIT: RateLimitConfig;
|
|
48
|
+
/**
|
|
49
|
+
* Aggregate token limit for one client address.
|
|
50
|
+
*
|
|
51
|
+
* The per-client key comes from an unauthenticated value, so a caller can vary
|
|
52
|
+
* the client identifier to open a fresh counter for every request. This
|
|
53
|
+
* aggregate bounds the total token traffic from one address, so the endpoint
|
|
54
|
+
* cannot be flooded with junk requests, while many legitimate clients behind
|
|
55
|
+
* one address still receive their own per-client budgets.
|
|
56
|
+
*/
|
|
57
|
+
export declare const TOKEN_IP_RATE_LIMIT: RateLimitConfig;
|
|
45
58
|
/**
|
|
46
59
|
* Create the token endpoint rate limiter middleware.
|
|
47
60
|
*
|
|
@@ -56,11 +69,11 @@ export declare function tokenRateLimiter(): Middleware;
|
|
|
56
69
|
/**
|
|
57
70
|
* Regex matching the OIDC token introspection endpoint path.
|
|
58
71
|
*
|
|
59
|
-
* Pattern: `/<orgSlug>/
|
|
72
|
+
* Pattern: `/<orgSlug>/token/introspection` where orgSlug uses
|
|
60
73
|
* the same slug format as TOKEN_PATH_REGEX.
|
|
61
74
|
*
|
|
62
|
-
* Matches: `/acme/
|
|
63
|
-
* Rejects: `/acme/
|
|
75
|
+
* Matches: `/acme/token/introspection`, `/my-org/token/introspection`
|
|
76
|
+
* Rejects: `/acme/token`, `/api/admin/introspection`
|
|
64
77
|
*/
|
|
65
78
|
export declare const INTROSPECTION_PATH_REGEX: RegExp;
|
|
66
79
|
/**
|
|
@@ -72,6 +85,14 @@ export declare const INTROSPECTION_PATH_REGEX: RegExp;
|
|
|
72
85
|
* while still preventing token enumeration attacks.
|
|
73
86
|
*/
|
|
74
87
|
export declare const INTROSPECTION_RATE_LIMIT: RateLimitConfig;
|
|
88
|
+
/**
|
|
89
|
+
* Aggregate introspection limit for one client address.
|
|
90
|
+
*
|
|
91
|
+
* As on the token endpoint, the per-client key comes from an unauthenticated
|
|
92
|
+
* value and can be varied per request, so this aggregate bounds the total
|
|
93
|
+
* introspection traffic from one address independently of the client value.
|
|
94
|
+
*/
|
|
95
|
+
export declare const INTROSPECTION_IP_RATE_LIMIT: RateLimitConfig;
|
|
75
96
|
/**
|
|
76
97
|
* Create the introspection endpoint rate limiter middleware.
|
|
77
98
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/token-rate-limiter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"token-rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/token-rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,KAAK,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAO/D;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AA2ChE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAG9B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,eAGjC,CAAC;AAgCF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAoD7C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,QAAiD,CAAC;AAEvF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAGtC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,eAGzC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,IAAI,UAAU,CA0DrD"}
|