alepha 0.15.3 → 0.15.5
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 +26 -11
- package/dist/api/audits/index.d.ts +335 -335
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +11 -3
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +3 -3
- package/dist/api/files/index.js +4 -3
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +198 -155
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +103 -5
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +198 -198
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/keys/index.js +3 -3
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +1 -0
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +3 -3
- package/dist/api/notifications/index.js +4 -3
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +263 -263
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +41 -30
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +383 -77
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +284 -72
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +131 -131
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +3 -3
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +3 -3
- package/dist/batch/index.js +3 -3
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +3 -3
- package/dist/bucket/index.js +6 -6
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/core/index.d.ts +3 -3
- package/dist/cache/core/index.js +3 -3
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cli/index.d.ts +5612 -20
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +122 -91
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +11 -4
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +8 -6
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +4 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +3 -3
- package/dist/datetime/index.js +3 -3
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +16 -16
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +10562 -10
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +3 -3
- package/dist/fake/index.js +3 -3
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +9 -4
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +12 -4
- package/dist/lock/core/index.js.map +1 -1
- package/dist/logger/index.d.ts +3 -3
- package/dist/logger/index.js +6 -3
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +3 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.d.ts +12 -12
- package/dist/orm/index.js +4 -4
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +3 -3
- package/dist/queue/core/index.js +3 -3
- package/dist/queue/core/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +2 -1
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.d.ts +3 -3
- package/dist/react/auth/index.js +5 -4
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +6 -6
- package/dist/react/core/index.js +3 -3
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +3 -3
- package/dist/react/form/index.js +3 -3
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.d.ts +3 -3
- package/dist/react/head/index.js +3 -3
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +3 -3
- package/dist/react/i18n/index.js +3 -3
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.css +337 -0
- package/dist/react/intro/index.css.map +1 -0
- package/dist/react/intro/index.d.ts +10 -0
- package/dist/react/intro/index.d.ts.map +1 -0
- package/dist/react/intro/index.js +222 -0
- package/dist/react/intro/index.js.map +1 -0
- package/dist/react/router/index.browser.js +2 -2
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +11 -1
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +21 -11
- package/dist/react/router/index.js.map +1 -1
- package/dist/redis/index.d.ts +22 -22
- package/dist/redis/index.js +3 -3
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +3 -3
- package/dist/retry/index.js +3 -3
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +16 -4
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +45 -7
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +3 -3
- package/dist/security/index.js +5 -5
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +3 -3
- package/dist/server/auth/index.js +3 -3
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +3 -3
- package/dist/server/cache/index.js +3 -3
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +3 -3
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +4 -3
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +3 -3
- package/dist/server/cookies/index.js +3 -3
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +14 -25
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +13 -29
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +3 -3
- package/dist/server/cors/index.js +3 -3
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/health/index.d.ts +20 -20
- package/dist/server/health/index.js +3 -3
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/helmet/index.d.ts +3 -3
- package/dist/server/helmet/index.js +3 -3
- package/dist/server/helmet/index.js.map +1 -1
- package/dist/server/links/index.d.ts +42 -42
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +4 -4
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +3 -3
- package/dist/server/metrics/index.js +3 -3
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts +3 -3
- package/dist/server/multipart/index.js +3 -3
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +3 -3
- package/dist/server/proxy/index.js +3 -3
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts +3 -3
- package/dist/server/rate-limit/index.js +3 -3
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +3 -3
- package/dist/server/static/index.js +6 -6
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +3 -3
- package/dist/server/swagger/index.js +6 -6
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +3 -3
- package/dist/sms/index.js +6 -6
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.d.ts +3 -3
- package/dist/system/index.js +3 -3
- package/dist/system/index.js.map +1 -1
- package/dist/thread/index.d.ts +3 -3
- package/dist/thread/index.js +3 -3
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts +3 -3
- package/dist/topic/core/index.js +3 -3
- package/dist/topic/core/index.js.map +1 -1
- package/dist/vite/index.d.ts +6286 -4
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +28 -2
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +37 -37
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +3 -3
- package/dist/websocket/index.js.map +1 -1
- package/package.json +12 -4
- package/src/api/audits/controllers/AdminAuditController.ts +8 -0
- package/src/api/audits/index.ts +3 -3
- package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
- package/src/api/files/index.ts +3 -3
- package/src/api/jobs/controllers/AdminJobController.ts +18 -2
- package/src/api/jobs/index.ts +4 -3
- package/src/api/jobs/services/JobAudits.spec.ts +89 -0
- package/src/api/jobs/services/JobAudits.ts +101 -0
- package/src/api/keys/index.ts +3 -3
- package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
- package/src/api/notifications/index.ts +3 -3
- package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
- package/src/api/parameters/index.ts +5 -3
- package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1 -1
- package/src/api/users/__tests__/ApiKeys.spec.ts +1 -1
- package/src/api/users/__tests__/EmailVerification.spec.ts +16 -1
- package/src/api/users/__tests__/PasswordReset.spec.ts +11 -0
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -0
- package/src/api/users/controllers/AdminIdentityController.ts +3 -0
- package/src/api/users/controllers/AdminSessionController.ts +3 -0
- package/src/api/users/controllers/AdminUserController.ts +5 -0
- package/src/api/users/index.ts +8 -9
- package/src/api/users/primitives/$realm.ts +117 -19
- package/src/api/users/providers/RealmProvider.ts +15 -7
- package/src/api/users/services/CredentialService.spec.ts +11 -0
- package/src/api/users/services/CredentialService.ts +47 -24
- package/src/api/users/services/IdentityService.ts +12 -4
- package/src/api/users/services/RegistrationService.spec.ts +11 -0
- package/src/api/users/services/RegistrationService.ts +33 -12
- package/src/api/users/services/SessionService.ts +83 -12
- package/src/api/users/services/UserAudits.ts +47 -0
- package/src/api/users/services/UserFiles.ts +19 -0
- package/src/api/users/services/UserJobs.spec.ts +107 -0
- package/src/api/users/services/UserJobs.ts +62 -0
- package/src/api/users/services/UserParameters.ts +23 -0
- package/src/api/users/services/UserService.ts +34 -17
- package/src/api/verifications/index.ts +3 -3
- package/src/batch/index.ts +3 -3
- package/src/bucket/index.ts +3 -3
- package/src/cache/core/index.ts +3 -3
- package/src/cli/commands/build.ts +1 -0
- package/src/cli/commands/db.ts +9 -0
- package/src/cli/commands/init.spec.ts +2 -17
- package/src/cli/commands/init.ts +37 -1
- package/src/cli/providers/ViteDevServerProvider.ts +36 -2
- package/src/cli/services/AlephaCliUtils.ts +17 -0
- package/src/cli/services/PackageManagerUtils.ts +15 -1
- package/src/cli/services/ProjectScaffolder.ts +8 -13
- package/src/cli/templates/agentMd.ts +2 -25
- package/src/cli/templates/apiAppSecurityTs.ts +37 -2
- package/src/cli/templates/mainCss.ts +2 -32
- package/src/cli/templates/webAppRouterTs.ts +5 -5
- package/src/cli/templates/webHomeComponentTsx.ts +10 -0
- package/src/command/helpers/Runner.ts +14 -1
- package/src/command/index.ts +3 -3
- package/src/core/helpers/primitive.ts +0 -5
- package/src/core/index.ts +3 -3
- package/src/datetime/index.ts +3 -3
- package/src/email/index.ts +3 -3
- package/src/email/index.workerd.ts +36 -0
- package/src/email/providers/LocalEmailProvider.ts +2 -2
- package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
- package/src/fake/index.ts +3 -3
- package/src/lock/core/index.ts +3 -3
- package/src/lock/core/primitives/$lock.ts +13 -1
- package/src/logger/index.ts +3 -3
- package/src/logger/providers/PrettyFormatterProvider.ts +7 -0
- package/src/mcp/index.ts +3 -3
- package/src/orm/index.ts +3 -3
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
- package/src/queue/core/index.ts +3 -3
- package/src/react/auth/index.ts +3 -3
- package/src/react/auth/services/ReactAuth.ts +3 -1
- package/src/react/core/index.ts +3 -3
- package/src/react/form/index.ts +3 -3
- package/src/react/head/index.ts +3 -3
- package/src/react/i18n/index.ts +3 -3
- package/src/react/intro/components/GettingStarted.css +334 -0
- package/src/react/intro/components/GettingStarted.tsx +276 -0
- package/src/react/intro/index.ts +1 -0
- package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
- package/src/react/router/index.browser.ts +2 -0
- package/src/react/router/index.ts +2 -0
- package/src/react/router/providers/ReactServerProvider.ts +14 -4
- package/src/react/router/providers/SSRManifestProvider.ts +7 -0
- package/src/redis/index.ts +3 -3
- package/src/retry/index.ts +3 -3
- package/src/router/index.ts +3 -3
- package/src/scheduler/index.ts +3 -3
- package/src/scheduler/index.workerd.ts +43 -0
- package/src/scheduler/providers/CronProvider.ts +53 -6
- package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
- package/src/security/index.ts +3 -3
- package/src/security/providers/JwtProvider.ts +2 -2
- package/src/server/auth/index.ts +3 -3
- package/src/server/cache/index.ts +3 -3
- package/src/server/compress/index.ts +3 -3
- package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
- package/src/server/cookies/index.ts +3 -3
- package/src/server/core/index.ts +3 -3
- package/src/server/core/primitives/$action.spec.ts +3 -2
- package/src/server/core/primitives/$action.ts +6 -2
- package/src/server/core/providers/NodeHttpServerProvider.ts +2 -15
- package/src/server/core/providers/ServerProvider.ts +4 -2
- package/src/server/core/providers/ServerRouterProvider.ts +5 -27
- package/src/server/cors/index.ts +3 -3
- package/src/server/health/index.ts +3 -3
- package/src/server/helmet/index.ts +3 -3
- package/src/server/links/index.ts +3 -3
- package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
- package/src/server/links/providers/ServerLinksProvider.ts +1 -1
- package/src/server/metrics/index.ts +3 -3
- package/src/server/multipart/index.ts +3 -3
- package/src/server/proxy/index.ts +3 -3
- package/src/server/rate-limit/index.ts +3 -3
- package/src/server/static/index.ts +3 -3
- package/src/server/swagger/index.ts +3 -3
- package/src/sms/index.ts +3 -3
- package/src/system/index.ts +3 -3
- package/src/thread/index.ts +3 -3
- package/src/topic/core/index.ts +3 -3
- package/src/vite/tasks/generateCloudflare.ts +38 -2
- package/src/websocket/index.ts +3 -3
- package/src/cli/templates/webHelloComponentTsx.ts +0 -30
- /package/src/api/users/{notifications → services}/UserNotifications.ts +0 -0
package/dist/api/users/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { $atom, $context, $inject, $module, Alepha, AlephaError, Json, isFileLike, t } from "alepha";
|
|
2
|
-
import { $notification, AlephaApiNotifications } from "alepha/api/notifications";
|
|
3
|
-
import { AlephaApiVerification } from "alepha/api/verifications";
|
|
4
2
|
import { AlephaEmail } from "alepha/email";
|
|
5
3
|
import { AlephaServerCompress } from "alepha/server/compress";
|
|
6
4
|
import { AlephaServerHelmet } from "alepha/server/helmet";
|
|
7
5
|
import { $action, BadRequestError, ConflictError, ForbiddenError, HttpError, NotFoundError, UnauthorizedError, okSchema } from "alepha/server";
|
|
8
6
|
import { $entity, $repository, db, pageQuerySchema, parseQueryString, sql } from "alepha/orm";
|
|
9
|
-
import { AlephaApiAudits, AuditService } from "alepha/api/audits";
|
|
10
7
|
import { $logger } from "alepha/logger";
|
|
11
|
-
import {
|
|
8
|
+
import { AuditService } from "alepha/api/audits";
|
|
12
9
|
import { $client } from "alepha/server/links";
|
|
10
|
+
import { $notification } from "alepha/api/notifications";
|
|
13
11
|
import { $authCredentials, $authGithub, $authGoogle, ServerAuthProvider, authenticationProviderSchema } from "alepha/server/auth";
|
|
14
12
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
15
13
|
import { $cache } from "alepha/cache";
|
|
@@ -21,8 +19,10 @@ import { access, copyFile, cp, mkdir, readFile, readdir, rename, rm, stat, write
|
|
|
21
19
|
import { PassThrough, Readable } from "node:stream";
|
|
22
20
|
import { fileURLToPath } from "node:url";
|
|
23
21
|
import { exec, spawn } from "node:child_process";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
22
|
+
import { AlephaApiVerification } from "alepha/api/verifications";
|
|
23
|
+
import { $bucket } from "alepha/bucket";
|
|
24
|
+
import { $job } from "alepha/api/jobs";
|
|
25
|
+
import { $config } from "alepha/api/parameters";
|
|
26
26
|
|
|
27
27
|
//#region ../../src/api/users/schemas/identityQuerySchema.ts
|
|
28
28
|
const identityQuerySchema = t.extend(pageQuerySchema, {
|
|
@@ -112,6 +112,8 @@ const realmAuthSettingsAtom = $atom({
|
|
|
112
112
|
firstNameLastNameEnabled: t.boolean({ description: "Enable first and last name for user accounts" }),
|
|
113
113
|
firstNameLastNameRequired: t.boolean({ description: "Require first and last name for user accounts" }),
|
|
114
114
|
resetPasswordAllowed: t.boolean({ description: "Enable forgot password functionality" }),
|
|
115
|
+
adminEmails: t.array(t.email(), { description: "List of email addresses that are automatically promoted to admin role on login" }),
|
|
116
|
+
adminUsernames: t.array(t.text(), { description: "List of usernames that are automatically promoted to admin role on login" }),
|
|
115
117
|
passwordPolicy: t.object({
|
|
116
118
|
minLength: t.integer({
|
|
117
119
|
description: "Minimum password length",
|
|
@@ -138,6 +140,8 @@ const realmAuthSettingsAtom = $atom({
|
|
|
138
140
|
resetPasswordAllowed: false,
|
|
139
141
|
firstNameLastNameEnabled: false,
|
|
140
142
|
firstNameLastNameRequired: false,
|
|
143
|
+
adminEmails: [],
|
|
144
|
+
adminUsernames: [],
|
|
141
145
|
passwordPolicy: {
|
|
142
146
|
minLength: 8,
|
|
143
147
|
requireUppercase: true,
|
|
@@ -181,16 +185,17 @@ var RealmProvider = class {
|
|
|
181
185
|
defaultSessions = $repository(sessions);
|
|
182
186
|
defaultUsers = $repository(users);
|
|
183
187
|
realms = /* @__PURE__ */ new Map();
|
|
184
|
-
avatars = $bucket({
|
|
185
|
-
maxSize: 5 * 1024 * 1024,
|
|
186
|
-
mimeTypes: [
|
|
187
|
-
"image/jpeg",
|
|
188
|
-
"image/png",
|
|
189
|
-
"image/gif",
|
|
190
|
-
"image/webp"
|
|
191
|
-
]
|
|
192
|
-
});
|
|
193
188
|
register(realmName, realmOptions = {}) {
|
|
189
|
+
const features = {
|
|
190
|
+
jobs: false,
|
|
191
|
+
notifications: false,
|
|
192
|
+
apiKeys: false,
|
|
193
|
+
parameters: false,
|
|
194
|
+
files: false,
|
|
195
|
+
audits: false,
|
|
196
|
+
organizations: false,
|
|
197
|
+
...realmOptions.features
|
|
198
|
+
};
|
|
194
199
|
this.realms.set(realmName, {
|
|
195
200
|
name: realmName,
|
|
196
201
|
repositories: {
|
|
@@ -205,7 +210,8 @@ var RealmProvider = class {
|
|
|
205
210
|
...realmAuthSettingsAtom.options.default.passwordPolicy,
|
|
206
211
|
...realmOptions.settings?.passwordPolicy
|
|
207
212
|
}
|
|
208
|
-
}
|
|
213
|
+
},
|
|
214
|
+
features
|
|
209
215
|
});
|
|
210
216
|
return this.getRealm(realmName);
|
|
211
217
|
}
|
|
@@ -233,12 +239,45 @@ var RealmProvider = class {
|
|
|
233
239
|
}
|
|
234
240
|
};
|
|
235
241
|
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region ../../src/api/users/services/UserAudits.ts
|
|
244
|
+
/**
|
|
245
|
+
* User-specific audit wrapper service.
|
|
246
|
+
*
|
|
247
|
+
* This service wraps the core AuditService to provide user-related audit logging.
|
|
248
|
+
* It is lazy-loaded when the `audits` feature is enabled in the realm.
|
|
249
|
+
*/
|
|
250
|
+
var UserAudits = class {
|
|
251
|
+
auditService = $inject(AuditService);
|
|
252
|
+
/**
|
|
253
|
+
* Record a user-related audit event.
|
|
254
|
+
*/
|
|
255
|
+
recordUser(action, context) {
|
|
256
|
+
return this.auditService.recordUser(action, context);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Record an authentication-related audit event.
|
|
260
|
+
*/
|
|
261
|
+
recordAuth(action, context) {
|
|
262
|
+
return this.auditService.recordAuth(action, context);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Record a generic audit event.
|
|
266
|
+
*/
|
|
267
|
+
record(category, action, context) {
|
|
268
|
+
return this.auditService.record(category, action, context);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
236
272
|
//#endregion
|
|
237
273
|
//#region ../../src/api/users/services/IdentityService.ts
|
|
238
274
|
var IdentityService = class {
|
|
275
|
+
alepha = $inject(Alepha);
|
|
239
276
|
log = $logger();
|
|
240
277
|
realmProvider = $inject(RealmProvider);
|
|
241
|
-
|
|
278
|
+
userAudits(realmName) {
|
|
279
|
+
if (this.realmProvider.getRealm(realmName).features.audits) return this.alepha.inject(UserAudits);
|
|
280
|
+
}
|
|
242
281
|
identities(userRealmName) {
|
|
243
282
|
return this.realmProvider.identityRepository(userRealmName);
|
|
244
283
|
}
|
|
@@ -293,7 +332,7 @@ var IdentityService = class {
|
|
|
293
332
|
userId: identity.userId
|
|
294
333
|
});
|
|
295
334
|
const realm = this.realmProvider.getRealm(userRealmName);
|
|
296
|
-
await this.
|
|
335
|
+
await this.userAudits(userRealmName)?.recordUser("update", {
|
|
297
336
|
userRealm: realm.name,
|
|
298
337
|
resourceId: identity.userId,
|
|
299
338
|
description: `Identity provider disconnected: ${identity.provider}`,
|
|
@@ -318,6 +357,7 @@ var AdminIdentityController = class {
|
|
|
318
357
|
findIdentities = $action({
|
|
319
358
|
path: this.url,
|
|
320
359
|
group: this.group,
|
|
360
|
+
secure: true,
|
|
321
361
|
description: "Find identities with pagination and filtering",
|
|
322
362
|
schema: {
|
|
323
363
|
query: t.extend(identityQuerySchema, { userRealmName: t.optional(t.string()) }),
|
|
@@ -334,6 +374,7 @@ var AdminIdentityController = class {
|
|
|
334
374
|
getIdentity = $action({
|
|
335
375
|
path: `${this.url}/:id`,
|
|
336
376
|
group: this.group,
|
|
377
|
+
secure: true,
|
|
337
378
|
description: "Get an identity by ID",
|
|
338
379
|
schema: {
|
|
339
380
|
params: t.object({ id: t.uuid() }),
|
|
@@ -349,6 +390,7 @@ var AdminIdentityController = class {
|
|
|
349
390
|
method: "DELETE",
|
|
350
391
|
path: `${this.url}/:id`,
|
|
351
392
|
group: this.group,
|
|
393
|
+
secure: true,
|
|
352
394
|
description: "Delete an identity",
|
|
353
395
|
schema: {
|
|
354
396
|
params: t.object({ id: t.uuid() }),
|
|
@@ -458,6 +500,7 @@ var AdminSessionController = class {
|
|
|
458
500
|
findSessions = $action({
|
|
459
501
|
path: this.url,
|
|
460
502
|
group: this.group,
|
|
503
|
+
secure: true,
|
|
461
504
|
description: "Find sessions with pagination and filtering",
|
|
462
505
|
schema: {
|
|
463
506
|
query: t.extend(sessionQuerySchema, { userRealmName: t.optional(t.string()) }),
|
|
@@ -474,6 +517,7 @@ var AdminSessionController = class {
|
|
|
474
517
|
getSession = $action({
|
|
475
518
|
path: `${this.url}/:id`,
|
|
476
519
|
group: this.group,
|
|
520
|
+
secure: true,
|
|
477
521
|
description: "Get a session by ID",
|
|
478
522
|
schema: {
|
|
479
523
|
params: t.object({ id: t.uuid() }),
|
|
@@ -489,6 +533,7 @@ var AdminSessionController = class {
|
|
|
489
533
|
method: "DELETE",
|
|
490
534
|
path: `${this.url}/:id`,
|
|
491
535
|
group: this.group,
|
|
536
|
+
secure: true,
|
|
492
537
|
description: "Delete a session",
|
|
493
538
|
schema: {
|
|
494
539
|
params: t.object({ id: t.uuid() }),
|
|
@@ -535,7 +580,7 @@ const userQuerySchema = t.extend(pageQuerySchema, {
|
|
|
535
580
|
const userResourceSchema = users.schema;
|
|
536
581
|
|
|
537
582
|
//#endregion
|
|
538
|
-
//#region ../../src/api/users/
|
|
583
|
+
//#region ../../src/api/users/services/UserNotifications.ts
|
|
539
584
|
var UserNotifications = class {
|
|
540
585
|
passwordReset = $notification({
|
|
541
586
|
category: "security",
|
|
@@ -666,11 +711,16 @@ var UserNotifications = class {
|
|
|
666
711
|
//#endregion
|
|
667
712
|
//#region ../../src/api/users/services/UserService.ts
|
|
668
713
|
var UserService = class {
|
|
714
|
+
alepha = $inject(Alepha);
|
|
669
715
|
log = $logger();
|
|
670
716
|
verificationController = $client();
|
|
671
|
-
userNotifications = $inject(UserNotifications);
|
|
672
717
|
realmProvider = $inject(RealmProvider);
|
|
673
|
-
|
|
718
|
+
userAudits(realmName) {
|
|
719
|
+
if (this.realmProvider.getRealm(realmName).features.audits) return this.alepha.inject(UserAudits);
|
|
720
|
+
}
|
|
721
|
+
userNotifications(realmName) {
|
|
722
|
+
if (this.realmProvider.getRealm(realmName).features.notifications) return this.alepha.inject(UserNotifications);
|
|
723
|
+
}
|
|
674
724
|
users(userRealmName) {
|
|
675
725
|
return this.realmProvider.userRepository(userRealmName);
|
|
676
726
|
}
|
|
@@ -709,7 +759,7 @@ var UserService = class {
|
|
|
709
759
|
url.searchParams.set("email", email);
|
|
710
760
|
url.searchParams.set("token", verification.token);
|
|
711
761
|
const fullVerifyUrl = verifyUrl ? `${verifyUrl}${url.search}` : url.pathname + url.search;
|
|
712
|
-
await this.userNotifications
|
|
762
|
+
await this.userNotifications(userRealmName)?.emailVerificationLink.push({
|
|
713
763
|
contact: email,
|
|
714
764
|
variables: {
|
|
715
765
|
email,
|
|
@@ -722,7 +772,7 @@ var UserService = class {
|
|
|
722
772
|
userId: user.id
|
|
723
773
|
});
|
|
724
774
|
} else {
|
|
725
|
-
await this.userNotifications
|
|
775
|
+
await this.userNotifications(userRealmName)?.emailVerification.push({
|
|
726
776
|
contact: email,
|
|
727
777
|
variables: {
|
|
728
778
|
email,
|
|
@@ -777,7 +827,7 @@ var UserService = class {
|
|
|
777
827
|
type
|
|
778
828
|
});
|
|
779
829
|
const realm = this.realmProvider.getRealm(userRealmName);
|
|
780
|
-
await this.
|
|
830
|
+
await this.userAudits(userRealmName)?.recordUser("update", {
|
|
781
831
|
userId: user.id,
|
|
782
832
|
userEmail: email,
|
|
783
833
|
userRealm: realm.name,
|
|
@@ -869,7 +919,7 @@ var UserService = class {
|
|
|
869
919
|
username: user.username,
|
|
870
920
|
email: user.email
|
|
871
921
|
});
|
|
872
|
-
await this.
|
|
922
|
+
await this.userAudits(userRealmName)?.recordUser("create", {
|
|
873
923
|
userRealm: realm.name,
|
|
874
924
|
resourceId: user.id,
|
|
875
925
|
description: "User created",
|
|
@@ -899,7 +949,7 @@ var UserService = class {
|
|
|
899
949
|
to: data[key]
|
|
900
950
|
};
|
|
901
951
|
const isRoleChange = data.roles !== void 0 && JSON.stringify(before.roles) !== JSON.stringify(data.roles);
|
|
902
|
-
await this.
|
|
952
|
+
await this.userAudits(userRealmName)?.recordUser(isRoleChange ? "role_change" : "update", {
|
|
903
953
|
userRealm: realm.name,
|
|
904
954
|
resourceId: user.id,
|
|
905
955
|
description: isRoleChange ? "User roles changed" : `User updated: ${Object.keys(changes).join(", ")}`,
|
|
@@ -919,7 +969,7 @@ var UserService = class {
|
|
|
919
969
|
await this.users(userRealmName).deleteById(id);
|
|
920
970
|
this.log.info("User deleted", { userId: id });
|
|
921
971
|
const realm = this.realmProvider.getRealm(userRealmName);
|
|
922
|
-
await this.
|
|
972
|
+
await this.userAudits(userRealmName)?.recordUser("delete", {
|
|
923
973
|
userRealm: realm.name,
|
|
924
974
|
resourceId: id,
|
|
925
975
|
severity: "warning",
|
|
@@ -944,6 +994,7 @@ var AdminUserController = class {
|
|
|
944
994
|
findUsers = $action({
|
|
945
995
|
path: this.url,
|
|
946
996
|
group: this.group,
|
|
997
|
+
secure: true,
|
|
947
998
|
description: "Find users with pagination and filtering",
|
|
948
999
|
schema: {
|
|
949
1000
|
query: t.extend(userQuerySchema, { userRealmName: t.optional(t.string()) }),
|
|
@@ -960,6 +1011,7 @@ var AdminUserController = class {
|
|
|
960
1011
|
getUser = $action({
|
|
961
1012
|
path: `${this.url}/:id`,
|
|
962
1013
|
group: this.group,
|
|
1014
|
+
secure: true,
|
|
963
1015
|
description: "Get a user by ID",
|
|
964
1016
|
schema: {
|
|
965
1017
|
params: t.object({ id: t.uuid() }),
|
|
@@ -975,6 +1027,7 @@ var AdminUserController = class {
|
|
|
975
1027
|
method: "POST",
|
|
976
1028
|
path: this.url,
|
|
977
1029
|
group: this.group,
|
|
1030
|
+
secure: true,
|
|
978
1031
|
description: "Create a new user",
|
|
979
1032
|
schema: {
|
|
980
1033
|
query: t.object({ userRealmName: t.optional(t.string()) }),
|
|
@@ -990,6 +1043,7 @@ var AdminUserController = class {
|
|
|
990
1043
|
method: "PATCH",
|
|
991
1044
|
path: `${this.url}/:id`,
|
|
992
1045
|
group: this.group,
|
|
1046
|
+
secure: true,
|
|
993
1047
|
description: "Update a user",
|
|
994
1048
|
schema: {
|
|
995
1049
|
params: t.object({ id: t.uuid() }),
|
|
@@ -1006,6 +1060,7 @@ var AdminUserController = class {
|
|
|
1006
1060
|
method: "DELETE",
|
|
1007
1061
|
path: `${this.url}/:id`,
|
|
1008
1062
|
group: this.group,
|
|
1063
|
+
secure: true,
|
|
1009
1064
|
description: "Delete a user",
|
|
1010
1065
|
schema: {
|
|
1011
1066
|
params: t.object({ id: t.uuid() }),
|
|
@@ -1169,13 +1224,18 @@ const registrationIntentResponseSchema = t.object({
|
|
|
1169
1224
|
//#region ../../src/api/users/services/CredentialService.ts
|
|
1170
1225
|
const INTENT_TTL_MINUTES$1 = 10;
|
|
1171
1226
|
var CredentialService = class {
|
|
1227
|
+
alepha = $inject(Alepha);
|
|
1172
1228
|
log = $logger();
|
|
1173
1229
|
cryptoProvider = $inject(CryptoProvider);
|
|
1174
1230
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1175
1231
|
verificationController = $client();
|
|
1176
|
-
userNotifications = $inject(UserNotifications);
|
|
1177
1232
|
realmProvider = $inject(RealmProvider);
|
|
1178
|
-
|
|
1233
|
+
userAudits(realmName) {
|
|
1234
|
+
if (this.realmProvider.getRealm(realmName).features.audits) return this.alepha.inject(UserAudits);
|
|
1235
|
+
}
|
|
1236
|
+
userNotifications(realmName) {
|
|
1237
|
+
if (this.realmProvider.getRealm(realmName).features.notifications) return this.alepha.inject(UserNotifications);
|
|
1238
|
+
}
|
|
1179
1239
|
intentCache = $cache({
|
|
1180
1240
|
name: "password-reset-intents",
|
|
1181
1241
|
ttl: [INTENT_TTL_MINUTES$1, "minutes"]
|
|
@@ -1230,7 +1290,7 @@ var CredentialService = class {
|
|
|
1230
1290
|
params: { type: "code" },
|
|
1231
1291
|
body: { target: email }
|
|
1232
1292
|
});
|
|
1233
|
-
await this.userNotifications
|
|
1293
|
+
await this.userNotifications(userRealmName)?.passwordReset.push({
|
|
1234
1294
|
contact: email,
|
|
1235
1295
|
variables: {
|
|
1236
1296
|
email,
|
|
@@ -1305,7 +1365,7 @@ var CredentialService = class {
|
|
|
1305
1365
|
email: intent.email
|
|
1306
1366
|
});
|
|
1307
1367
|
const realm = this.realmProvider.getRealm(intent.realmName);
|
|
1308
|
-
await this.
|
|
1368
|
+
await this.userAudits(intent.realmName)?.recordUser("update", {
|
|
1309
1369
|
userId: intent.userId,
|
|
1310
1370
|
userEmail: intent.email,
|
|
1311
1371
|
userRealm: realm.name,
|
|
@@ -1313,7 +1373,7 @@ var CredentialService = class {
|
|
|
1313
1373
|
description: "Password reset completed",
|
|
1314
1374
|
metadata: { email: intent.email }
|
|
1315
1375
|
});
|
|
1316
|
-
await this.
|
|
1376
|
+
await this.userAudits(intent.realmName)?.record("security", "sessions_invalidated", {
|
|
1317
1377
|
userId: intent.userId,
|
|
1318
1378
|
userEmail: intent.email,
|
|
1319
1379
|
userRealm: realm.name,
|
|
@@ -1364,7 +1424,7 @@ var CredentialService = class {
|
|
|
1364
1424
|
await this.identities(userRealmName).updateById(identity.id, { password: hashedPassword });
|
|
1365
1425
|
await this.sessions(userRealmName).deleteMany({ userId: { eq: user.id } });
|
|
1366
1426
|
const realm = this.realmProvider.getRealm(userRealmName);
|
|
1367
|
-
await this.
|
|
1427
|
+
await this.userAudits(userRealmName)?.recordUser("update", {
|
|
1368
1428
|
userId: user.id,
|
|
1369
1429
|
userEmail: email,
|
|
1370
1430
|
userRealm: realm.name,
|
|
@@ -1372,7 +1432,7 @@ var CredentialService = class {
|
|
|
1372
1432
|
description: "Password reset completed (legacy)",
|
|
1373
1433
|
metadata: { email }
|
|
1374
1434
|
});
|
|
1375
|
-
await this.
|
|
1435
|
+
await this.userAudits(userRealmName)?.record("security", "sessions_invalidated", {
|
|
1376
1436
|
userId: user.id,
|
|
1377
1437
|
userEmail: email,
|
|
1378
1438
|
userRealm: realm.name,
|
|
@@ -1387,17 +1447,22 @@ var CredentialService = class {
|
|
|
1387
1447
|
//#region ../../src/api/users/services/RegistrationService.ts
|
|
1388
1448
|
const INTENT_TTL_MINUTES = 10;
|
|
1389
1449
|
var RegistrationService = class {
|
|
1450
|
+
alepha = $inject(Alepha);
|
|
1390
1451
|
log = $logger();
|
|
1391
1452
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1392
1453
|
cryptoProvider = $inject(CryptoProvider);
|
|
1393
1454
|
verificationController = $client();
|
|
1394
|
-
userNotifications = $inject(UserNotifications);
|
|
1395
1455
|
realmProvider = $inject(RealmProvider);
|
|
1396
|
-
auditService = $inject(AuditService);
|
|
1397
1456
|
intentCache = $cache({
|
|
1398
1457
|
name: "registration-intents",
|
|
1399
1458
|
ttl: [INTENT_TTL_MINUTES, "minutes"]
|
|
1400
1459
|
});
|
|
1460
|
+
userAudits(realmName) {
|
|
1461
|
+
if (this.realmProvider.getRealm(realmName).features.audits) return this.alepha.inject(UserAudits);
|
|
1462
|
+
}
|
|
1463
|
+
userNotifications(realmName) {
|
|
1464
|
+
if (this.realmProvider.getRealm(realmName).features.notifications) return this.alepha.inject(UserNotifications);
|
|
1465
|
+
}
|
|
1401
1466
|
/**
|
|
1402
1467
|
* Phase 1: Create a registration intent.
|
|
1403
1468
|
*
|
|
@@ -1446,8 +1511,8 @@ var RegistrationService = class {
|
|
|
1446
1511
|
phone: realmSettings?.verifyPhoneRequired === true && !!body.phoneNumber,
|
|
1447
1512
|
captcha: false
|
|
1448
1513
|
};
|
|
1449
|
-
if (requirements.email && body.email) await this.sendEmailVerification(body.email);
|
|
1450
|
-
if (requirements.phone && body.phoneNumber) await this.sendPhoneVerification(body.phoneNumber);
|
|
1514
|
+
if (requirements.email && body.email) await this.sendEmailVerification(body.email, userRealmName);
|
|
1515
|
+
if (requirements.phone && body.phoneNumber) await this.sendPhoneVerification(body.phoneNumber, userRealmName);
|
|
1451
1516
|
const intentId = randomUUID();
|
|
1452
1517
|
const expiresAt = this.dateTimeProvider.now().add(INTENT_TTL_MINUTES, "minutes").toISOString();
|
|
1453
1518
|
const intent = {
|
|
@@ -1547,7 +1612,7 @@ var RegistrationService = class {
|
|
|
1547
1612
|
username: user.username
|
|
1548
1613
|
});
|
|
1549
1614
|
const realm = this.realmProvider.getRealm(userRealmName);
|
|
1550
|
-
await this.
|
|
1615
|
+
await this.userAudits(userRealmName)?.recordUser("create", {
|
|
1551
1616
|
userId: user.id,
|
|
1552
1617
|
userEmail: user.email ?? void 0,
|
|
1553
1618
|
userRealm: realm.name,
|
|
@@ -1589,13 +1654,13 @@ var RegistrationService = class {
|
|
|
1589
1654
|
/**
|
|
1590
1655
|
* Send email verification code.
|
|
1591
1656
|
*/
|
|
1592
|
-
async sendEmailVerification(email) {
|
|
1657
|
+
async sendEmailVerification(email, realmName) {
|
|
1593
1658
|
this.log.debug("Sending email verification code", { email });
|
|
1594
1659
|
const verification = await this.verificationController.requestVerificationCode({
|
|
1595
1660
|
params: { type: "code" },
|
|
1596
1661
|
body: { target: email }
|
|
1597
1662
|
});
|
|
1598
|
-
await this.userNotifications
|
|
1663
|
+
await this.userNotifications(realmName)?.emailVerification.push({
|
|
1599
1664
|
contact: email,
|
|
1600
1665
|
variables: {
|
|
1601
1666
|
email,
|
|
@@ -1608,14 +1673,14 @@ var RegistrationService = class {
|
|
|
1608
1673
|
/**
|
|
1609
1674
|
* Send phone verification code.
|
|
1610
1675
|
*/
|
|
1611
|
-
async sendPhoneVerification(phoneNumber) {
|
|
1676
|
+
async sendPhoneVerification(phoneNumber, realmName) {
|
|
1612
1677
|
this.log.debug("Sending phone verification code", { phoneNumber });
|
|
1613
1678
|
try {
|
|
1614
1679
|
const verification = await this.verificationController.requestVerificationCode({
|
|
1615
1680
|
params: { type: "code" },
|
|
1616
1681
|
body: { target: phoneNumber }
|
|
1617
1682
|
});
|
|
1618
|
-
await this.userNotifications
|
|
1683
|
+
await this.userNotifications(realmName)?.phoneVerification.push({
|
|
1619
1684
|
contact: phoneNumber,
|
|
1620
1685
|
variables: {
|
|
1621
1686
|
phoneNumber,
|
|
@@ -3699,9 +3764,9 @@ var ShellProvider = class {};
|
|
|
3699
3764
|
//#endregion
|
|
3700
3765
|
//#region ../../src/system/index.ts
|
|
3701
3766
|
/**
|
|
3702
|
-
* |
|
|
3703
|
-
*
|
|
3704
|
-
* |
|
|
3767
|
+
* | Stability | Since | Runtime |
|
|
3768
|
+
* |-----------|-------|---------|
|
|
3769
|
+
* | 3 - stable | 0.14.0 | node, bun, browser|
|
|
3705
3770
|
*
|
|
3706
3771
|
* System-level abstractions for portable code across runtimes.
|
|
3707
3772
|
*
|
|
@@ -3746,7 +3811,9 @@ var SessionService = class {
|
|
|
3746
3811
|
log = $logger();
|
|
3747
3812
|
realmProvider = $inject(RealmProvider);
|
|
3748
3813
|
fileController = $client();
|
|
3749
|
-
|
|
3814
|
+
userAudits(realmName) {
|
|
3815
|
+
if (this.realmProvider.getRealm(realmName).features.audits) return this.alepha.inject(UserAudits);
|
|
3816
|
+
}
|
|
3750
3817
|
users(userRealmName) {
|
|
3751
3818
|
return this.realmProvider.userRepository(userRealmName);
|
|
3752
3819
|
}
|
|
@@ -3757,6 +3824,40 @@ var SessionService = class {
|
|
|
3757
3824
|
return this.realmProvider.identityRepository(userRealmName);
|
|
3758
3825
|
}
|
|
3759
3826
|
/**
|
|
3827
|
+
* Check if user should be auto-promoted to admin based on adminEmails/adminUsernames settings.
|
|
3828
|
+
* If user matches and doesn't have admin role, promote them.
|
|
3829
|
+
*/
|
|
3830
|
+
async ensureAdminRole(user, userRealmName) {
|
|
3831
|
+
if (user.roles.includes("admin")) return false;
|
|
3832
|
+
const { settings, name } = this.realmProvider.getRealm(userRealmName);
|
|
3833
|
+
const adminEmails = settings.adminEmails ?? [];
|
|
3834
|
+
const adminUsernames = settings.adminUsernames ?? [];
|
|
3835
|
+
const isAdminByEmail = user.email && adminEmails.includes(user.email);
|
|
3836
|
+
const isAdminByUsername = user.username && adminUsernames.includes(user.username);
|
|
3837
|
+
if (!isAdminByEmail && !isAdminByUsername) return false;
|
|
3838
|
+
user.roles = [...user.roles.filter((r) => r !== "admin"), "admin"];
|
|
3839
|
+
await this.users(userRealmName).updateById(user.id, { roles: user.roles });
|
|
3840
|
+
const reason = isAdminByEmail ? "adminEmails" : "adminUsernames";
|
|
3841
|
+
this.log.info(`User auto-promoted to admin via ${reason} setting`, {
|
|
3842
|
+
userId: user.id,
|
|
3843
|
+
email: user.email,
|
|
3844
|
+
username: user.username,
|
|
3845
|
+
realm: name
|
|
3846
|
+
});
|
|
3847
|
+
await this.userAudits(userRealmName)?.recordUser("role_change", {
|
|
3848
|
+
userId: user.id,
|
|
3849
|
+
userEmail: user.email ?? void 0,
|
|
3850
|
+
userRealm: name,
|
|
3851
|
+
resourceId: user.id,
|
|
3852
|
+
description: `User auto-promoted to admin via ${reason} setting`,
|
|
3853
|
+
metadata: {
|
|
3854
|
+
addedRole: "admin",
|
|
3855
|
+
reason
|
|
3856
|
+
}
|
|
3857
|
+
});
|
|
3858
|
+
return true;
|
|
3859
|
+
}
|
|
3860
|
+
/**
|
|
3760
3861
|
* Random delay to prevent timing attacks (50-200ms)
|
|
3761
3862
|
* Uses cryptographically secure random number generation
|
|
3762
3863
|
*/
|
|
@@ -3785,7 +3886,7 @@ var SessionService = class {
|
|
|
3785
3886
|
username,
|
|
3786
3887
|
realm: name
|
|
3787
3888
|
});
|
|
3788
|
-
await this.
|
|
3889
|
+
await this.userAudits(userRealmName)?.recordAuth("login_failed", {
|
|
3789
3890
|
userRealm: name,
|
|
3790
3891
|
description: "Username does not match required format",
|
|
3791
3892
|
metadata: {
|
|
@@ -3805,7 +3906,7 @@ var SessionService = class {
|
|
|
3805
3906
|
username,
|
|
3806
3907
|
realm: name
|
|
3807
3908
|
});
|
|
3808
|
-
await this.
|
|
3909
|
+
await this.userAudits(userRealmName)?.recordAuth("login_failed", {
|
|
3809
3910
|
userRealm: name,
|
|
3810
3911
|
description: "Invalid login identifier format",
|
|
3811
3912
|
metadata: {
|
|
@@ -3822,7 +3923,7 @@ var SessionService = class {
|
|
|
3822
3923
|
username,
|
|
3823
3924
|
realm: name
|
|
3824
3925
|
});
|
|
3825
|
-
await this.
|
|
3926
|
+
await this.userAudits(userRealmName)?.recordAuth("login_failed", {
|
|
3826
3927
|
userRealm: name,
|
|
3827
3928
|
description: "User not found",
|
|
3828
3929
|
metadata: {
|
|
@@ -3852,7 +3953,7 @@ var SessionService = class {
|
|
|
3852
3953
|
username,
|
|
3853
3954
|
realm: name
|
|
3854
3955
|
});
|
|
3855
|
-
await this.
|
|
3956
|
+
await this.userAudits(userRealmName)?.recordAuth("login_failed", {
|
|
3856
3957
|
userRealm: name,
|
|
3857
3958
|
resourceId: user.id,
|
|
3858
3959
|
description: "Invalid password",
|
|
@@ -3863,7 +3964,7 @@ var SessionService = class {
|
|
|
3863
3964
|
});
|
|
3864
3965
|
throw new InvalidCredentialsError();
|
|
3865
3966
|
}
|
|
3866
|
-
await this.
|
|
3967
|
+
await this.userAudits(userRealmName)?.recordAuth("login", {
|
|
3867
3968
|
userId: user.id,
|
|
3868
3969
|
userEmail: user.email ?? void 0,
|
|
3869
3970
|
userRealm: name,
|
|
@@ -3874,6 +3975,7 @@ var SessionService = class {
|
|
|
3874
3975
|
username
|
|
3875
3976
|
}
|
|
3876
3977
|
});
|
|
3978
|
+
await this.ensureAdminRole(user, userRealmName);
|
|
3877
3979
|
return user;
|
|
3878
3980
|
} catch (error) {
|
|
3879
3981
|
if (error instanceof InvalidCredentialsError) throw error;
|
|
@@ -3920,6 +4022,7 @@ var SessionService = class {
|
|
|
3920
4022
|
throw new UnauthorizedError("Session expired");
|
|
3921
4023
|
}
|
|
3922
4024
|
const user = await this.users(userRealmName).findOne({ where: { id: { eq: session.userId } } });
|
|
4025
|
+
await this.ensureAdminRole(user, userRealmName);
|
|
3923
4026
|
this.log.debug("Session refreshed", {
|
|
3924
4027
|
sessionId: session.id,
|
|
3925
4028
|
userId: session.userId
|
|
@@ -3937,7 +4040,7 @@ var SessionService = class {
|
|
|
3937
4040
|
this.log.debug("Session deleted");
|
|
3938
4041
|
if (session) {
|
|
3939
4042
|
const { name } = this.realmProvider.getRealm(userRealmName);
|
|
3940
|
-
await this.
|
|
4043
|
+
await this.userAudits(userRealmName)?.recordAuth("logout", {
|
|
3941
4044
|
userId: session.userId,
|
|
3942
4045
|
userRealm: name,
|
|
3943
4046
|
sessionId: session.id,
|
|
@@ -3965,7 +4068,7 @@ var SessionService = class {
|
|
|
3965
4068
|
userId: identity.userId
|
|
3966
4069
|
});
|
|
3967
4070
|
const user = await users.findById(identity.userId);
|
|
3968
|
-
await this.
|
|
4071
|
+
await this.userAudits(userRealmName)?.recordAuth("login", {
|
|
3969
4072
|
userId: user.id,
|
|
3970
4073
|
userEmail: user.email ?? void 0,
|
|
3971
4074
|
userRealm: realm.name,
|
|
@@ -3976,6 +4079,7 @@ var SessionService = class {
|
|
|
3976
4079
|
providerUserId: profile.sub
|
|
3977
4080
|
}
|
|
3978
4081
|
});
|
|
4082
|
+
await this.ensureAdminRole(user, userRealmName);
|
|
3979
4083
|
return user;
|
|
3980
4084
|
}
|
|
3981
4085
|
if (!profile.email) {
|
|
@@ -4001,7 +4105,7 @@ var SessionService = class {
|
|
|
4001
4105
|
providerUserId: profile.sub,
|
|
4002
4106
|
userId: existing.id
|
|
4003
4107
|
});
|
|
4004
|
-
await this.
|
|
4108
|
+
await this.userAudits(userRealmName)?.recordAuth("login", {
|
|
4005
4109
|
userId: existing.id,
|
|
4006
4110
|
userEmail: existing.email ?? void 0,
|
|
4007
4111
|
userRealm: realm.name,
|
|
@@ -4013,6 +4117,7 @@ var SessionService = class {
|
|
|
4013
4117
|
linked: true
|
|
4014
4118
|
}
|
|
4015
4119
|
});
|
|
4120
|
+
await this.ensureAdminRole(existing, userRealmName);
|
|
4016
4121
|
return existing;
|
|
4017
4122
|
}
|
|
4018
4123
|
const user = await users.create({
|
|
@@ -4049,7 +4154,7 @@ var SessionService = class {
|
|
|
4049
4154
|
email: user.email,
|
|
4050
4155
|
username: user.username
|
|
4051
4156
|
});
|
|
4052
|
-
await this.
|
|
4157
|
+
await this.userAudits(userRealmName)?.recordUser("create", {
|
|
4053
4158
|
userId: user.id,
|
|
4054
4159
|
userEmail: user.email ?? void 0,
|
|
4055
4160
|
userRealm: realm.name,
|
|
@@ -4062,7 +4167,7 @@ var SessionService = class {
|
|
|
4062
4167
|
email: user.email
|
|
4063
4168
|
}
|
|
4064
4169
|
});
|
|
4065
|
-
await this.
|
|
4170
|
+
await this.userAudits(userRealmName)?.recordAuth("login", {
|
|
4066
4171
|
userId: user.id,
|
|
4067
4172
|
userEmail: user.email ?? void 0,
|
|
4068
4173
|
userRealm: realm.name,
|
|
@@ -4074,6 +4179,7 @@ var SessionService = class {
|
|
|
4074
4179
|
firstLogin: true
|
|
4075
4180
|
}
|
|
4076
4181
|
});
|
|
4182
|
+
await this.ensureAdminRole(user, userRealmName);
|
|
4077
4183
|
return user;
|
|
4078
4184
|
}
|
|
4079
4185
|
};
|
|
@@ -4508,9 +4614,9 @@ var ApiKeyController = class {
|
|
|
4508
4614
|
//#endregion
|
|
4509
4615
|
//#region ../../src/api/keys/index.ts
|
|
4510
4616
|
/**
|
|
4511
|
-
* |
|
|
4512
|
-
*
|
|
4513
|
-
* |
|
|
4617
|
+
* | Stability | Since | Runtime |
|
|
4618
|
+
* |-----------|-------|---------|
|
|
4619
|
+
* | 3 - stable | 0.11.0 | node, bun, workerd|
|
|
4514
4620
|
*
|
|
4515
4621
|
* API key management module for programmatic access.
|
|
4516
4622
|
*
|
|
@@ -4544,6 +4650,95 @@ const AlephaApiKeys = $module({
|
|
|
4544
4650
|
]
|
|
4545
4651
|
});
|
|
4546
4652
|
|
|
4653
|
+
//#endregion
|
|
4654
|
+
//#region ../../src/api/users/services/UserFiles.ts
|
|
4655
|
+
/**
|
|
4656
|
+
* User-specific file storage wrapper service.
|
|
4657
|
+
*
|
|
4658
|
+
* This service provides file storage for user-related files such as:
|
|
4659
|
+
* - User avatars/profile pictures
|
|
4660
|
+
*
|
|
4661
|
+
* It is lazy-loaded when the `files` feature is enabled in the realm.
|
|
4662
|
+
*/
|
|
4663
|
+
var UserFiles = class {
|
|
4664
|
+
/**
|
|
4665
|
+
* Bucket for user avatar storage.
|
|
4666
|
+
*/
|
|
4667
|
+
avatars = $bucket({
|
|
4668
|
+
maxSize: 5 * 1024 * 1024,
|
|
4669
|
+
mimeTypes: [
|
|
4670
|
+
"image/jpeg",
|
|
4671
|
+
"image/png",
|
|
4672
|
+
"image/gif",
|
|
4673
|
+
"image/webp"
|
|
4674
|
+
]
|
|
4675
|
+
});
|
|
4676
|
+
};
|
|
4677
|
+
|
|
4678
|
+
//#endregion
|
|
4679
|
+
//#region ../../src/api/users/services/UserJobs.ts
|
|
4680
|
+
/**
|
|
4681
|
+
* User-specific jobs wrapper service.
|
|
4682
|
+
*
|
|
4683
|
+
* This service handles user-related scheduled jobs such as:
|
|
4684
|
+
* - Session purge (cleaning up expired sessions)
|
|
4685
|
+
* - Verification code cleanup
|
|
4686
|
+
* - Inactive user notifications
|
|
4687
|
+
*
|
|
4688
|
+
* It is lazy-loaded when the `jobs` feature is enabled in the realm.
|
|
4689
|
+
*/
|
|
4690
|
+
var UserJobs = class {
|
|
4691
|
+
log = $logger();
|
|
4692
|
+
dateTimeProvider = $inject(DateTimeProvider);
|
|
4693
|
+
sessionRepository = $repository(sessions);
|
|
4694
|
+
/**
|
|
4695
|
+
* Purge expired sessions from the database.
|
|
4696
|
+
*
|
|
4697
|
+
* This job runs daily at 3:00 AM and removes all sessions
|
|
4698
|
+
* where the `expiresAt` timestamp has passed.
|
|
4699
|
+
*/
|
|
4700
|
+
purgeExpiredSessions = $job({
|
|
4701
|
+
name: "users.purgeExpiredSessions",
|
|
4702
|
+
description: "Remove expired user sessions from the database",
|
|
4703
|
+
cron: "0 3 * * *",
|
|
4704
|
+
handler: async () => {
|
|
4705
|
+
const now = this.dateTimeProvider.nowISOString();
|
|
4706
|
+
this.log.info("Starting expired sessions purge", { cutoffTime: now });
|
|
4707
|
+
const expiredSessions = await this.sessionRepository.findMany({ where: { expiresAt: { lt: now } } });
|
|
4708
|
+
if (expiredSessions.length === 0) {
|
|
4709
|
+
this.log.info("No expired sessions found");
|
|
4710
|
+
return;
|
|
4711
|
+
}
|
|
4712
|
+
this.log.info("Found expired sessions", { count: expiredSessions.length });
|
|
4713
|
+
const deletedIds = await this.sessionRepository.deleteMany({ expiresAt: { lt: now } });
|
|
4714
|
+
this.log.info("Expired sessions purged successfully", { deletedCount: deletedIds.length });
|
|
4715
|
+
}
|
|
4716
|
+
});
|
|
4717
|
+
};
|
|
4718
|
+
|
|
4719
|
+
//#endregion
|
|
4720
|
+
//#region ../../src/api/users/services/UserParameters.ts
|
|
4721
|
+
/**
|
|
4722
|
+
* User-specific configuration service.
|
|
4723
|
+
*
|
|
4724
|
+
* This service wraps the core ConfigStore to provide realm settings management.
|
|
4725
|
+
* It is lazy-loaded when the `parameters` feature is enabled in the realm.
|
|
4726
|
+
*/
|
|
4727
|
+
var UserParameters = class {
|
|
4728
|
+
/**
|
|
4729
|
+
* Realm authentication settings configuration.
|
|
4730
|
+
*
|
|
4731
|
+
* Controls user registration, login methods, verification requirements,
|
|
4732
|
+
* and password policies for the realm.
|
|
4733
|
+
*/
|
|
4734
|
+
realmSettings = $config({
|
|
4735
|
+
name: "alepha.api.users.realmSettings",
|
|
4736
|
+
description: "Realm authentication and registration settings",
|
|
4737
|
+
schema: realmAuthSettingsAtom.schema,
|
|
4738
|
+
default: realmAuthSettingsAtom.options.default
|
|
4739
|
+
});
|
|
4740
|
+
};
|
|
4741
|
+
|
|
4547
4742
|
//#endregion
|
|
4548
4743
|
//#region ../../src/api/users/primitives/$realm.ts
|
|
4549
4744
|
/**
|
|
@@ -4569,12 +4764,32 @@ const $realm = (options = {}) => {
|
|
|
4569
4764
|
if (options.settings.emailRequired) options.settings.emailEnabled = true;
|
|
4570
4765
|
if (options.settings.usernameRequired) options.settings.usernameEnabled = true;
|
|
4571
4766
|
if (options.settings.phoneRequired) options.settings.phoneEnabled = true;
|
|
4767
|
+
const features = {
|
|
4768
|
+
jobs: false,
|
|
4769
|
+
notifications: false,
|
|
4770
|
+
apiKeys: false,
|
|
4771
|
+
parameters: false,
|
|
4772
|
+
files: false,
|
|
4773
|
+
audits: false,
|
|
4774
|
+
organizations: false,
|
|
4775
|
+
...options.features
|
|
4776
|
+
};
|
|
4777
|
+
if (!features.notifications) {
|
|
4778
|
+
options.settings.verifyEmailRequired = false;
|
|
4779
|
+
options.settings.verifyPhoneRequired = false;
|
|
4780
|
+
options.settings.resetPasswordAllowed = false;
|
|
4781
|
+
}
|
|
4572
4782
|
const realmRegistration = realmProvider.register(name, options);
|
|
4573
|
-
alepha.with(
|
|
4574
|
-
alepha.with(
|
|
4575
|
-
alepha.with(
|
|
4783
|
+
if (features.files) alepha.with(UserFiles);
|
|
4784
|
+
if (features.audits) alepha.with(UserAudits);
|
|
4785
|
+
if (features.jobs) alepha.with(UserJobs);
|
|
4786
|
+
if (features.notifications) {
|
|
4787
|
+
alepha.with(AlephaApiVerification);
|
|
4788
|
+
alepha.with(UserNotifications);
|
|
4789
|
+
}
|
|
4790
|
+
if (features.parameters) alepha.with(UserParameters);
|
|
4576
4791
|
const customResolvers = [...options.issuer?.resolvers ?? []];
|
|
4577
|
-
if (
|
|
4792
|
+
if (features.apiKeys) {
|
|
4578
4793
|
alepha.with(AlephaApiKeys);
|
|
4579
4794
|
const apiKeyService = alepha.inject(ApiKeyService);
|
|
4580
4795
|
customResolvers.push(apiKeyService.createResolver());
|
|
@@ -4690,9 +4905,9 @@ const resetPasswordSchema = t.object({
|
|
|
4690
4905
|
//#endregion
|
|
4691
4906
|
//#region ../../src/api/users/index.ts
|
|
4692
4907
|
/**
|
|
4693
|
-
* |
|
|
4694
|
-
*
|
|
4695
|
-
* |
|
|
4908
|
+
* | Stability | Since | Runtime |
|
|
4909
|
+
* |-----------|-------|---------|
|
|
4910
|
+
* | 3 - stable | 0.5.0 | node, bun, workerd|
|
|
4696
4911
|
*
|
|
4697
4912
|
* Complete user management with multi-realm support for multi-tenant applications.
|
|
4698
4913
|
*
|
|
@@ -4711,8 +4926,6 @@ const resetPasswordSchema = t.object({
|
|
|
4711
4926
|
const AlephaApiUsers = $module({
|
|
4712
4927
|
name: "alepha.api.users",
|
|
4713
4928
|
services: [
|
|
4714
|
-
AlephaApiVerification,
|
|
4715
|
-
AlephaApiNotifications,
|
|
4716
4929
|
AlephaServerHelmet,
|
|
4717
4930
|
AlephaServerCompress,
|
|
4718
4931
|
AlephaEmail,
|
|
@@ -4727,11 +4940,10 @@ const AlephaApiUsers = $module({
|
|
|
4727
4940
|
AdminUserController,
|
|
4728
4941
|
AdminSessionController,
|
|
4729
4942
|
AdminIdentityController,
|
|
4730
|
-
RealmController
|
|
4731
|
-
UserNotifications
|
|
4943
|
+
RealmController
|
|
4732
4944
|
]
|
|
4733
4945
|
});
|
|
4734
4946
|
|
|
4735
4947
|
//#endregion
|
|
4736
|
-
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 };
|
|
4948
|
+
export { $realm, AdminIdentityController, AdminSessionController, AdminUserController, AlephaApiUsers, CredentialService, DEFAULT_USER_REALM_NAME, IdentityService, RealmController, RealmProvider, RegistrationService, SessionCrudService, SessionService, UserAudits, UserController, UserFiles, UserJobs, UserNotifications, UserParameters, UserService, completePasswordResetRequestSchema, completeRegistrationRequestSchema, createUserSchema, identities, identityQuerySchema, identityResourceSchema, loginSchema, passwordResetIntentResponseSchema, realmAuthSettingsAtom, realmConfigSchema, registerSchema, registrationIntentResponseSchema, resetPasswordRequestSchema, resetPasswordSchema, sessionQuerySchema, sessionResourceSchema, sessions, updateUserSchema, userQuerySchema, userResourceSchema, users };
|
|
4737
4949
|
//# sourceMappingURL=index.js.map
|