alepha 0.14.4 → 0.15.1
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 +44 -102
- package/dist/api/audits/index.d.ts +331 -443
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +2 -2
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +0 -113
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +2 -3
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +151 -262
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.browser.js +4 -4
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +164 -276
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +4 -4
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +265 -377
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.browser.js +1 -2
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +195 -301
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +203 -184
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +1 -2
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +2 -2
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/cli/index.d.ts +5900 -165
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1481 -639
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +8 -4
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +29 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +563 -54
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +175 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +564 -54
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +563 -54
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +4 -4
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +89 -42
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +129 -33
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +7969 -2
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +22 -22
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +134 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +253 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +1 -2
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +1 -5
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +19 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +28 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/chunk-DH6iiROE.js +38 -0
- package/dist/orm/index.browser.js +9 -9
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +2821 -0
- package/dist/orm/index.bun.js.map +1 -0
- package/dist/orm/index.d.ts +318 -169
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +2086 -1776
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +4 -4
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/redis/index.bun.js +285 -0
- package/dist/redis/index.bun.js.map +1 -0
- package/dist/redis/index.d.ts +13 -31
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +18 -38
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +83 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +393 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.browser.js +5 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +598 -112
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1808 -97
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1200 -175
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +1268 -37
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +6 -3
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +1 -1
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +3 -3
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +115 -13
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +321 -139
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +0 -1
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +0 -1
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js +9 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +1 -2
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +14 -7
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +514 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4462 -4
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +0 -1
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +1 -2
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +3 -1
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +10 -10
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +0 -1
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/thread/index.js +2 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/vite/index.d.ts +6315 -149
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +140 -469
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +9 -9
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +28 -28
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +9 -9
- package/dist/websocket/index.js.map +1 -1
- package/package.json +13 -18
- package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
- package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
- package/src/api/users/entities/users.ts +1 -1
- package/src/api/users/index.ts +8 -8
- package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
- package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
- package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
- package/src/api/users/services/CredentialService.ts +7 -7
- package/src/api/users/services/IdentityService.ts +4 -4
- package/src/api/users/services/RegistrationService.spec.ts +25 -27
- package/src/api/users/services/RegistrationService.ts +38 -27
- package/src/api/users/services/SessionCrudService.ts +3 -3
- package/src/api/users/services/SessionService.spec.ts +3 -3
- package/src/api/users/services/SessionService.ts +27 -18
- package/src/api/users/services/UserService.ts +7 -7
- package/src/batch/providers/BatchProvider.ts +1 -2
- package/src/cli/apps/AlephaCli.ts +2 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
- package/src/cli/assets/apiHelloControllerTs.ts +19 -0
- package/src/cli/assets/apiIndexTs.ts +16 -0
- package/src/cli/assets/biomeJson.ts +2 -1
- package/src/cli/assets/claudeMd.ts +308 -0
- package/src/cli/assets/dummySpecTs.ts +2 -1
- package/src/cli/assets/editorconfig.ts +2 -1
- package/src/cli/assets/mainBrowserTs.ts +4 -3
- package/src/cli/assets/mainCss.ts +24 -0
- package/src/cli/assets/mainServerTs.ts +24 -0
- package/src/cli/assets/tsconfigJson.ts +2 -1
- package/src/cli/assets/webAppRouterTs.ts +16 -0
- package/src/cli/assets/webHelloComponentTsx.ts +20 -0
- package/src/cli/assets/webIndexTs.ts +16 -0
- package/src/cli/atoms/appEntryOptions.ts +13 -0
- package/src/cli/atoms/buildOptions.ts +1 -1
- package/src/cli/atoms/changelogOptions.ts +1 -1
- package/src/cli/commands/build.ts +97 -61
- package/src/cli/commands/db.ts +21 -18
- package/src/cli/commands/deploy.ts +17 -5
- package/src/cli/commands/dev.ts +26 -47
- package/src/cli/commands/gen/env.ts +1 -1
- package/src/cli/commands/init.ts +79 -25
- package/src/cli/commands/lint.ts +9 -3
- package/src/cli/commands/test.ts +8 -2
- package/src/cli/commands/typecheck.ts +5 -1
- package/src/cli/commands/verify.ts +4 -2
- package/src/cli/defineConfig.ts +9 -0
- package/src/cli/index.ts +2 -1
- package/src/cli/providers/AppEntryProvider.ts +131 -0
- package/src/cli/providers/ViteBuildProvider.ts +82 -0
- package/src/cli/providers/ViteDevServerProvider.ts +350 -0
- package/src/cli/providers/ViteTemplateProvider.ts +27 -0
- package/src/cli/services/AlephaCliUtils.ts +72 -602
- package/src/cli/services/PackageManagerUtils.ts +308 -0
- package/src/cli/services/ProjectScaffolder.ts +329 -0
- package/src/command/helpers/Runner.ts +15 -3
- package/src/core/Alepha.ts +2 -8
- package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +2 -0
- package/src/core/primitives/$hook.ts +6 -2
- package/src/core/primitives/$module.spec.ts +4 -0
- package/src/core/primitives/$module.ts +12 -0
- package/src/core/providers/AlsProvider.ts +1 -1
- package/src/core/providers/CodecManager.spec.ts +12 -6
- package/src/core/providers/CodecManager.ts +26 -6
- package/src/core/providers/EventManager.ts +169 -13
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
- package/src/core/providers/SchemaValidator.spec.ts +236 -0
- package/src/core/providers/StateManager.spec.ts +27 -16
- package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
- package/src/email/providers/LocalEmailProvider.ts +52 -15
- package/src/email/providers/NodemailerEmailProvider.ts +167 -56
- package/src/file/errors/FileError.ts +7 -0
- package/src/file/index.ts +9 -1
- package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
- package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
- package/src/mcp/errors/McpError.ts +30 -0
- package/src/mcp/index.ts +3 -0
- package/src/mcp/transports/SseMcpTransport.ts +16 -6
- package/src/orm/index.browser.ts +1 -19
- package/src/orm/index.bun.ts +77 -0
- package/src/orm/index.shared-server.ts +22 -0
- package/src/orm/index.shared.ts +15 -0
- package/src/orm/index.ts +19 -39
- package/src/orm/providers/DrizzleKitProvider.ts +3 -5
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
- package/src/orm/services/Repository.ts +19 -0
- package/src/redis/index.bun.ts +35 -0
- package/src/redis/providers/BunRedisProvider.ts +12 -43
- package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
- package/src/redis/providers/NodeRedisProvider.ts +16 -34
- package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
- package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
- package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
- package/src/security/index.browser.ts +5 -0
- package/src/security/index.ts +90 -7
- package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
- package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
- package/src/security/primitives/$role.ts +5 -5
- package/src/security/primitives/$serviceAccount.spec.ts +5 -5
- package/src/security/primitives/$serviceAccount.ts +3 -3
- package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
- package/src/server/auth/primitives/$auth.ts +10 -10
- package/src/server/auth/primitives/$authCredentials.ts +3 -3
- package/src/server/auth/primitives/$authGithub.ts +3 -3
- package/src/server/auth/primitives/$authGoogle.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
- package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
- package/src/server/core/index.ts +1 -1
- package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
- package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
- package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
- package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
- package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
- package/src/server/core/providers/ServerProvider.ts +144 -24
- package/src/server/core/providers/ServerRouterProvider.ts +259 -115
- package/src/server/core/providers/ServerTimingProvider.ts +2 -2
- package/src/server/links/atoms/apiLinksAtom.ts +7 -0
- package/src/server/links/index.browser.ts +2 -0
- package/src/server/links/index.ts +3 -1
- package/src/server/links/providers/LinkProvider.ts +1 -1
- package/src/server/swagger/index.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
- package/src/sms/providers/LocalSmsProvider.ts +8 -7
- package/src/vite/index.ts +3 -2
- package/src/vite/tasks/buildClient.ts +0 -1
- package/src/vite/tasks/buildServer.ts +80 -22
- package/src/vite/tasks/copyAssets.ts +5 -4
- package/src/vite/tasks/generateCloudflare.ts +7 -0
- package/src/vite/tasks/generateSitemap.ts +64 -23
- package/src/vite/tasks/index.ts +0 -2
- package/src/vite/tasks/prerenderPages.ts +49 -24
- package/dist/server/security/index.browser.js +0 -13
- package/dist/server/security/index.browser.js.map +0 -1
- package/dist/server/security/index.d.ts +0 -173
- package/dist/server/security/index.d.ts.map +0 -1
- package/dist/server/security/index.js +0 -311
- package/dist/server/security/index.js.map +0 -1
- package/src/cli/assets/appRouterTs.ts +0 -9
- package/src/cli/assets/indexHtml.ts +0 -15
- package/src/cli/assets/mainTs.ts +0 -13
- package/src/cli/commands/format.ts +0 -17
- package/src/server/security/index.browser.ts +0 -10
- package/src/server/security/index.ts +0 -94
- package/src/vite/helpers/boot.ts +0 -106
- package/src/vite/plugins/viteAlephaDev.ts +0 -177
- package/src/vite/tasks/devServer.ts +0 -69
- package/src/vite/tasks/runAlepha.ts +0 -270
- /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
package/dist/api/users/index.js
CHANGED
|
@@ -10,11 +10,11 @@ import { AlephaApiAudits, AuditService } from "alepha/api/audits";
|
|
|
10
10
|
import { $logger } from "alepha/logger";
|
|
11
11
|
import { $bucket } from "alepha/bucket";
|
|
12
12
|
import { $client } from "alepha/server/links";
|
|
13
|
+
import { $authCredentials, $authGithub, $authGoogle, ServerAuthProvider, authenticationProviderSchema } from "alepha/server/auth";
|
|
13
14
|
import { randomInt, randomUUID } from "node:crypto";
|
|
14
15
|
import { $cache } from "alepha/cache";
|
|
15
16
|
import { DateTimeProvider } from "alepha/datetime";
|
|
16
|
-
import { $
|
|
17
|
-
import { $authCredentials, $authGithub, $authGoogle, ServerAuthProvider, authenticationProviderSchema } from "alepha/server/auth";
|
|
17
|
+
import { $issuer, CryptoProvider, InvalidCredentialsError, SecurityProvider } from "alepha/security";
|
|
18
18
|
import { FileSystemProvider } from "alepha/file";
|
|
19
19
|
import { AlephaApiFiles } from "alepha/api/files";
|
|
20
20
|
|
|
@@ -37,8 +37,7 @@ const users = $entity({
|
|
|
37
37
|
realm: db.default(t.text(), DEFAULT_USER_REALM_NAME),
|
|
38
38
|
username: t.optional(t.shortText({
|
|
39
39
|
minLength: 3,
|
|
40
|
-
maxLength: 50
|
|
41
|
-
pattern: "^[a-zA-Z0-9._-]+$"
|
|
40
|
+
maxLength: 50
|
|
42
41
|
})),
|
|
43
42
|
email: t.optional(t.string({ format: "email" })),
|
|
44
43
|
phoneNumber: t.optional(t.e164()),
|
|
@@ -99,6 +98,7 @@ const realmAuthSettingsAtom = $atom({
|
|
|
99
98
|
emailRequired: t.boolean({ description: "Require email address for user accounts" }),
|
|
100
99
|
usernameEnabled: t.boolean({ description: "Enable username as a login/registration credential" }),
|
|
101
100
|
usernameRequired: t.boolean({ description: "Require username for user accounts" }),
|
|
101
|
+
usernameRegExp: t.string({ description: "Regular expression that usernames must match (if username is enabled)" }),
|
|
102
102
|
phoneEnabled: t.boolean({ description: "Enable phone number as a login/registration credential" }),
|
|
103
103
|
phoneRequired: t.boolean({ description: "Require phone number for user accounts" }),
|
|
104
104
|
verifyEmailRequired: t.boolean({ description: "Require email verification for user accounts" }),
|
|
@@ -124,6 +124,7 @@ const realmAuthSettingsAtom = $atom({
|
|
|
124
124
|
emailRequired: true,
|
|
125
125
|
usernameEnabled: false,
|
|
126
126
|
usernameRequired: false,
|
|
127
|
+
usernameRegExp: "^[a-zA-Z0-9_]{3,30}$",
|
|
127
128
|
phoneEnabled: false,
|
|
128
129
|
phoneRequired: false,
|
|
129
130
|
verifyEmailRequired: false,
|
|
@@ -167,8 +168,8 @@ const sessions = $entity({
|
|
|
167
168
|
});
|
|
168
169
|
|
|
169
170
|
//#endregion
|
|
170
|
-
//#region ../../src/api/users/providers/
|
|
171
|
-
var
|
|
171
|
+
//#region ../../src/api/users/providers/RealmProvider.ts
|
|
172
|
+
var RealmProvider = class {
|
|
172
173
|
alepha = $inject(Alepha);
|
|
173
174
|
defaultIdentities = $repository(identities);
|
|
174
175
|
defaultSessions = $repository(sessions);
|
|
@@ -193,46 +194,46 @@ var UserRealmProvider = class {
|
|
|
193
194
|
});
|
|
194
195
|
}
|
|
195
196
|
});
|
|
196
|
-
register(
|
|
197
|
-
this.realms.set(
|
|
198
|
-
name:
|
|
197
|
+
register(realmName, realmOptions = {}) {
|
|
198
|
+
this.realms.set(realmName, {
|
|
199
|
+
name: realmName,
|
|
199
200
|
repositories: {
|
|
200
|
-
identities:
|
|
201
|
-
sessions:
|
|
202
|
-
users:
|
|
201
|
+
identities: realmOptions.entities?.identities ?? this.defaultIdentities,
|
|
202
|
+
sessions: realmOptions.entities?.sessions ?? this.defaultSessions,
|
|
203
|
+
users: realmOptions.entities?.users ?? this.defaultUsers
|
|
203
204
|
},
|
|
204
205
|
settings: {
|
|
205
206
|
...realmAuthSettingsAtom.options.default,
|
|
206
|
-
...
|
|
207
|
+
...realmOptions.settings,
|
|
207
208
|
passwordPolicy: {
|
|
208
209
|
...realmAuthSettingsAtom.options.default.passwordPolicy,
|
|
209
|
-
...
|
|
210
|
+
...realmOptions.settings?.passwordPolicy
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
});
|
|
213
|
-
return this.getRealm(
|
|
214
|
+
return this.getRealm(realmName);
|
|
214
215
|
}
|
|
215
216
|
/**
|
|
216
217
|
* Gets a registered realm by name, auto-creating default if needed.
|
|
217
218
|
*/
|
|
218
|
-
getRealm(
|
|
219
|
-
let realm = this.realms.get(
|
|
219
|
+
getRealm(realmName = DEFAULT_USER_REALM_NAME) {
|
|
220
|
+
let realm = this.realms.get(realmName);
|
|
220
221
|
if (!realm) {
|
|
221
222
|
const firstRealm = Array.from(this.realms.values())[0];
|
|
222
|
-
if (
|
|
223
|
-
else if (this.alepha.isTest()) realm = this.register(
|
|
224
|
-
else throw new AlephaError(`Missing
|
|
223
|
+
if (realmName === DEFAULT_USER_REALM_NAME && firstRealm) realm = firstRealm;
|
|
224
|
+
else if (this.alepha.isTest()) realm = this.register(realmName);
|
|
225
|
+
else throw new AlephaError(`Missing realm '${realmName}', please declare $realm in your application.`);
|
|
225
226
|
}
|
|
226
227
|
return realm;
|
|
227
228
|
}
|
|
228
|
-
identityRepository(
|
|
229
|
-
return this.getRealm(
|
|
229
|
+
identityRepository(realmName = DEFAULT_USER_REALM_NAME) {
|
|
230
|
+
return this.getRealm(realmName).repositories.identities;
|
|
230
231
|
}
|
|
231
|
-
sessionRepository(
|
|
232
|
-
return this.getRealm(
|
|
232
|
+
sessionRepository(realmName = DEFAULT_USER_REALM_NAME) {
|
|
233
|
+
return this.getRealm(realmName).repositories.sessions;
|
|
233
234
|
}
|
|
234
|
-
userRepository(
|
|
235
|
-
return this.getRealm(
|
|
235
|
+
userRepository(realmName = DEFAULT_USER_REALM_NAME) {
|
|
236
|
+
return this.getRealm(realmName).repositories.users;
|
|
236
237
|
}
|
|
237
238
|
};
|
|
238
239
|
|
|
@@ -240,10 +241,10 @@ var UserRealmProvider = class {
|
|
|
240
241
|
//#region ../../src/api/users/services/IdentityService.ts
|
|
241
242
|
var IdentityService = class {
|
|
242
243
|
log = $logger();
|
|
243
|
-
|
|
244
|
+
realmProvider = $inject(RealmProvider);
|
|
244
245
|
auditService = $inject(AuditService);
|
|
245
246
|
identities(userRealmName) {
|
|
246
|
-
return this.
|
|
247
|
+
return this.realmProvider.identityRepository(userRealmName);
|
|
247
248
|
}
|
|
248
249
|
/**
|
|
249
250
|
* Find identities with pagination and filtering.
|
|
@@ -295,7 +296,7 @@ var IdentityService = class {
|
|
|
295
296
|
provider: identity.provider,
|
|
296
297
|
userId: identity.userId
|
|
297
298
|
});
|
|
298
|
-
const realm = this.
|
|
299
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
299
300
|
await this.auditService.recordUser("update", {
|
|
300
301
|
userRealm: realm.name,
|
|
301
302
|
resourceId: identity.userId,
|
|
@@ -398,9 +399,9 @@ const sessionResourceSchema = t.object({
|
|
|
398
399
|
//#region ../../src/api/users/services/SessionCrudService.ts
|
|
399
400
|
var SessionCrudService = class {
|
|
400
401
|
log = $logger();
|
|
401
|
-
|
|
402
|
+
realmProvider = $inject(RealmProvider);
|
|
402
403
|
sessions(userRealmName) {
|
|
403
|
-
return this.
|
|
404
|
+
return this.realmProvider.sessionRepository(userRealmName);
|
|
404
405
|
}
|
|
405
406
|
/**
|
|
406
407
|
* Find sessions with pagination and filtering.
|
|
@@ -672,10 +673,10 @@ var UserService = class {
|
|
|
672
673
|
log = $logger();
|
|
673
674
|
verificationController = $client();
|
|
674
675
|
userNotifications = $inject(UserNotifications);
|
|
675
|
-
|
|
676
|
+
realmProvider = $inject(RealmProvider);
|
|
676
677
|
auditService = $inject(AuditService);
|
|
677
678
|
users(userRealmName) {
|
|
678
|
-
return this.
|
|
679
|
+
return this.realmProvider.userRepository(userRealmName);
|
|
679
680
|
}
|
|
680
681
|
/**
|
|
681
682
|
* Request email verification for a user.
|
|
@@ -779,7 +780,7 @@ var UserService = class {
|
|
|
779
780
|
userId: user.id,
|
|
780
781
|
type
|
|
781
782
|
});
|
|
782
|
-
const realm = this.
|
|
783
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
783
784
|
await this.auditService.recordUser("update", {
|
|
784
785
|
userId: user.id,
|
|
785
786
|
userEmail: email,
|
|
@@ -843,7 +844,7 @@ var UserService = class {
|
|
|
843
844
|
email: data.email,
|
|
844
845
|
userRealmName
|
|
845
846
|
});
|
|
846
|
-
const realm = this.
|
|
847
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
847
848
|
if (data.username) {
|
|
848
849
|
if (await this.users(userRealmName).findOne({ where: { username: { eq: data.username } } }).catch(() => void 0)) {
|
|
849
850
|
this.log.debug("Username already taken", { username: data.username });
|
|
@@ -895,7 +896,7 @@ var UserService = class {
|
|
|
895
896
|
const before = await this.getUserById(id, userRealmName);
|
|
896
897
|
const user = await this.users(userRealmName).updateById(id, data);
|
|
897
898
|
this.log.debug("User updated", { userId: id });
|
|
898
|
-
const realm = this.
|
|
899
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
899
900
|
const changes = {};
|
|
900
901
|
for (const key of Object.keys(data)) if (data[key] !== void 0 && before[key] !== data[key]) changes[key] = {
|
|
901
902
|
from: before[key],
|
|
@@ -921,7 +922,7 @@ var UserService = class {
|
|
|
921
922
|
const user = await this.getUserById(id, userRealmName);
|
|
922
923
|
await this.users(userRealmName).deleteById(id);
|
|
923
924
|
this.log.info("User deleted", { userId: id });
|
|
924
|
-
const realm = this.
|
|
925
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
925
926
|
await this.auditService.recordUser("delete", {
|
|
926
927
|
userRealm: realm.name,
|
|
927
928
|
resourceId: id,
|
|
@@ -1025,6 +1026,67 @@ var AdminUserController = class {
|
|
|
1025
1026
|
});
|
|
1026
1027
|
};
|
|
1027
1028
|
|
|
1029
|
+
//#endregion
|
|
1030
|
+
//#region ../../src/api/users/schemas/realmConfigSchema.ts
|
|
1031
|
+
const realmConfigSchema = t.object({
|
|
1032
|
+
settings: realmAuthSettingsAtom.schema,
|
|
1033
|
+
realmName: t.string(),
|
|
1034
|
+
authenticationMethods: t.array(authenticationProviderSchema)
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
//#endregion
|
|
1038
|
+
//#region ../../src/api/users/controllers/RealmController.ts
|
|
1039
|
+
/**
|
|
1040
|
+
* Controller for exposing realm configuration.
|
|
1041
|
+
* Uses $route instead of $action to keep endpoints hidden from API documentation.
|
|
1042
|
+
*/
|
|
1043
|
+
var RealmController = class {
|
|
1044
|
+
url = "/realms";
|
|
1045
|
+
group = "realms";
|
|
1046
|
+
realmProvider = $inject(RealmProvider);
|
|
1047
|
+
serverAuthProvider = $inject(ServerAuthProvider);
|
|
1048
|
+
/**
|
|
1049
|
+
* Get realm configuration settings.
|
|
1050
|
+
* This endpoint is not exposed in the API documentation.
|
|
1051
|
+
*/
|
|
1052
|
+
getRealmConfig = $action({
|
|
1053
|
+
group: this.group,
|
|
1054
|
+
method: "GET",
|
|
1055
|
+
path: `${this.url}/config`,
|
|
1056
|
+
secure: false,
|
|
1057
|
+
cache: {
|
|
1058
|
+
etag: true,
|
|
1059
|
+
control: { maxAge: [24, "hours"] }
|
|
1060
|
+
},
|
|
1061
|
+
schema: {
|
|
1062
|
+
query: t.object({ realmName: t.optional(t.string()) }),
|
|
1063
|
+
response: realmConfigSchema
|
|
1064
|
+
},
|
|
1065
|
+
handler: ({ query }) => {
|
|
1066
|
+
const { name: realmName, settings } = this.realmProvider.getRealm(query.realmName);
|
|
1067
|
+
return {
|
|
1068
|
+
settings,
|
|
1069
|
+
realmName,
|
|
1070
|
+
authenticationMethods: this.serverAuthProvider.getAuthenticationProviders({ realmName })
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
checkUsernameAvailability = $action({
|
|
1075
|
+
group: this.group,
|
|
1076
|
+
path: `${this.url}/check-username`,
|
|
1077
|
+
secure: false,
|
|
1078
|
+
schema: {
|
|
1079
|
+
query: t.object({ realmName: t.optional(t.text()) }),
|
|
1080
|
+
body: t.object({ username: t.text() }),
|
|
1081
|
+
response: t.object({ available: t.boolean() })
|
|
1082
|
+
},
|
|
1083
|
+
handler: async ({ query, body }) => {
|
|
1084
|
+
const realmName = query.realmName;
|
|
1085
|
+
return { available: !await this.realmProvider.userRepository(realmName).findOne({ where: { username: { eq: body.username } } }).catch(() => void 0) };
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1028
1090
|
//#endregion
|
|
1029
1091
|
//#region ../../src/api/users/schemas/completePasswordResetRequestSchema.ts
|
|
1030
1092
|
/**
|
|
@@ -1116,20 +1178,20 @@ var CredentialService = class {
|
|
|
1116
1178
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1117
1179
|
verificationController = $client();
|
|
1118
1180
|
userNotifications = $inject(UserNotifications);
|
|
1119
|
-
|
|
1181
|
+
realmProvider = $inject(RealmProvider);
|
|
1120
1182
|
auditService = $inject(AuditService);
|
|
1121
1183
|
intentCache = $cache({
|
|
1122
1184
|
name: "password-reset-intents",
|
|
1123
1185
|
ttl: [INTENT_TTL_MINUTES$1, "minutes"]
|
|
1124
1186
|
});
|
|
1125
1187
|
users(userRealmName) {
|
|
1126
|
-
return this.
|
|
1188
|
+
return this.realmProvider.userRepository(userRealmName);
|
|
1127
1189
|
}
|
|
1128
1190
|
sessions(userRealmName) {
|
|
1129
|
-
return this.
|
|
1191
|
+
return this.realmProvider.sessionRepository(userRealmName);
|
|
1130
1192
|
}
|
|
1131
1193
|
identities(userRealmName) {
|
|
1132
|
-
return this.
|
|
1194
|
+
return this.realmProvider.identityRepository(userRealmName);
|
|
1133
1195
|
}
|
|
1134
1196
|
/**
|
|
1135
1197
|
* Phase 1: Create a password reset intent.
|
|
@@ -1246,7 +1308,7 @@ var CredentialService = class {
|
|
|
1246
1308
|
userId: intent.userId,
|
|
1247
1309
|
email: intent.email
|
|
1248
1310
|
});
|
|
1249
|
-
const realm = this.
|
|
1311
|
+
const realm = this.realmProvider.getRealm(intent.realmName);
|
|
1250
1312
|
await this.auditService.recordUser("update", {
|
|
1251
1313
|
userId: intent.userId,
|
|
1252
1314
|
userEmail: intent.email,
|
|
@@ -1305,7 +1367,7 @@ var CredentialService = class {
|
|
|
1305
1367
|
const hashedPassword = await this.cryptoProvider.hashPassword(newPassword);
|
|
1306
1368
|
await this.identities(userRealmName).updateById(identity.id, { password: hashedPassword });
|
|
1307
1369
|
await this.sessions(userRealmName).deleteMany({ userId: { eq: user.id } });
|
|
1308
|
-
const realm = this.
|
|
1370
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
1309
1371
|
await this.auditService.recordUser("update", {
|
|
1310
1372
|
userId: user.id,
|
|
1311
1373
|
userEmail: email,
|
|
@@ -1334,7 +1396,7 @@ var RegistrationService = class {
|
|
|
1334
1396
|
cryptoProvider = $inject(CryptoProvider);
|
|
1335
1397
|
verificationController = $client();
|
|
1336
1398
|
userNotifications = $inject(UserNotifications);
|
|
1337
|
-
|
|
1399
|
+
realmProvider = $inject(RealmProvider);
|
|
1338
1400
|
auditService = $inject(AuditService);
|
|
1339
1401
|
intentCache = $cache({
|
|
1340
1402
|
name: "registration-intents",
|
|
@@ -1352,8 +1414,7 @@ var RegistrationService = class {
|
|
|
1352
1414
|
username: body.username,
|
|
1353
1415
|
userRealmName
|
|
1354
1416
|
});
|
|
1355
|
-
const realmSettings = this.
|
|
1356
|
-
this.userRealmProvider.userRepository(userRealmName);
|
|
1417
|
+
const realmSettings = this.realmProvider.getRealm(userRealmName).settings;
|
|
1357
1418
|
if (realmSettings?.registrationAllowed === false) {
|
|
1358
1419
|
this.log.warn("Registration not allowed for realm", { userRealmName });
|
|
1359
1420
|
throw new BadRequestError("Registration is not allowed");
|
|
@@ -1362,6 +1423,18 @@ var RegistrationService = class {
|
|
|
1362
1423
|
this.log.debug("Registration rejected: username required", { userRealmName });
|
|
1363
1424
|
throw new BadRequestError("Username is required");
|
|
1364
1425
|
}
|
|
1426
|
+
if (body.username) {
|
|
1427
|
+
const usernameRegExp = realmSettings?.usernameRegExp;
|
|
1428
|
+
if (usernameRegExp) {
|
|
1429
|
+
if (!new RegExp(usernameRegExp).test(body.username)) {
|
|
1430
|
+
this.log.debug("Registration rejected: username regex mismatch", {
|
|
1431
|
+
userRealmName,
|
|
1432
|
+
username: body.username
|
|
1433
|
+
});
|
|
1434
|
+
throw new BadRequestError("Username does not meet the required format");
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1365
1438
|
if (realmSettings?.emailRequired !== false && !body.email) {
|
|
1366
1439
|
this.log.debug("Registration rejected: email required", { userRealmName });
|
|
1367
1440
|
throw new BadRequestError("Email is required");
|
|
@@ -1428,8 +1501,8 @@ var RegistrationService = class {
|
|
|
1428
1501
|
});
|
|
1429
1502
|
}
|
|
1430
1503
|
const userRealmName = intent.realmName;
|
|
1431
|
-
const userRepository = this.
|
|
1432
|
-
const identityRepository = this.
|
|
1504
|
+
const userRepository = this.realmProvider.userRepository(userRealmName);
|
|
1505
|
+
const identityRepository = this.realmProvider.identityRepository(userRealmName);
|
|
1433
1506
|
if (intent.requirements.email) {
|
|
1434
1507
|
if (!body.emailCode) {
|
|
1435
1508
|
this.log.debug("Registration completion missing email code", { intentId: body.intentId });
|
|
@@ -1477,7 +1550,7 @@ var RegistrationService = class {
|
|
|
1477
1550
|
email: user.email,
|
|
1478
1551
|
username: user.username
|
|
1479
1552
|
});
|
|
1480
|
-
const realm = this.
|
|
1553
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
1481
1554
|
await this.auditService.recordUser("create", {
|
|
1482
1555
|
userId: user.id,
|
|
1483
1556
|
userEmail: user.email ?? void 0,
|
|
@@ -1497,7 +1570,7 @@ var RegistrationService = class {
|
|
|
1497
1570
|
* Check if username, email, and phone are available.
|
|
1498
1571
|
*/
|
|
1499
1572
|
async checkUserAvailability(body, userRealmName) {
|
|
1500
|
-
const userRepository = this.
|
|
1573
|
+
const userRepository = this.realmProvider.userRepository(userRealmName);
|
|
1501
1574
|
if (body.username) {
|
|
1502
1575
|
if (await userRepository.findOne({ where: { username: { eq: body.username } } }).catch(() => void 0)) {
|
|
1503
1576
|
this.log.debug("Username already taken", { username: body.username });
|
|
@@ -1522,23 +1595,19 @@ var RegistrationService = class {
|
|
|
1522
1595
|
*/
|
|
1523
1596
|
async sendEmailVerification(email) {
|
|
1524
1597
|
this.log.debug("Sending email verification code", { email });
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
this.log.debug("Email verification code sent", { email });
|
|
1539
|
-
} catch (error) {
|
|
1540
|
-
this.log.warn("Failed to send email verification code", error);
|
|
1541
|
-
}
|
|
1598
|
+
const verification = await this.verificationController.requestVerificationCode({
|
|
1599
|
+
params: { type: "code" },
|
|
1600
|
+
body: { target: email }
|
|
1601
|
+
});
|
|
1602
|
+
await this.userNotifications.emailVerification.push({
|
|
1603
|
+
contact: email,
|
|
1604
|
+
variables: {
|
|
1605
|
+
email,
|
|
1606
|
+
code: verification.token,
|
|
1607
|
+
expiresInMinutes: Math.floor(verification.codeExpiration / 60)
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
this.log.debug("Email verification code sent", { email });
|
|
1542
1611
|
}
|
|
1543
1612
|
/**
|
|
1544
1613
|
* Send phone verification code.
|
|
@@ -1831,67 +1900,6 @@ var UserController = class {
|
|
|
1831
1900
|
});
|
|
1832
1901
|
};
|
|
1833
1902
|
|
|
1834
|
-
//#endregion
|
|
1835
|
-
//#region ../../src/api/users/schemas/userRealmConfigSchema.ts
|
|
1836
|
-
const userRealmConfigSchema = t.object({
|
|
1837
|
-
settings: realmAuthSettingsAtom.schema,
|
|
1838
|
-
realmName: t.string(),
|
|
1839
|
-
authenticationMethods: t.array(authenticationProviderSchema)
|
|
1840
|
-
});
|
|
1841
|
-
|
|
1842
|
-
//#endregion
|
|
1843
|
-
//#region ../../src/api/users/controllers/UserRealmController.ts
|
|
1844
|
-
/**
|
|
1845
|
-
* Controller for exposing realm configuration.
|
|
1846
|
-
* Uses $route instead of $action to keep endpoints hidden from API documentation.
|
|
1847
|
-
*/
|
|
1848
|
-
var UserRealmController = class {
|
|
1849
|
-
url = "/realms";
|
|
1850
|
-
group = "realms";
|
|
1851
|
-
userRealmProvider = $inject(UserRealmProvider);
|
|
1852
|
-
serverAuthProvider = $inject(ServerAuthProvider);
|
|
1853
|
-
/**
|
|
1854
|
-
* Get realm configuration settings.
|
|
1855
|
-
* This endpoint is not exposed in the API documentation.
|
|
1856
|
-
*/
|
|
1857
|
-
getRealmConfig = $action({
|
|
1858
|
-
group: this.group,
|
|
1859
|
-
method: "GET",
|
|
1860
|
-
path: `${this.url}/config`,
|
|
1861
|
-
secure: false,
|
|
1862
|
-
cache: {
|
|
1863
|
-
etag: true,
|
|
1864
|
-
control: { maxAge: [24, "hours"] }
|
|
1865
|
-
},
|
|
1866
|
-
schema: {
|
|
1867
|
-
query: t.object({ userRealmName: t.optional(t.string()) }),
|
|
1868
|
-
response: userRealmConfigSchema
|
|
1869
|
-
},
|
|
1870
|
-
handler: ({ query }) => {
|
|
1871
|
-
const { name: realmName, settings } = this.userRealmProvider.getRealm(query.userRealmName);
|
|
1872
|
-
return {
|
|
1873
|
-
settings,
|
|
1874
|
-
realmName,
|
|
1875
|
-
authenticationMethods: this.serverAuthProvider.getAuthenticationProviders({ realmName })
|
|
1876
|
-
};
|
|
1877
|
-
}
|
|
1878
|
-
});
|
|
1879
|
-
checkUsernameAvailability = $action({
|
|
1880
|
-
group: this.group,
|
|
1881
|
-
path: `${this.url}/check-username`,
|
|
1882
|
-
secure: false,
|
|
1883
|
-
schema: {
|
|
1884
|
-
query: t.object({ userRealmName: t.optional(t.text()) }),
|
|
1885
|
-
body: t.object({ username: t.text() }),
|
|
1886
|
-
response: t.object({ available: t.boolean() })
|
|
1887
|
-
},
|
|
1888
|
-
handler: async ({ query, body }) => {
|
|
1889
|
-
const realmName = query.userRealmName;
|
|
1890
|
-
return { available: !await this.userRealmProvider.userRepository(realmName).findOne({ where: { username: { eq: body.username } } }).catch(() => void 0) };
|
|
1891
|
-
}
|
|
1892
|
-
});
|
|
1893
|
-
};
|
|
1894
|
-
|
|
1895
1903
|
//#endregion
|
|
1896
1904
|
//#region ../../src/api/users/services/SessionService.ts
|
|
1897
1905
|
var SessionService = class {
|
|
@@ -1900,17 +1908,17 @@ var SessionService = class {
|
|
|
1900
1908
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1901
1909
|
cryptoProvider = $inject(CryptoProvider);
|
|
1902
1910
|
log = $logger();
|
|
1903
|
-
|
|
1911
|
+
realmProvider = $inject(RealmProvider);
|
|
1904
1912
|
fileController = $client();
|
|
1905
1913
|
auditService = $inject(AuditService);
|
|
1906
1914
|
users(userRealmName) {
|
|
1907
|
-
return this.
|
|
1915
|
+
return this.realmProvider.userRepository(userRealmName);
|
|
1908
1916
|
}
|
|
1909
1917
|
sessions(userRealmName) {
|
|
1910
|
-
return this.
|
|
1918
|
+
return this.realmProvider.sessionRepository(userRealmName);
|
|
1911
1919
|
}
|
|
1912
1920
|
identities(userRealmName) {
|
|
1913
|
-
return this.
|
|
1921
|
+
return this.realmProvider.identityRepository(userRealmName);
|
|
1914
1922
|
}
|
|
1915
1923
|
/**
|
|
1916
1924
|
* Random delay to prevent timing attacks (50-200ms)
|
|
@@ -1923,18 +1931,37 @@ var SessionService = class {
|
|
|
1923
1931
|
* Validate user credentials and return the user if valid.
|
|
1924
1932
|
*/
|
|
1925
1933
|
async login(provider, username, password, userRealmName) {
|
|
1926
|
-
const { settings, name } = this.
|
|
1934
|
+
const { settings, name } = this.realmProvider.getRealm(userRealmName);
|
|
1927
1935
|
const isEmail = username.includes("@");
|
|
1928
1936
|
const isPhone = /^[+\d][\d\s()-]+$/.test(username);
|
|
1929
1937
|
const isUsername = !isEmail && !isPhone;
|
|
1930
|
-
const identities
|
|
1931
|
-
const users
|
|
1938
|
+
const identities = this.identities(userRealmName);
|
|
1939
|
+
const users = this.users(userRealmName);
|
|
1932
1940
|
await this.randomDelay();
|
|
1933
1941
|
try {
|
|
1934
|
-
const where = users
|
|
1942
|
+
const where = users.createQueryWhere();
|
|
1935
1943
|
where.realm = name;
|
|
1936
|
-
if (settings.usernameEnabled !== false && isUsername)
|
|
1937
|
-
|
|
1944
|
+
if (settings.usernameEnabled !== false && isUsername) {
|
|
1945
|
+
if (settings.usernameRegExp) {
|
|
1946
|
+
if (!new RegExp(settings.usernameRegExp).test(username)) {
|
|
1947
|
+
this.log.warn("Username does not match required format", {
|
|
1948
|
+
provider,
|
|
1949
|
+
username,
|
|
1950
|
+
realm: name
|
|
1951
|
+
});
|
|
1952
|
+
await this.auditService.recordAuth("login_failed", {
|
|
1953
|
+
userRealm: name,
|
|
1954
|
+
description: "Username does not match required format",
|
|
1955
|
+
metadata: {
|
|
1956
|
+
provider,
|
|
1957
|
+
username
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
throw new InvalidCredentialsError();
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
where.username = username;
|
|
1964
|
+
} else if (settings.emailEnabled !== false && isEmail) where.email = username;
|
|
1938
1965
|
else if (settings.phoneEnabled === true && isPhone) where.phoneNumber = username;
|
|
1939
1966
|
else {
|
|
1940
1967
|
this.log.warn("Invalid login identifier format", {
|
|
@@ -1952,7 +1979,7 @@ var SessionService = class {
|
|
|
1952
1979
|
});
|
|
1953
1980
|
throw new InvalidCredentialsError();
|
|
1954
1981
|
}
|
|
1955
|
-
const user = await users
|
|
1982
|
+
const user = await users.findOne({ where }).catch(() => void 0);
|
|
1956
1983
|
if (!user) {
|
|
1957
1984
|
this.log.warn("User not found during login attempt", {
|
|
1958
1985
|
provider,
|
|
@@ -1969,7 +1996,7 @@ var SessionService = class {
|
|
|
1969
1996
|
});
|
|
1970
1997
|
throw new InvalidCredentialsError();
|
|
1971
1998
|
}
|
|
1972
|
-
const identity = await identities
|
|
1999
|
+
const identity = await identities.findOne({ where: {
|
|
1973
2000
|
provider: { eq: provider },
|
|
1974
2001
|
userId: { eq: user.id }
|
|
1975
2002
|
} });
|
|
@@ -2061,14 +2088,6 @@ var SessionService = class {
|
|
|
2061
2088
|
sessionId: session.id,
|
|
2062
2089
|
userId: session.userId
|
|
2063
2090
|
});
|
|
2064
|
-
const { name } = this.userRealmProvider.getRealm(userRealmName);
|
|
2065
|
-
await this.auditService.recordAuth("token_refresh", {
|
|
2066
|
-
userId: user.id,
|
|
2067
|
-
userEmail: user.email ?? void 0,
|
|
2068
|
-
userRealm: name,
|
|
2069
|
-
sessionId: session.id,
|
|
2070
|
-
description: "Session token refreshed"
|
|
2071
|
-
});
|
|
2072
2091
|
return {
|
|
2073
2092
|
user,
|
|
2074
2093
|
expiresIn: expiresAt.unix() - now.unix(),
|
|
@@ -2081,7 +2100,7 @@ var SessionService = class {
|
|
|
2081
2100
|
await this.sessions(userRealmName).deleteOne({ refreshToken });
|
|
2082
2101
|
this.log.debug("Session deleted");
|
|
2083
2102
|
if (session) {
|
|
2084
|
-
const { name } = this.
|
|
2103
|
+
const { name } = this.realmProvider.getRealm(userRealmName);
|
|
2085
2104
|
await this.auditService.recordAuth("logout", {
|
|
2086
2105
|
userId: session.userId,
|
|
2087
2106
|
userRealm: name,
|
|
@@ -2096,10 +2115,10 @@ var SessionService = class {
|
|
|
2096
2115
|
profileSub: profile.sub,
|
|
2097
2116
|
email: profile.email
|
|
2098
2117
|
});
|
|
2099
|
-
const realm = this.
|
|
2100
|
-
const identities
|
|
2101
|
-
const users
|
|
2102
|
-
const identity = await identities
|
|
2118
|
+
const realm = this.realmProvider.getRealm(userRealmName);
|
|
2119
|
+
const identities = this.identities(userRealmName);
|
|
2120
|
+
const users = this.users(userRealmName);
|
|
2121
|
+
const identity = await identities.findOne({ where: {
|
|
2103
2122
|
provider,
|
|
2104
2123
|
providerUserId: profile.sub
|
|
2105
2124
|
} }).catch(() => void 0);
|
|
@@ -2109,19 +2128,19 @@ var SessionService = class {
|
|
|
2109
2128
|
identityId: identity.id,
|
|
2110
2129
|
userId: identity.userId
|
|
2111
2130
|
});
|
|
2112
|
-
const user
|
|
2131
|
+
const user = await users.findById(identity.userId);
|
|
2113
2132
|
await this.auditService.recordAuth("login", {
|
|
2114
|
-
userId: user
|
|
2115
|
-
userEmail: user
|
|
2133
|
+
userId: user.id,
|
|
2134
|
+
userEmail: user.email ?? void 0,
|
|
2116
2135
|
userRealm: realm.name,
|
|
2117
|
-
resourceId: user
|
|
2136
|
+
resourceId: user.id,
|
|
2118
2137
|
description: `User logged in via OAuth2 (${provider})`,
|
|
2119
2138
|
metadata: {
|
|
2120
2139
|
provider,
|
|
2121
2140
|
providerUserId: profile.sub
|
|
2122
2141
|
}
|
|
2123
2142
|
});
|
|
2124
|
-
return user
|
|
2143
|
+
return user;
|
|
2125
2144
|
}
|
|
2126
2145
|
if (!profile.email) {
|
|
2127
2146
|
this.log.debug("OAuth2 profile has no email, returning profile as-is", {
|
|
@@ -2133,7 +2152,7 @@ var SessionService = class {
|
|
|
2133
2152
|
...profile
|
|
2134
2153
|
};
|
|
2135
2154
|
}
|
|
2136
|
-
const existing = await users
|
|
2155
|
+
const existing = await users.findOne({ where: { email: profile.email } }).catch(() => void 0);
|
|
2137
2156
|
if (existing) {
|
|
2138
2157
|
this.log.debug("Linking OAuth2 profile to existing user by email", {
|
|
2139
2158
|
provider,
|
|
@@ -2141,7 +2160,7 @@ var SessionService = class {
|
|
|
2141
2160
|
userId: existing.id,
|
|
2142
2161
|
email: profile.email
|
|
2143
2162
|
});
|
|
2144
|
-
await identities
|
|
2163
|
+
await identities.create({
|
|
2145
2164
|
provider,
|
|
2146
2165
|
providerUserId: profile.sub,
|
|
2147
2166
|
userId: existing.id
|
|
@@ -2160,7 +2179,7 @@ var SessionService = class {
|
|
|
2160
2179
|
});
|
|
2161
2180
|
return existing;
|
|
2162
2181
|
}
|
|
2163
|
-
const user = await users
|
|
2182
|
+
const user = await users.create({
|
|
2164
2183
|
realm: realm.name,
|
|
2165
2184
|
username: profile.email.split("@")[0],
|
|
2166
2185
|
email: profile.email,
|
|
@@ -2177,7 +2196,7 @@ var SessionService = class {
|
|
|
2177
2196
|
const file = this.fsp.createFile({ response });
|
|
2178
2197
|
if (response.ok && response.body) {
|
|
2179
2198
|
const fileEntity = await this.fileController.uploadFile({ body: { file } }, { user });
|
|
2180
|
-
await users
|
|
2199
|
+
await users.updateById(user.id, { picture: fileEntity.id });
|
|
2181
2200
|
}
|
|
2182
2201
|
} catch (error) {
|
|
2183
2202
|
this.log.warn("Failed to fetch user profile picture", error);
|
|
@@ -2224,7 +2243,7 @@ var SessionService = class {
|
|
|
2224
2243
|
};
|
|
2225
2244
|
|
|
2226
2245
|
//#endregion
|
|
2227
|
-
//#region ../../src/api/users/primitives/$
|
|
2246
|
+
//#region ../../src/api/users/primitives/$realm.ts
|
|
2228
2247
|
/**
|
|
2229
2248
|
* Already configured realm for user management.
|
|
2230
2249
|
*
|
|
@@ -2238,24 +2257,24 @@ var SessionService = class {
|
|
|
2238
2257
|
* Environment Variables:
|
|
2239
2258
|
* - `APP_SECRET`: Secret key for signing tokens (if not provided in options).
|
|
2240
2259
|
*/
|
|
2241
|
-
const $
|
|
2260
|
+
const $realm = (options = {}) => {
|
|
2242
2261
|
const { alepha } = $context();
|
|
2243
2262
|
const sessionService = alepha.inject(SessionService);
|
|
2244
2263
|
const securityProvider = alepha.inject(SecurityProvider);
|
|
2245
|
-
const
|
|
2246
|
-
const name = options.
|
|
2264
|
+
const realmProvider = alepha.inject(RealmProvider);
|
|
2265
|
+
const name = options.issuer?.name ?? DEFAULT_USER_REALM_NAME;
|
|
2247
2266
|
options.settings ??= {};
|
|
2248
2267
|
if (options.settings.emailRequired) options.settings.emailEnabled = true;
|
|
2249
2268
|
if (options.settings.usernameRequired) options.settings.usernameEnabled = true;
|
|
2250
2269
|
if (options.settings.phoneRequired) options.settings.phoneEnabled = true;
|
|
2251
|
-
const
|
|
2270
|
+
const realmRegistration = realmProvider.register(name, options);
|
|
2252
2271
|
alepha.with(AlephaApiFiles);
|
|
2253
2272
|
alepha.with(AlephaApiAudits);
|
|
2254
|
-
const realm = $
|
|
2255
|
-
...options.
|
|
2273
|
+
const realm = $issuer({
|
|
2274
|
+
...options.issuer,
|
|
2256
2275
|
name,
|
|
2257
2276
|
secret: options.secret ?? securityProvider.secretKey,
|
|
2258
|
-
roles: options.
|
|
2277
|
+
roles: options.issuer?.roles ?? [{
|
|
2259
2278
|
name: "admin",
|
|
2260
2279
|
permissions: [{ name: "*" }]
|
|
2261
2280
|
}, {
|
|
@@ -2278,24 +2297,24 @@ const $userRealm = (options = {}) => {
|
|
|
2278
2297
|
onDeleteSession: async (refreshToken) => {
|
|
2279
2298
|
await sessionService.deleteSession(refreshToken);
|
|
2280
2299
|
},
|
|
2281
|
-
...options.
|
|
2300
|
+
...options.issuer?.settings
|
|
2282
2301
|
}
|
|
2283
2302
|
});
|
|
2284
|
-
realm.link = (name
|
|
2285
|
-
return (ctx) => sessionService.link(name
|
|
2303
|
+
realm.link = (name) => {
|
|
2304
|
+
return (ctx) => sessionService.link(name, ctx.user, realm.name);
|
|
2286
2305
|
};
|
|
2287
|
-
realm.login = (name
|
|
2306
|
+
realm.login = (name) => {
|
|
2288
2307
|
return (credentials) => {
|
|
2289
|
-
return sessionService.login(name
|
|
2308
|
+
return sessionService.login(name, credentials.username, credentials.password, realm.name);
|
|
2290
2309
|
};
|
|
2291
2310
|
};
|
|
2292
|
-
const identities
|
|
2293
|
-
if (identities
|
|
2311
|
+
const identities = options.identities ?? { credentials: true };
|
|
2312
|
+
if (identities) {
|
|
2294
2313
|
const auth = {};
|
|
2295
|
-
if (identities
|
|
2296
|
-
else
|
|
2297
|
-
if (identities
|
|
2298
|
-
if (identities
|
|
2314
|
+
if (identities.credentials) auth.credentials = $authCredentials(realm);
|
|
2315
|
+
else realmRegistration.settings.registrationAllowed = false;
|
|
2316
|
+
if (identities.google) auth.google = $authGoogle(realm);
|
|
2317
|
+
if (identities.github) auth.github = $authGithub(realm);
|
|
2299
2318
|
alepha.with(() => auth);
|
|
2300
2319
|
}
|
|
2301
2320
|
return realm;
|
|
@@ -2376,7 +2395,7 @@ const AlephaApiUsers = $module({
|
|
|
2376
2395
|
AlephaServerHelmet,
|
|
2377
2396
|
AlephaServerCompress,
|
|
2378
2397
|
AlephaEmail,
|
|
2379
|
-
|
|
2398
|
+
RealmProvider,
|
|
2380
2399
|
SessionService,
|
|
2381
2400
|
SessionCrudService,
|
|
2382
2401
|
CredentialService,
|
|
@@ -2387,11 +2406,11 @@ const AlephaApiUsers = $module({
|
|
|
2387
2406
|
AdminUserController,
|
|
2388
2407
|
AdminSessionController,
|
|
2389
2408
|
AdminIdentityController,
|
|
2390
|
-
|
|
2409
|
+
RealmController,
|
|
2391
2410
|
UserNotifications
|
|
2392
2411
|
]
|
|
2393
2412
|
});
|
|
2394
2413
|
|
|
2395
2414
|
//#endregion
|
|
2396
|
-
export { $
|
|
2415
|
+
export { $realm, AdminIdentityController, AdminSessionController, AdminUserController, AlephaApiUsers, CredentialService, DEFAULT_USER_REALM_NAME, IdentityService, RealmController, RealmProvider, RegistrationService, SessionCrudService, SessionService, UserController, UserService, completePasswordResetRequestSchema, completeRegistrationRequestSchema, createUserSchema, identities, identityQuerySchema, identityResourceSchema, loginSchema, passwordResetIntentResponseSchema, realmAuthSettingsAtom, realmConfigSchema, registerSchema, registrationIntentResponseSchema, resetPasswordRequestSchema, resetPasswordSchema, sessionQuerySchema, sessionResourceSchema, sessions, updateUserSchema, userQuerySchema, userResourceSchema, users };
|
|
2397
2416
|
//# sourceMappingURL=index.js.map
|