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,229 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { SecurityError, SecurityProvider } from "../index.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bug #1: Multi-layer Wildcard Permission Validation Fails After App Start
|
|
7
|
+
*
|
|
8
|
+
* Issue: When creating roles with multi-layer wildcard permissions (e.g., "admin:api:*")
|
|
9
|
+
* after app.start(), the validation logic only checked if parts[1] === "*", which fails
|
|
10
|
+
* for deeper wildcards.
|
|
11
|
+
*
|
|
12
|
+
* Expected: Multi-layer wildcards should be validated correctly by checking if any
|
|
13
|
+
* permission exists with the matching group prefix.
|
|
14
|
+
*/
|
|
15
|
+
describe("Bug #1: Multi-layer Wildcard Permission Validation After App Start", () => {
|
|
16
|
+
it("should allow creating role with 2-layer wildcard after app start", async () => {
|
|
17
|
+
const app = Alepha.create();
|
|
18
|
+
const sec = app.inject(SecurityProvider);
|
|
19
|
+
|
|
20
|
+
sec.createPermission("hello:hey");
|
|
21
|
+
sec.createPermission("hello:ho");
|
|
22
|
+
|
|
23
|
+
await app.start();
|
|
24
|
+
|
|
25
|
+
// This should work - 2-layer wildcard with existing permissions
|
|
26
|
+
expect(() =>
|
|
27
|
+
sec.createRole({
|
|
28
|
+
name: "superuser",
|
|
29
|
+
permissions: [{ name: "hello:*" }],
|
|
30
|
+
}),
|
|
31
|
+
).not.toThrow();
|
|
32
|
+
|
|
33
|
+
expect(sec.can("superuser", "hello:hey")).toEqual(true);
|
|
34
|
+
expect(sec.can("superuser", "hello:ho")).toEqual(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should allow creating role with 3-layer wildcard after app start", async () => {
|
|
38
|
+
const app = Alepha.create();
|
|
39
|
+
const sec = app.inject(SecurityProvider);
|
|
40
|
+
|
|
41
|
+
sec.createPermission("admin:api:users");
|
|
42
|
+
sec.createPermission("admin:api:posts");
|
|
43
|
+
|
|
44
|
+
await app.start();
|
|
45
|
+
|
|
46
|
+
// This is the bug - should work but previously failed
|
|
47
|
+
expect(() =>
|
|
48
|
+
sec.createRole({
|
|
49
|
+
name: "api-admin",
|
|
50
|
+
permissions: [{ name: "admin:api:*" }],
|
|
51
|
+
}),
|
|
52
|
+
).not.toThrow();
|
|
53
|
+
|
|
54
|
+
expect(sec.can("api-admin", "admin:api:users")).toEqual(true);
|
|
55
|
+
expect(sec.can("api-admin", "admin:api:posts")).toEqual(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should allow creating role with 4-layer wildcard after app start", async () => {
|
|
59
|
+
const app = Alepha.create();
|
|
60
|
+
const sec = app.inject(SecurityProvider);
|
|
61
|
+
|
|
62
|
+
sec.createPermission("admin:api:v1:users");
|
|
63
|
+
sec.createPermission("admin:api:v1:posts");
|
|
64
|
+
|
|
65
|
+
await app.start();
|
|
66
|
+
|
|
67
|
+
// Deep wildcard should work
|
|
68
|
+
expect(() =>
|
|
69
|
+
sec.createRole({
|
|
70
|
+
name: "api-v1-admin",
|
|
71
|
+
permissions: [{ name: "admin:api:v1:*" }],
|
|
72
|
+
}),
|
|
73
|
+
).not.toThrow();
|
|
74
|
+
|
|
75
|
+
expect(sec.can("api-v1-admin", "admin:api:v1:users")).toEqual(true);
|
|
76
|
+
expect(sec.can("api-v1-admin", "admin:api:v1:posts")).toEqual(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should allow wildcard that matches nested groups", async () => {
|
|
80
|
+
const app = Alepha.create();
|
|
81
|
+
const sec = app.inject(SecurityProvider);
|
|
82
|
+
|
|
83
|
+
// Create permissions with different nesting levels under same prefix
|
|
84
|
+
sec.createPermission("admin:api:users:read");
|
|
85
|
+
sec.createPermission("admin:api:users:write");
|
|
86
|
+
sec.createPermission("admin:api:posts:delete");
|
|
87
|
+
|
|
88
|
+
await app.start();
|
|
89
|
+
|
|
90
|
+
// Wildcard at intermediate level should work
|
|
91
|
+
expect(() =>
|
|
92
|
+
sec.createRole({
|
|
93
|
+
name: "api-manager",
|
|
94
|
+
permissions: [{ name: "admin:api:*" }],
|
|
95
|
+
}),
|
|
96
|
+
).not.toThrow();
|
|
97
|
+
|
|
98
|
+
expect(sec.can("api-manager", "admin:api:users:read")).toEqual(true);
|
|
99
|
+
expect(sec.can("api-manager", "admin:api:users:write")).toEqual(true);
|
|
100
|
+
expect(sec.can("api-manager", "admin:api:posts:delete")).toEqual(true);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("should reject wildcard when no matching permissions exist", async () => {
|
|
104
|
+
const app = Alepha.create();
|
|
105
|
+
const sec = app.inject(SecurityProvider);
|
|
106
|
+
|
|
107
|
+
sec.createPermission("hello:hey");
|
|
108
|
+
|
|
109
|
+
await app.start();
|
|
110
|
+
|
|
111
|
+
// This should fail - no permissions match "admin:*"
|
|
112
|
+
expect(() =>
|
|
113
|
+
sec.createRole({
|
|
114
|
+
name: "admin",
|
|
115
|
+
permissions: [{ name: "admin:*" }],
|
|
116
|
+
}),
|
|
117
|
+
).toThrow(SecurityError);
|
|
118
|
+
|
|
119
|
+
expect(() =>
|
|
120
|
+
sec.createRole({
|
|
121
|
+
name: "admin-api",
|
|
122
|
+
permissions: [{ name: "admin:api:*" }],
|
|
123
|
+
}),
|
|
124
|
+
).toThrow(SecurityError);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should allow global wildcard after app start", async () => {
|
|
128
|
+
const app = Alepha.create();
|
|
129
|
+
const sec = app.inject(SecurityProvider);
|
|
130
|
+
|
|
131
|
+
sec.createPermission("anything");
|
|
132
|
+
|
|
133
|
+
await app.start();
|
|
134
|
+
|
|
135
|
+
// Global wildcard should always work
|
|
136
|
+
expect(() =>
|
|
137
|
+
sec.createRole({
|
|
138
|
+
name: "admin",
|
|
139
|
+
permissions: [{ name: "*" }],
|
|
140
|
+
}),
|
|
141
|
+
).not.toThrow();
|
|
142
|
+
|
|
143
|
+
expect(sec.can("admin", "anything")).toEqual(true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should allow exact permission match after app start", async () => {
|
|
147
|
+
const app = Alepha.create();
|
|
148
|
+
const sec = app.inject(SecurityProvider);
|
|
149
|
+
|
|
150
|
+
sec.createPermission("admin:api:users:read");
|
|
151
|
+
|
|
152
|
+
await app.start();
|
|
153
|
+
|
|
154
|
+
// Exact permission should work
|
|
155
|
+
expect(() =>
|
|
156
|
+
sec.createRole({
|
|
157
|
+
name: "reader",
|
|
158
|
+
permissions: [{ name: "admin:api:users:read" }],
|
|
159
|
+
}),
|
|
160
|
+
).not.toThrow();
|
|
161
|
+
|
|
162
|
+
expect(sec.can("reader", "admin:api:users:read")).toEqual(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should reject exact permission when it doesn't exist", async () => {
|
|
166
|
+
const app = Alepha.create();
|
|
167
|
+
const sec = app.inject(SecurityProvider);
|
|
168
|
+
|
|
169
|
+
sec.createPermission("hello:hey");
|
|
170
|
+
|
|
171
|
+
await app.start();
|
|
172
|
+
|
|
173
|
+
// Non-existent exact permission should fail
|
|
174
|
+
expect(() =>
|
|
175
|
+
sec.createRole({
|
|
176
|
+
name: "user",
|
|
177
|
+
permissions: [{ name: "admin:api:users:read" }],
|
|
178
|
+
}),
|
|
179
|
+
).toThrow(SecurityError);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should handle mixed wildcards and exact permissions", async () => {
|
|
183
|
+
const app = Alepha.create();
|
|
184
|
+
const sec = app.inject(SecurityProvider);
|
|
185
|
+
|
|
186
|
+
sec.createPermission("admin:api:users:read");
|
|
187
|
+
sec.createPermission("admin:api:posts:write");
|
|
188
|
+
sec.createPermission("public:read");
|
|
189
|
+
|
|
190
|
+
await app.start();
|
|
191
|
+
|
|
192
|
+
// Mix of wildcard and exact should work if all exist
|
|
193
|
+
expect(() =>
|
|
194
|
+
sec.createRole({
|
|
195
|
+
name: "mixed",
|
|
196
|
+
permissions: [
|
|
197
|
+
{ name: "admin:api:*" }, // wildcard - should match
|
|
198
|
+
{ name: "public:read" }, // exact - exists
|
|
199
|
+
],
|
|
200
|
+
}),
|
|
201
|
+
).not.toThrow();
|
|
202
|
+
|
|
203
|
+
expect(sec.can("mixed", "admin:api:users:read")).toEqual(true);
|
|
204
|
+
expect(sec.can("mixed", "public:read")).toEqual(true);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should handle wildcard at exact group level", async () => {
|
|
208
|
+
const app = Alepha.create();
|
|
209
|
+
const sec = app.inject(SecurityProvider);
|
|
210
|
+
|
|
211
|
+
// Permission with exact group "admin:api"
|
|
212
|
+
sec.createPermission({ group: "admin:api", name: "execute" });
|
|
213
|
+
// Permission with nested group "admin:api:users"
|
|
214
|
+
sec.createPermission({ group: "admin:api:users", name: "read" });
|
|
215
|
+
|
|
216
|
+
await app.start();
|
|
217
|
+
|
|
218
|
+
// Wildcard "admin:api:*" should match both
|
|
219
|
+
expect(() =>
|
|
220
|
+
sec.createRole({
|
|
221
|
+
name: "api-all",
|
|
222
|
+
permissions: [{ name: "admin:api:*" }],
|
|
223
|
+
}),
|
|
224
|
+
).not.toThrow();
|
|
225
|
+
|
|
226
|
+
expect(sec.can("api-all", "admin:api:execute")).toEqual(true);
|
|
227
|
+
expect(sec.can("api-all", "admin:api:users:read")).toEqual(true);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { CryptoProvider } from "../index.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bug #2: Password Verification Missing Input Validation
|
|
7
|
+
*
|
|
8
|
+
* Issue: The verifyPassword method didn't validate input format before processing,
|
|
9
|
+
* leading to crashes when:
|
|
10
|
+
* - stored hash is malformed (missing colon, wrong format)
|
|
11
|
+
* - stored hash has incorrect length
|
|
12
|
+
* - timingSafeEqual throws when buffer lengths differ
|
|
13
|
+
*
|
|
14
|
+
* Expected: All invalid inputs should return false gracefully instead of throwing.
|
|
15
|
+
*/
|
|
16
|
+
describe("Bug #2: Password Verification Missing Input Validation", () => {
|
|
17
|
+
it("should verify valid password correctly", async () => {
|
|
18
|
+
const app = Alepha.create();
|
|
19
|
+
const crypto = app.inject(CryptoProvider);
|
|
20
|
+
|
|
21
|
+
const password = "mySecurePassword123!";
|
|
22
|
+
const hashed = await crypto.hashPassword(password);
|
|
23
|
+
|
|
24
|
+
const isValid = await crypto.verifyPassword(password, hashed);
|
|
25
|
+
expect(isValid).toBe(true);
|
|
26
|
+
|
|
27
|
+
const isInvalid = await crypto.verifyPassword("wrongPassword", hashed);
|
|
28
|
+
expect(isInvalid).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should return false for malformed hash with no colon", async () => {
|
|
32
|
+
const app = Alepha.create();
|
|
33
|
+
const crypto = app.inject(CryptoProvider);
|
|
34
|
+
|
|
35
|
+
const malformed = "notavalidhashwithoutcolon";
|
|
36
|
+
|
|
37
|
+
// Should not throw, should return false
|
|
38
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
39
|
+
expect(result).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should return false for hash with multiple colons", async () => {
|
|
43
|
+
const app = Alepha.create();
|
|
44
|
+
const crypto = app.inject(CryptoProvider);
|
|
45
|
+
|
|
46
|
+
const malformed = "salt:hash:extra";
|
|
47
|
+
|
|
48
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
49
|
+
expect(result).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should return false for empty string", async () => {
|
|
53
|
+
const app = Alepha.create();
|
|
54
|
+
const crypto = app.inject(CryptoProvider);
|
|
55
|
+
|
|
56
|
+
const result = await crypto.verifyPassword("password", "");
|
|
57
|
+
expect(result).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should return false for hash with empty salt", async () => {
|
|
61
|
+
const app = Alepha.create();
|
|
62
|
+
const crypto = app.inject(CryptoProvider);
|
|
63
|
+
|
|
64
|
+
const malformed = ":somehashvalue";
|
|
65
|
+
|
|
66
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
67
|
+
expect(result).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should return false for hash with empty hash value", async () => {
|
|
71
|
+
const app = Alepha.create();
|
|
72
|
+
const crypto = app.inject(CryptoProvider);
|
|
73
|
+
|
|
74
|
+
const malformed = "somesalt:";
|
|
75
|
+
|
|
76
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
77
|
+
expect(result).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should return false for just a colon", async () => {
|
|
81
|
+
const app = Alepha.create();
|
|
82
|
+
const crypto = app.inject(CryptoProvider);
|
|
83
|
+
|
|
84
|
+
const malformed = ":";
|
|
85
|
+
|
|
86
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
87
|
+
expect(result).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should return false for invalid hex in hash portion", async () => {
|
|
91
|
+
const app = Alepha.create();
|
|
92
|
+
const crypto = app.inject(CryptoProvider);
|
|
93
|
+
|
|
94
|
+
// Valid salt, but hash contains non-hex characters
|
|
95
|
+
const malformed = "validSalt123:notHexChars!@#";
|
|
96
|
+
|
|
97
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
98
|
+
expect(result).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should return false for odd-length hex string", async () => {
|
|
102
|
+
const app = Alepha.create();
|
|
103
|
+
const crypto = app.inject(CryptoProvider);
|
|
104
|
+
|
|
105
|
+
// Hex strings must have even length (2 chars per byte)
|
|
106
|
+
const malformed = "salt:abc"; // 3 chars, odd
|
|
107
|
+
|
|
108
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
109
|
+
expect(result).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should return false for hash with wrong length", async () => {
|
|
113
|
+
const app = Alepha.create();
|
|
114
|
+
const crypto = app.inject(CryptoProvider);
|
|
115
|
+
|
|
116
|
+
// Valid hex, but wrong length (scrypt produces 64 bytes = 128 hex chars)
|
|
117
|
+
const malformed = "salt:abcd"; // Only 4 hex chars = 2 bytes
|
|
118
|
+
|
|
119
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
120
|
+
expect(result).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should return false for corrupted but well-formed hash", async () => {
|
|
124
|
+
const app = Alepha.create();
|
|
125
|
+
const crypto = app.inject(CryptoProvider);
|
|
126
|
+
|
|
127
|
+
const password = "testPassword";
|
|
128
|
+
const hashed = await crypto.hashPassword(password);
|
|
129
|
+
|
|
130
|
+
// Corrupt the hash by changing one character
|
|
131
|
+
const removedChar = hashed.slice(-1);
|
|
132
|
+
const corrupted = hashed.slice(0, -1) + (removedChar === "0" ? "1" : "0");
|
|
133
|
+
|
|
134
|
+
const result = await crypto.verifyPassword(password, corrupted);
|
|
135
|
+
expect(result).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should return false for null or undefined input", async () => {
|
|
139
|
+
const app = Alepha.create();
|
|
140
|
+
const crypto = app.inject(CryptoProvider);
|
|
141
|
+
|
|
142
|
+
// @ts-expect-error - testing runtime behavior
|
|
143
|
+
const resultNull = await crypto.verifyPassword("password", null);
|
|
144
|
+
expect(resultNull).toBe(false);
|
|
145
|
+
|
|
146
|
+
// @ts-expect-error - testing runtime behavior
|
|
147
|
+
const resultUndefined = await crypto.verifyPassword("password", undefined);
|
|
148
|
+
expect(resultUndefined).toBe(false);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should return false for non-string input", async () => {
|
|
152
|
+
const app = Alepha.create();
|
|
153
|
+
const crypto = app.inject(CryptoProvider);
|
|
154
|
+
|
|
155
|
+
// @ts-expect-error - testing runtime behavior
|
|
156
|
+
const resultNumber = await crypto.verifyPassword("password", 12345);
|
|
157
|
+
expect(resultNumber).toBe(false);
|
|
158
|
+
|
|
159
|
+
// @ts-expect-error - testing runtime behavior
|
|
160
|
+
const resultObject = await crypto.verifyPassword("password", {
|
|
161
|
+
hash: "test",
|
|
162
|
+
});
|
|
163
|
+
expect(resultObject).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should handle special characters in salt gracefully", async () => {
|
|
167
|
+
const app = Alepha.create();
|
|
168
|
+
const crypto = app.inject(CryptoProvider);
|
|
169
|
+
|
|
170
|
+
// If somehow a salt with special chars got stored
|
|
171
|
+
const malformed =
|
|
172
|
+
"salt\nwith\nnewlines:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
|
173
|
+
|
|
174
|
+
// Should not crash, should return false (likely during scrypt or comparison)
|
|
175
|
+
const result = await crypto.verifyPassword("password", malformed);
|
|
176
|
+
expect(result).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should validate format before attempting expensive scrypt operation", async () => {
|
|
180
|
+
const app = Alepha.create();
|
|
181
|
+
const crypto = app.inject(CryptoProvider);
|
|
182
|
+
|
|
183
|
+
// These should fail fast without calling scrypt
|
|
184
|
+
const invalidFormats = [
|
|
185
|
+
"no-colon-at-all",
|
|
186
|
+
"too:many:colons:here",
|
|
187
|
+
":no-salt",
|
|
188
|
+
"no-hash:",
|
|
189
|
+
":",
|
|
190
|
+
"",
|
|
191
|
+
"salt:invalidhex!",
|
|
192
|
+
"salt:abc", // odd length
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
for (const invalid of invalidFormats) {
|
|
196
|
+
const result = await crypto.verifyPassword("password", invalid);
|
|
197
|
+
expect(result).toBe(false);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should properly handle valid hash format with correct verification", async () => {
|
|
202
|
+
const app = Alepha.create();
|
|
203
|
+
const crypto = app.inject(CryptoProvider);
|
|
204
|
+
|
|
205
|
+
// Test multiple passwords
|
|
206
|
+
const passwords = [
|
|
207
|
+
"simple",
|
|
208
|
+
"with spaces",
|
|
209
|
+
"special!@#$%^&*()",
|
|
210
|
+
"emoji🔐🔑",
|
|
211
|
+
`${"very".repeat(100)}long`,
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
for (const password of passwords) {
|
|
215
|
+
const hashed = await crypto.hashPassword(password);
|
|
216
|
+
|
|
217
|
+
// Verify format is correct (salt:hash with 128 hex chars for hash)
|
|
218
|
+
expect(hashed).toMatch(/^[0-9a-f]+:[0-9a-f]{128}$/i);
|
|
219
|
+
|
|
220
|
+
// Correct password should verify
|
|
221
|
+
expect(await crypto.verifyPassword(password, hashed)).toBe(true);
|
|
222
|
+
|
|
223
|
+
// Wrong password should not verify
|
|
224
|
+
expect(await crypto.verifyPassword(`${password}wrong`, hashed)).toBe(
|
|
225
|
+
false,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should prevent timing attacks with constant-time comparison", async () => {
|
|
231
|
+
const app = Alepha.create();
|
|
232
|
+
const crypto = app.inject(CryptoProvider);
|
|
233
|
+
|
|
234
|
+
const password = "testPassword";
|
|
235
|
+
const hashed = await crypto.hashPassword(password);
|
|
236
|
+
|
|
237
|
+
// Both wrong passwords should take similar time (constant-time comparison)
|
|
238
|
+
// This is a behavioral test - we're just checking they both return false
|
|
239
|
+
const wrongPassword1 = "x";
|
|
240
|
+
const wrongPassword2 = "x".repeat(100);
|
|
241
|
+
|
|
242
|
+
expect(await crypto.verifyPassword(wrongPassword1, hashed)).toBe(false);
|
|
243
|
+
expect(await crypto.verifyPassword(wrongPassword2, hashed)).toBe(false);
|
|
244
|
+
});
|
|
245
|
+
});
|