alepha 0.14.2 → 0.14.4
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/README.md +1 -1
- package/dist/api/audits/index.browser.js +5 -5
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +706 -785
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +13 -13
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +5 -5
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +58 -137
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +71 -71
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +5 -5
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +29 -108
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +10 -10
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +10 -10
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +504 -171
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +12 -12
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +163 -10
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +277 -351
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +196 -91
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.browser.js +19 -19
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +787 -852
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +827 -596
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js +6 -6
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +128 -128
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +6 -6
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bin/index.d.ts +1 -2
- package/dist/bin/index.js +0 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/cli/index.d.ts +252 -131
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +595 -395
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +46 -11
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +99 -19
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +40 -22
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +45 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +40 -22
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +40 -22
- package/dist/core/index.native.js.map +1 -1
- package/dist/fake/index.js +195 -168
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +8 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +3 -0
- package/dist/file/index.js.map +1 -1
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +12 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.d.ts +59 -195
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +201 -430
- package/dist/orm/index.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +171 -155
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +0 -1
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +12 -0
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +55 -2
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +6 -0
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +38 -1
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/core/index.browser.js +2 -2
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +10 -10
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +7 -4
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js +22 -6
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +46 -44
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +24 -41
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +4 -0
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +2 -1
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +9 -5
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/vite/index.d.ts +101 -106
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +574 -503
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- package/package.json +7 -7
- package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
- package/src/api/audits/entities/audits.ts +5 -5
- package/src/api/audits/index.browser.ts +1 -1
- package/src/api/audits/index.ts +3 -3
- package/src/api/audits/primitives/$audit.spec.ts +276 -0
- package/src/api/audits/services/AuditService.spec.ts +495 -0
- package/src/api/files/__tests__/$bucket.spec.ts +91 -0
- package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
- package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
- package/src/api/files/controllers/FileController.spec.ts +558 -0
- package/src/api/files/controllers/FileController.ts +4 -5
- package/src/api/files/entities/files.ts +5 -5
- package/src/api/files/index.browser.ts +1 -1
- package/src/api/files/index.ts +4 -4
- package/src/api/files/jobs/FileJobs.spec.ts +52 -0
- package/src/api/files/services/FileService.spec.ts +109 -0
- package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
- package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
- package/src/api/jobs/entities/jobExecutions.ts +5 -5
- package/src/api/jobs/index.ts +3 -3
- package/src/api/jobs/primitives/$job.spec.ts +476 -0
- package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
- package/src/api/notifications/entities/notifications.ts +5 -5
- package/src/api/notifications/index.browser.ts +1 -1
- package/src/api/notifications/index.ts +4 -4
- package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
- package/src/api/parameters/entities/parameters.ts +7 -17
- package/src/api/parameters/index.ts +3 -3
- package/src/api/parameters/primitives/$config.spec.ts +356 -0
- package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
- package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
- package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
- package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
- package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
- package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
- package/src/api/parameters/schemas/index.ts +15 -0
- package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
- package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
- package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
- package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
- package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
- package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
- package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
- package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
- package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
- package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
- package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
- package/src/api/users/controllers/AdminUserController.ts +116 -0
- package/src/api/users/controllers/UserController.ts +4 -107
- package/src/api/users/controllers/UserRealmController.ts +3 -0
- package/src/api/users/entities/identities.ts +6 -6
- package/src/api/users/entities/sessions.ts +6 -6
- package/src/api/users/entities/users.ts +9 -9
- package/src/api/users/index.ts +9 -6
- package/src/api/users/primitives/$userRealm.ts +13 -8
- package/src/api/users/services/CredentialService.spec.ts +509 -0
- package/src/api/users/services/CredentialService.ts +46 -0
- package/src/api/users/services/IdentityService.ts +15 -0
- package/src/api/users/services/RegistrationService.spec.ts +630 -0
- package/src/api/users/services/RegistrationService.ts +18 -0
- package/src/api/users/services/SessionService.spec.ts +301 -0
- package/src/api/users/services/SessionService.ts +110 -1
- package/src/api/users/services/UserService.ts +67 -2
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
- package/src/api/verifications/entities/verifications.ts +6 -6
- package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
- package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
- package/src/batch/primitives/$batch.spec.ts +766 -0
- package/src/batch/providers/BatchProvider.spec.ts +786 -0
- package/src/bin/index.ts +0 -1
- package/src/bucket/__tests__/shared.ts +194 -0
- package/src/bucket/primitives/$bucket.spec.ts +104 -0
- package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
- package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
- package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
- package/src/cache/core/__tests__/shared.ts +377 -0
- package/src/cache/core/primitives/$cache.spec.ts +111 -0
- package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
- package/src/cli/apps/AlephaCli.ts +25 -6
- package/src/cli/atoms/buildOptions.ts +88 -0
- package/src/cli/commands/build.ts +32 -69
- package/src/cli/commands/db.ts +0 -4
- package/src/cli/commands/dev.ts +34 -10
- package/src/cli/commands/gen/changelog.spec.ts +315 -0
- package/src/cli/commands/{changelog.ts → gen/changelog.ts} +9 -9
- package/src/cli/commands/gen/env.ts +53 -0
- package/src/cli/commands/gen/openapi.ts +71 -0
- package/src/cli/commands/gen/resource.ts +15 -0
- package/src/cli/commands/gen.ts +24 -0
- package/src/cli/commands/init.ts +2 -1
- package/src/cli/commands/root.ts +12 -3
- package/src/cli/commands/test.ts +0 -1
- package/src/cli/commands/typecheck.ts +5 -0
- package/src/cli/commands/verify.ts +1 -1
- package/src/cli/defineConfig.ts +49 -7
- package/src/cli/index.ts +2 -2
- package/src/cli/services/AlephaCliUtils.ts +105 -55
- package/src/cli/services/GitMessageParser.ts +1 -1
- package/src/command/helpers/Asker.spec.ts +127 -0
- package/src/command/helpers/Runner.spec.ts +126 -0
- package/src/command/helpers/Runner.ts +1 -1
- package/src/command/primitives/$command.spec.ts +1588 -0
- package/src/command/primitives/$command.ts +0 -6
- package/src/command/providers/CliProvider.ts +75 -27
- package/src/core/Alepha.ts +87 -0
- package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
- package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
- package/src/core/__tests__/Alepha-has.spec.ts +41 -0
- package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
- package/src/core/__tests__/Alepha-register.spec.ts +81 -0
- package/src/core/__tests__/Alepha-start.spec.ts +176 -0
- package/src/core/__tests__/Alepha-with.spec.ts +14 -0
- package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
- package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
- package/src/core/__tests__/descriptor.spec.ts +34 -0
- package/src/core/__tests__/fixtures/A.ts +5 -0
- package/src/core/__tests__/pagination.spec.ts +77 -0
- package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
- package/src/core/primitives/$atom.spec.ts +43 -0
- package/src/core/primitives/$hook.spec.ts +130 -0
- package/src/core/primitives/$inject.spec.ts +175 -0
- package/src/core/primitives/$module.spec.ts +115 -0
- package/src/core/providers/CodecManager.spec.ts +740 -0
- package/src/core/providers/EventManager.spec.ts +762 -0
- package/src/core/providers/EventManager.ts +4 -0
- package/src/core/providers/StateManager.spec.ts +365 -0
- package/src/core/providers/TypeProvider.spec.ts +1607 -0
- package/src/core/providers/TypeProvider.ts +20 -26
- package/src/datetime/primitives/$interval.spec.ts +103 -0
- package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
- package/src/email/primitives/$email.spec.ts +175 -0
- package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
- package/src/fake/__tests__/keyName.example.ts +40 -0
- package/src/fake/__tests__/keyName.spec.ts +152 -0
- package/src/fake/__tests__/module.example.ts +32 -0
- package/src/fake/providers/FakeProvider.spec.ts +438 -0
- package/src/file/providers/FileSystemProvider.ts +8 -0
- package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
- package/src/file/providers/NodeFileSystemProvider.ts +5 -0
- package/src/file/services/FileDetector.spec.ts +591 -0
- package/src/lock/core/__tests__/shared.ts +190 -0
- package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
- package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
- package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
- package/src/logger/index.ts +15 -3
- package/src/logger/primitives/$logger.spec.ts +108 -0
- package/src/logger/services/Logger.spec.ts +295 -0
- package/src/mcp/__tests__/errors.spec.ts +175 -0
- package/src/mcp/__tests__/integration.spec.ts +450 -0
- package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
- package/src/mcp/primitives/$prompt.spec.ts +468 -0
- package/src/mcp/primitives/$resource.spec.ts +390 -0
- package/src/mcp/primitives/$tool.spec.ts +406 -0
- package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
- package/src/mcp/transports/StdioMcpTransport.ts +1 -1
- package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
- package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
- package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
- package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
- package/src/orm/__tests__/$repository-save.spec.ts +37 -0
- package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
- package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
- package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
- package/src/orm/__tests__/delete-returning.spec.ts +256 -0
- package/src/orm/__tests__/deletedAt.spec.ts +80 -0
- package/src/orm/__tests__/enums.spec.ts +315 -0
- package/src/orm/__tests__/execute.spec.ts +72 -0
- package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
- package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
- package/src/orm/__tests__/joins.spec.ts +1114 -0
- package/src/orm/__tests__/page.spec.ts +287 -0
- package/src/orm/__tests__/primaryKey.spec.ts +87 -0
- package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
- package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
- package/src/orm/__tests__/references.spec.ts +102 -0
- package/src/orm/__tests__/security.spec.ts +710 -0
- package/src/orm/__tests__/sqlite.spec.ts +111 -0
- package/src/orm/__tests__/string-operators.spec.ts +429 -0
- package/src/orm/__tests__/timestamps.spec.ts +388 -0
- package/src/orm/__tests__/validation.spec.ts +183 -0
- package/src/orm/__tests__/version.spec.ts +64 -0
- package/src/orm/helpers/parseQueryString.spec.ts +196 -0
- package/src/orm/index.ts +2 -8
- package/src/orm/primitives/$repository.spec.ts +137 -0
- package/src/orm/primitives/$sequence.spec.ts +29 -0
- package/src/orm/primitives/$transaction.spec.ts +82 -0
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
- package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
- package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
- package/src/orm/services/ModelBuilder.spec.ts +575 -0
- package/src/orm/services/Repository.spec.ts +137 -0
- package/src/queue/core/__tests__/shared.ts +143 -0
- package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
- package/src/queue/core/providers/WorkerProvider.spec.ts +394 -0
- package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
- package/src/redis/__tests__/redis.spec.ts +58 -0
- package/src/retry/primitives/$retry.spec.ts +234 -0
- package/src/retry/providers/RetryProvider.spec.ts +438 -0
- package/src/router/__tests__/match.spec.ts +252 -0
- package/src/router/providers/RouterProvider.spec.ts +197 -0
- package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
- package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
- package/src/scheduler/__tests__/shared.ts +77 -0
- package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
- package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
- package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
- package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
- package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
- package/src/security/primitives/$permission.spec.ts +30 -0
- package/src/security/primitives/$permission.ts +2 -2
- package/src/security/primitives/$realm.spec.ts +101 -0
- package/src/security/primitives/$role.spec.ts +52 -0
- package/src/security/primitives/$serviceAccount.spec.ts +61 -0
- package/src/security/providers/SecurityProvider.spec.ts +350 -0
- package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
- package/src/server/cache/providers/ServerCacheProvider.spec.ts +1125 -0
- package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
- package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
- package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
- package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
- package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
- package/src/server/core/helpers/ServerReply.ts +2 -2
- package/src/server/core/primitives/$action.spec.ts +191 -0
- package/src/server/core/primitives/$route.spec.ts +65 -0
- package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
- package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
- package/src/server/core/providers/ServerProvider.ts +14 -2
- package/src/server/core/services/HttpClient.spec.ts +123 -0
- package/src/server/core/services/UserAgentParser.spec.ts +111 -0
- package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
- package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
- package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
- package/src/server/links/__tests__/$action.spec.ts +238 -0
- package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
- package/src/server/links/__tests__/requestId.spec.ts +120 -0
- package/src/server/links/primitives/$remote.spec.ts +228 -0
- package/src/server/links/providers/LinkProvider.spec.ts +54 -0
- package/src/server/links/providers/LinkProvider.ts +49 -3
- package/src/server/links/providers/ServerLinksProvider.ts +1 -53
- package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
- package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
- package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
- package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
- package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
- package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
- package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
- package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
- package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
- package/src/server/static/primitives/$serve.spec.ts +193 -0
- package/src/server/static/providers/ServerStaticProvider.ts +10 -0
- package/src/server/swagger/__tests__/ui.spec.ts +52 -0
- package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +19 -12
- package/src/sms/primitives/$sms.spec.ts +165 -0
- package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
- package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
- package/src/thread/primitives/$thread.spec.ts +186 -0
- package/src/topic/core/__tests__/shared.ts +144 -0
- package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
- package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
- package/src/vite/helpers/importViteReact.ts +13 -0
- package/src/vite/index.ts +1 -21
- package/src/vite/plugins/viteAlephaDev.ts +32 -5
- package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
- package/src/vite/tasks/buildClient.ts +11 -0
- package/src/vite/tasks/buildServer.ts +47 -3
- package/src/vite/tasks/devServer.ts +69 -0
- package/src/vite/tasks/index.ts +2 -1
- package/src/vite/tasks/runAlepha.ts +7 -1
- package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
- package/src/websocket/primitives/$channel.spec.ts +30 -0
- package/src/cli/assets/viteConfigTs.ts +0 -14
- package/src/cli/commands/run.ts +0 -24
- package/src/vite/plugins/viteAlepha.ts +0 -37
- package/src/vite/plugins/viteAlephaBuild.ts +0 -281
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import {
|
|
3
|
+
AlephaSecurity,
|
|
4
|
+
CryptoProvider,
|
|
5
|
+
InvalidCredentialsError,
|
|
6
|
+
} from "alepha/security";
|
|
7
|
+
import { describe, it } from "vitest";
|
|
8
|
+
import {
|
|
9
|
+
AlephaApiUsers,
|
|
10
|
+
SessionService,
|
|
11
|
+
UserRealmProvider,
|
|
12
|
+
UserService,
|
|
13
|
+
} from "../index.ts";
|
|
14
|
+
|
|
15
|
+
const setup = async (options?: { usernameEnabled?: boolean }) => {
|
|
16
|
+
const alepha = Alepha.create({
|
|
17
|
+
env: { LOG_LEVEL: "error" },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
alepha.with(AlephaSecurity);
|
|
21
|
+
alepha.with(AlephaApiUsers);
|
|
22
|
+
|
|
23
|
+
await alepha.start();
|
|
24
|
+
|
|
25
|
+
const sessionService = alepha.inject(SessionService);
|
|
26
|
+
|
|
27
|
+
// Configure realm settings if provided
|
|
28
|
+
if (options?.usernameEnabled) {
|
|
29
|
+
const userRealmProvider = alepha.inject(UserRealmProvider);
|
|
30
|
+
userRealmProvider.register("default", {
|
|
31
|
+
settings: {
|
|
32
|
+
usernameEnabled: true,
|
|
33
|
+
} as never,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
alepha,
|
|
39
|
+
sessionService,
|
|
40
|
+
userService: alepha.inject(UserService),
|
|
41
|
+
cryptoProvider: alepha.inject(CryptoProvider),
|
|
42
|
+
identities: sessionService.identities(),
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
describe("alepha/api/users - SessionService.login", () => {
|
|
47
|
+
it("should login successfully with valid credentials", async ({ expect }) => {
|
|
48
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
49
|
+
await setup();
|
|
50
|
+
|
|
51
|
+
// Create a test user
|
|
52
|
+
const user = await userService.users().create({
|
|
53
|
+
username: "loginsuccessuser",
|
|
54
|
+
email: "login-success@example.com",
|
|
55
|
+
roles: ["user"],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Create identity with password
|
|
59
|
+
const password = "securePassword123!";
|
|
60
|
+
const hashedPassword = await cryptoProvider.hashPassword(password);
|
|
61
|
+
|
|
62
|
+
await identities.create({
|
|
63
|
+
provider: "local",
|
|
64
|
+
providerUserId: "login-success@example.com",
|
|
65
|
+
userId: user.id,
|
|
66
|
+
password: hashedPassword,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Test login
|
|
70
|
+
const result = await sessionService.login(
|
|
71
|
+
"local",
|
|
72
|
+
"login-success@example.com",
|
|
73
|
+
password,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
expect(result?.id).toBe(user.id);
|
|
77
|
+
expect(result?.email).toBe("login-success@example.com");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should throw InvalidCredentialsError when identity not found", async ({
|
|
81
|
+
expect,
|
|
82
|
+
}) => {
|
|
83
|
+
const { sessionService } = await setup();
|
|
84
|
+
|
|
85
|
+
await expect(
|
|
86
|
+
sessionService.login("local", "nonexistent@example.com", "password"),
|
|
87
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should throw InvalidCredentialsError when password is invalid", async ({
|
|
91
|
+
expect,
|
|
92
|
+
}) => {
|
|
93
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
94
|
+
await setup();
|
|
95
|
+
|
|
96
|
+
// Create a test user
|
|
97
|
+
const user = await userService.users().create({
|
|
98
|
+
username: "invalidpassworduser",
|
|
99
|
+
email: "invalid-password@example.com",
|
|
100
|
+
roles: ["user"],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Create identity with password
|
|
104
|
+
const hashedPassword = await cryptoProvider.hashPassword("correctPassword");
|
|
105
|
+
|
|
106
|
+
await identities.create({
|
|
107
|
+
provider: "local",
|
|
108
|
+
providerUserId: "invalid-password@example.com",
|
|
109
|
+
userId: user.id,
|
|
110
|
+
password: hashedPassword,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Test login with wrong password
|
|
114
|
+
await expect(
|
|
115
|
+
sessionService.login(
|
|
116
|
+
"local",
|
|
117
|
+
"invalid-password@example.com",
|
|
118
|
+
"wrongPassword",
|
|
119
|
+
),
|
|
120
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should throw InvalidCredentialsError when identity has no password configured", async ({
|
|
124
|
+
expect,
|
|
125
|
+
}) => {
|
|
126
|
+
const { sessionService, userService, identities } = await setup();
|
|
127
|
+
|
|
128
|
+
// Create a test user
|
|
129
|
+
const user = await userService.users().create({
|
|
130
|
+
username: "nopassworduser",
|
|
131
|
+
email: "no-password@example.com",
|
|
132
|
+
roles: ["user"],
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Create identity without password
|
|
136
|
+
await identities.create({
|
|
137
|
+
provider: "local",
|
|
138
|
+
providerUserId: "no-password@example.com",
|
|
139
|
+
userId: user.id,
|
|
140
|
+
providerData: {}, // No password
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await expect(
|
|
144
|
+
sessionService.login("local", "no-password@example.com", "anyPassword"),
|
|
145
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should throw InvalidCredentialsError when user is deleted after identity creation", async ({
|
|
149
|
+
expect,
|
|
150
|
+
}) => {
|
|
151
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
152
|
+
await setup();
|
|
153
|
+
|
|
154
|
+
// Create a user, then delete them to simulate orphan identity
|
|
155
|
+
const user = await userService.users().create({
|
|
156
|
+
username: "orphanidentityuser",
|
|
157
|
+
email: "orphan-identity@example.com",
|
|
158
|
+
roles: ["user"],
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const hashedPassword = await cryptoProvider.hashPassword("password123");
|
|
162
|
+
|
|
163
|
+
await identities.create({
|
|
164
|
+
provider: "local",
|
|
165
|
+
providerUserId: "orphan-identity@example.com",
|
|
166
|
+
userId: user.id,
|
|
167
|
+
password: hashedPassword,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Delete the user to create orphan identity scenario
|
|
171
|
+
await userService.users().deleteById(user.id);
|
|
172
|
+
|
|
173
|
+
await expect(
|
|
174
|
+
sessionService.login(
|
|
175
|
+
"local",
|
|
176
|
+
"orphan-identity@example.com",
|
|
177
|
+
"password123",
|
|
178
|
+
),
|
|
179
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should throw InvalidCredentialsError with same message for all failure types", async ({
|
|
183
|
+
expect,
|
|
184
|
+
}) => {
|
|
185
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
186
|
+
await setup();
|
|
187
|
+
|
|
188
|
+
// Setup for invalid password test
|
|
189
|
+
const user = await userService.users().create({
|
|
190
|
+
username: "sameerroruser",
|
|
191
|
+
email: "same-error@example.com",
|
|
192
|
+
roles: ["user"],
|
|
193
|
+
});
|
|
194
|
+
const hashedPassword = await cryptoProvider.hashPassword("correctPass");
|
|
195
|
+
await identities.create({
|
|
196
|
+
provider: "local",
|
|
197
|
+
providerUserId: "same-error@example.com",
|
|
198
|
+
userId: user.id,
|
|
199
|
+
password: hashedPassword,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Test identity not found
|
|
203
|
+
try {
|
|
204
|
+
await sessionService.login("local", "notfound@example.com", "password");
|
|
205
|
+
} catch (error) {
|
|
206
|
+
expect(error).toBeInstanceOf(InvalidCredentialsError);
|
|
207
|
+
expect((error as Error).message).toBe("Invalid credentials");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Test invalid password
|
|
211
|
+
try {
|
|
212
|
+
await sessionService.login(
|
|
213
|
+
"local",
|
|
214
|
+
"same-error@example.com",
|
|
215
|
+
"wrongPassword",
|
|
216
|
+
);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
expect(error).toBeInstanceOf(InvalidCredentialsError);
|
|
219
|
+
expect((error as Error).message).toBe("Invalid credentials");
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("should include random delay to prevent timing attacks", async ({
|
|
224
|
+
expect,
|
|
225
|
+
}) => {
|
|
226
|
+
const { sessionService } = await setup();
|
|
227
|
+
|
|
228
|
+
const start = Date.now();
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
await sessionService.login(
|
|
232
|
+
"local",
|
|
233
|
+
"timing-attack@example.com",
|
|
234
|
+
"password",
|
|
235
|
+
);
|
|
236
|
+
} catch {
|
|
237
|
+
// Expected to fail
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const elapsed = Date.now() - start;
|
|
241
|
+
|
|
242
|
+
// Should take at least 50ms due to random delay
|
|
243
|
+
expect(elapsed).toBeGreaterThanOrEqual(50);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should handle different providers correctly", async ({ expect }) => {
|
|
247
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
248
|
+
await setup({ usernameEnabled: true });
|
|
249
|
+
|
|
250
|
+
const user = await userService.users().create({
|
|
251
|
+
username: "multiprovideruser",
|
|
252
|
+
email: "multi-provider@example.com",
|
|
253
|
+
roles: ["user"],
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Create identity for 'custom' provider
|
|
257
|
+
const hashedPassword = await cryptoProvider.hashPassword("customPass");
|
|
258
|
+
await identities.create({
|
|
259
|
+
provider: "custom",
|
|
260
|
+
userId: user.id,
|
|
261
|
+
password: hashedPassword,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Login with correct provider
|
|
265
|
+
const result = await sessionService.login(
|
|
266
|
+
"custom",
|
|
267
|
+
"multiprovideruser",
|
|
268
|
+
"customPass",
|
|
269
|
+
);
|
|
270
|
+
expect(result?.id).toBe(user.id);
|
|
271
|
+
|
|
272
|
+
// Should fail with wrong provider
|
|
273
|
+
await expect(
|
|
274
|
+
sessionService.login("local", "custom-user-id", "customPass"),
|
|
275
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("should handle empty password correctly", async ({ expect }) => {
|
|
279
|
+
const { sessionService, userService, cryptoProvider, identities } =
|
|
280
|
+
await setup();
|
|
281
|
+
|
|
282
|
+
const user = await userService.users().create({
|
|
283
|
+
username: "emptypassworduser",
|
|
284
|
+
email: "empty-password@example.com",
|
|
285
|
+
roles: ["user"],
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const hashedPassword = await cryptoProvider.hashPassword("realPassword");
|
|
289
|
+
await identities.create({
|
|
290
|
+
provider: "local",
|
|
291
|
+
providerUserId: "empty-password@example.com",
|
|
292
|
+
userId: user.id,
|
|
293
|
+
password: hashedPassword,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Empty password should fail
|
|
297
|
+
await expect(
|
|
298
|
+
sessionService.login("local", "empty-password@example.com", ""),
|
|
299
|
+
).rejects.toThrowError(InvalidCredentialsError);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomInt } from "node:crypto";
|
|
2
2
|
import { $inject, Alepha } from "alepha";
|
|
3
|
+
import { AuditService } from "alepha/api/audits";
|
|
3
4
|
import type { FileController } from "alepha/api/files";
|
|
4
5
|
import { DateTimeProvider } from "alepha/datetime";
|
|
5
6
|
import { FileSystemProvider } from "alepha/file";
|
|
@@ -23,6 +24,7 @@ export class SessionService {
|
|
|
23
24
|
protected readonly log = $logger();
|
|
24
25
|
protected readonly userRealmProvider = $inject(UserRealmProvider);
|
|
25
26
|
protected readonly fileController = $client<FileController>();
|
|
27
|
+
protected readonly auditService = $inject(AuditService);
|
|
26
28
|
|
|
27
29
|
public users(userRealmName?: string) {
|
|
28
30
|
return this.userRealmProvider.userRepository(userRealmName);
|
|
@@ -79,6 +81,13 @@ export class SessionService {
|
|
|
79
81
|
username,
|
|
80
82
|
realm: name,
|
|
81
83
|
});
|
|
84
|
+
|
|
85
|
+
await this.auditService.recordAuth("login_failed", {
|
|
86
|
+
userRealm: name,
|
|
87
|
+
description: "Invalid login identifier format",
|
|
88
|
+
metadata: { provider, username },
|
|
89
|
+
});
|
|
90
|
+
|
|
82
91
|
throw new InvalidCredentialsError();
|
|
83
92
|
}
|
|
84
93
|
|
|
@@ -89,6 +98,13 @@ export class SessionService {
|
|
|
89
98
|
username,
|
|
90
99
|
realm: name,
|
|
91
100
|
});
|
|
101
|
+
|
|
102
|
+
await this.auditService.recordAuth("login_failed", {
|
|
103
|
+
userRealm: name,
|
|
104
|
+
description: "User not found",
|
|
105
|
+
metadata: { provider, username },
|
|
106
|
+
});
|
|
107
|
+
|
|
92
108
|
throw new InvalidCredentialsError();
|
|
93
109
|
}
|
|
94
110
|
|
|
@@ -121,9 +137,26 @@ export class SessionService {
|
|
|
121
137
|
username,
|
|
122
138
|
realm: name,
|
|
123
139
|
});
|
|
140
|
+
|
|
141
|
+
await this.auditService.recordAuth("login_failed", {
|
|
142
|
+
userRealm: name,
|
|
143
|
+
resourceId: user.id,
|
|
144
|
+
description: "Invalid password",
|
|
145
|
+
metadata: { provider, username },
|
|
146
|
+
});
|
|
147
|
+
|
|
124
148
|
throw new InvalidCredentialsError();
|
|
125
149
|
}
|
|
126
150
|
|
|
151
|
+
await this.auditService.recordAuth("login", {
|
|
152
|
+
userId: user.id,
|
|
153
|
+
userEmail: user.email ?? undefined,
|
|
154
|
+
userRealm: name,
|
|
155
|
+
resourceId: user.id,
|
|
156
|
+
description: `User logged in via ${provider}`,
|
|
157
|
+
metadata: { provider, username },
|
|
158
|
+
});
|
|
159
|
+
|
|
127
160
|
return user;
|
|
128
161
|
} catch (error) {
|
|
129
162
|
if (error instanceof InvalidCredentialsError) {
|
|
@@ -204,6 +237,16 @@ export class SessionService {
|
|
|
204
237
|
userId: session.userId,
|
|
205
238
|
});
|
|
206
239
|
|
|
240
|
+
const { name } = this.userRealmProvider.getRealm(userRealmName);
|
|
241
|
+
|
|
242
|
+
await this.auditService.recordAuth("token_refresh", {
|
|
243
|
+
userId: user.id,
|
|
244
|
+
userEmail: user.email ?? undefined,
|
|
245
|
+
userRealm: name,
|
|
246
|
+
sessionId: session.id,
|
|
247
|
+
description: "Session token refreshed",
|
|
248
|
+
});
|
|
249
|
+
|
|
207
250
|
return {
|
|
208
251
|
user,
|
|
209
252
|
expiresIn: expiresAt.unix() - now.unix(),
|
|
@@ -213,10 +256,29 @@ export class SessionService {
|
|
|
213
256
|
|
|
214
257
|
public async deleteSession(refreshToken: string, userRealmName?: string) {
|
|
215
258
|
this.log.trace("Deleting session");
|
|
259
|
+
|
|
260
|
+
// Get session info before deletion for audit
|
|
261
|
+
const session = await this.sessions(userRealmName)
|
|
262
|
+
.findOne({
|
|
263
|
+
where: { refreshToken: { eq: refreshToken } },
|
|
264
|
+
})
|
|
265
|
+
.catch(() => undefined);
|
|
266
|
+
|
|
216
267
|
await this.sessions(userRealmName).deleteOne({
|
|
217
268
|
refreshToken,
|
|
218
269
|
});
|
|
219
270
|
this.log.debug("Session deleted");
|
|
271
|
+
|
|
272
|
+
if (session) {
|
|
273
|
+
const { name } = this.userRealmProvider.getRealm(userRealmName);
|
|
274
|
+
|
|
275
|
+
await this.auditService.recordAuth("logout", {
|
|
276
|
+
userId: session.userId,
|
|
277
|
+
userRealm: name,
|
|
278
|
+
sessionId: session.id,
|
|
279
|
+
description: "User logged out",
|
|
280
|
+
});
|
|
281
|
+
}
|
|
220
282
|
}
|
|
221
283
|
|
|
222
284
|
public async link(
|
|
@@ -250,7 +312,19 @@ export class SessionService {
|
|
|
250
312
|
identityId: identity.id,
|
|
251
313
|
userId: identity.userId,
|
|
252
314
|
});
|
|
253
|
-
|
|
315
|
+
|
|
316
|
+
const user = await users.findById(identity.userId);
|
|
317
|
+
|
|
318
|
+
await this.auditService.recordAuth("login", {
|
|
319
|
+
userId: user.id,
|
|
320
|
+
userEmail: user.email ?? undefined,
|
|
321
|
+
userRealm: realm.name,
|
|
322
|
+
resourceId: user.id,
|
|
323
|
+
description: `User logged in via OAuth2 (${provider})`,
|
|
324
|
+
metadata: { provider, providerUserId: profile.sub },
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return user;
|
|
254
328
|
}
|
|
255
329
|
|
|
256
330
|
if (!profile.email) {
|
|
@@ -284,6 +358,16 @@ export class SessionService {
|
|
|
284
358
|
providerUserId: profile.sub,
|
|
285
359
|
userId: existing.id,
|
|
286
360
|
});
|
|
361
|
+
|
|
362
|
+
await this.auditService.recordAuth("login", {
|
|
363
|
+
userId: existing.id,
|
|
364
|
+
userEmail: existing.email ?? undefined,
|
|
365
|
+
userRealm: realm.name,
|
|
366
|
+
resourceId: existing.id,
|
|
367
|
+
description: `OAuth2 identity linked to existing user (${provider})`,
|
|
368
|
+
metadata: { provider, providerUserId: profile.sub, linked: true },
|
|
369
|
+
});
|
|
370
|
+
|
|
287
371
|
return existing;
|
|
288
372
|
}
|
|
289
373
|
|
|
@@ -338,6 +422,31 @@ export class SessionService {
|
|
|
338
422
|
username: user.username,
|
|
339
423
|
});
|
|
340
424
|
|
|
425
|
+
// Audit: user created via OAuth
|
|
426
|
+
await this.auditService.recordUser("create", {
|
|
427
|
+
userId: user.id,
|
|
428
|
+
userEmail: user.email ?? undefined,
|
|
429
|
+
userRealm: realm.name,
|
|
430
|
+
resourceId: user.id,
|
|
431
|
+
description: `User created via OAuth2 (${provider})`,
|
|
432
|
+
metadata: {
|
|
433
|
+
provider,
|
|
434
|
+
providerUserId: profile.sub,
|
|
435
|
+
username: user.username,
|
|
436
|
+
email: user.email,
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// Audit: login event
|
|
441
|
+
await this.auditService.recordAuth("login", {
|
|
442
|
+
userId: user.id,
|
|
443
|
+
userEmail: user.email ?? undefined,
|
|
444
|
+
userRealm: realm.name,
|
|
445
|
+
resourceId: user.id,
|
|
446
|
+
description: `First login via OAuth2 (${provider})`,
|
|
447
|
+
metadata: { provider, providerUserId: profile.sub, firstLogin: true },
|
|
448
|
+
});
|
|
449
|
+
|
|
341
450
|
return user;
|
|
342
451
|
}
|
|
343
452
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { $inject } from "alepha";
|
|
2
|
+
import { AuditService } from "alepha/api/audits";
|
|
2
3
|
import type { VerificationController } from "alepha/api/verifications";
|
|
3
4
|
import { $logger } from "alepha/logger";
|
|
4
5
|
import { type Page, parseQueryString } from "alepha/orm";
|
|
@@ -16,6 +17,7 @@ export class UserService {
|
|
|
16
17
|
protected readonly verificationController = $client<VerificationController>();
|
|
17
18
|
protected readonly userNotifications = $inject(UserNotifications);
|
|
18
19
|
protected readonly userRealmProvider = $inject(UserRealmProvider);
|
|
20
|
+
protected readonly auditService = $inject(AuditService);
|
|
19
21
|
|
|
20
22
|
public users(userRealmName?: string) {
|
|
21
23
|
return this.userRealmProvider.userRepository(userRealmName);
|
|
@@ -153,6 +155,17 @@ export class UserService {
|
|
|
153
155
|
});
|
|
154
156
|
|
|
155
157
|
this.log.info("Email verified", { email, userId: user.id, type });
|
|
158
|
+
|
|
159
|
+
const realm = this.userRealmProvider.getRealm(userRealmName);
|
|
160
|
+
|
|
161
|
+
await this.auditService.recordUser("update", {
|
|
162
|
+
userId: user.id,
|
|
163
|
+
userEmail: email,
|
|
164
|
+
userRealm: realm.name,
|
|
165
|
+
resourceId: user.id,
|
|
166
|
+
description: "Email verified",
|
|
167
|
+
metadata: { email, verificationType: type },
|
|
168
|
+
});
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
/**
|
|
@@ -301,6 +314,17 @@ export class UserService {
|
|
|
301
314
|
email: user.email,
|
|
302
315
|
});
|
|
303
316
|
|
|
317
|
+
await this.auditService.recordUser("create", {
|
|
318
|
+
userRealm: realm.name,
|
|
319
|
+
resourceId: user.id,
|
|
320
|
+
description: "User created",
|
|
321
|
+
metadata: {
|
|
322
|
+
username: user.username,
|
|
323
|
+
email: user.email,
|
|
324
|
+
roles: user.roles,
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
|
|
304
328
|
return user;
|
|
305
329
|
}
|
|
306
330
|
|
|
@@ -313,10 +337,38 @@ export class UserService {
|
|
|
313
337
|
userRealmName?: string,
|
|
314
338
|
): Promise<UserEntity> {
|
|
315
339
|
this.log.trace("Updating user", { id, userRealmName });
|
|
316
|
-
await this.getUserById(id, userRealmName);
|
|
340
|
+
const before = await this.getUserById(id, userRealmName);
|
|
317
341
|
|
|
318
342
|
const user = await this.users(userRealmName).updateById(id, data);
|
|
319
343
|
this.log.debug("User updated", { userId: id });
|
|
344
|
+
|
|
345
|
+
const realm = this.userRealmProvider.getRealm(userRealmName);
|
|
346
|
+
|
|
347
|
+
// Build changes object showing what was updated
|
|
348
|
+
const changes: Record<string, { from: unknown; to: unknown }> = {};
|
|
349
|
+
for (const key of Object.keys(data) as (keyof UpdateUser)[]) {
|
|
350
|
+
if (data[key] !== undefined && before[key] !== data[key]) {
|
|
351
|
+
changes[key] = { from: before[key], to: data[key] };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Detect role changes for special handling
|
|
356
|
+
const isRoleChange =
|
|
357
|
+
data.roles !== undefined &&
|
|
358
|
+
JSON.stringify(before.roles) !== JSON.stringify(data.roles);
|
|
359
|
+
|
|
360
|
+
await this.auditService.recordUser(
|
|
361
|
+
isRoleChange ? "role_change" : "update",
|
|
362
|
+
{
|
|
363
|
+
userRealm: realm.name,
|
|
364
|
+
resourceId: user.id,
|
|
365
|
+
description: isRoleChange
|
|
366
|
+
? "User roles changed"
|
|
367
|
+
: `User updated: ${Object.keys(changes).join(", ")}`,
|
|
368
|
+
metadata: { changes },
|
|
369
|
+
},
|
|
370
|
+
);
|
|
371
|
+
|
|
320
372
|
return user;
|
|
321
373
|
}
|
|
322
374
|
|
|
@@ -325,9 +377,22 @@ export class UserService {
|
|
|
325
377
|
*/
|
|
326
378
|
public async deleteUser(id: string, userRealmName?: string): Promise<void> {
|
|
327
379
|
this.log.trace("Deleting user", { id, userRealmName });
|
|
328
|
-
await this.getUserById(id, userRealmName);
|
|
380
|
+
const user = await this.getUserById(id, userRealmName);
|
|
329
381
|
|
|
330
382
|
await this.users(userRealmName).deleteById(id);
|
|
331
383
|
this.log.info("User deleted", { userId: id });
|
|
384
|
+
|
|
385
|
+
const realm = this.userRealmProvider.getRealm(userRealmName);
|
|
386
|
+
|
|
387
|
+
await this.auditService.recordUser("delete", {
|
|
388
|
+
userRealm: realm.name,
|
|
389
|
+
resourceId: id,
|
|
390
|
+
severity: "warning",
|
|
391
|
+
description: "User deleted",
|
|
392
|
+
metadata: {
|
|
393
|
+
username: user.username,
|
|
394
|
+
email: user.email,
|
|
395
|
+
},
|
|
396
|
+
});
|
|
332
397
|
}
|
|
333
398
|
}
|