alepha 0.13.1 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api-files/index.d.ts +28 -91
- package/dist/api-files/index.js +10 -755
- package/dist/api-files/index.js.map +1 -1
- package/dist/api-jobs/index.d.ts +46 -46
- package/dist/api-jobs/index.js +13 -13
- package/dist/api-jobs/index.js.map +1 -1
- package/dist/api-notifications/index.d.ts +129 -146
- package/dist/api-notifications/index.js +17 -39
- package/dist/api-notifications/index.js.map +1 -1
- package/dist/api-parameters/index.d.ts +21 -22
- package/dist/api-parameters/index.js +22 -22
- package/dist/api-parameters/index.js.map +1 -1
- package/dist/api-users/index.d.ts +223 -2000
- package/dist/api-users/index.js +914 -4787
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.d.ts +96 -96
- package/dist/batch/index.d.ts +13 -13
- package/dist/batch/index.js +8 -8
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +14 -14
- package/dist/bucket/index.js +12 -12
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/index.d.ts +11 -11
- package/dist/cache/index.js +9 -9
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.d.ts +28 -26
- package/dist/cli/index.js +50 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +19 -19
- package/dist/command/index.js +25 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +218 -218
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +232 -232
- package/dist/core/index.js +218 -218
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +2113 -0
- package/dist/core/index.native.js.map +1 -0
- package/dist/datetime/index.d.ts +9 -9
- package/dist/datetime/index.js +7 -7
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +16 -16
- package/dist/email/index.js +9 -9
- package/dist/email/index.js.map +1 -1
- package/dist/file/index.js +1 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/index.d.ts +9 -9
- package/dist/lock/index.js +8 -8
- package/dist/lock/index.js.map +1 -1
- package/dist/lock-redis/index.js +3 -66
- package/dist/lock-redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -5
- package/dist/logger/index.js +8 -8
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.browser.js +114 -114
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +218 -218
- package/dist/orm/index.js +46 -46
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +29 -29
- package/dist/queue/index.js +20 -20
- package/dist/queue/index.js.map +1 -1
- package/dist/queue-redis/index.d.ts +2 -2
- package/dist/redis/index.d.ts +10 -10
- package/dist/retry/index.d.ts +19 -19
- package/dist/retry/index.js +7 -7
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +16 -16
- package/dist/scheduler/index.js +9 -9
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +80 -80
- package/dist/security/index.js +32 -32
- package/dist/security/index.js.map +1 -1
- package/dist/server/index.browser.js +1 -1
- package/dist/server/index.browser.js.map +1 -1
- package/dist/server/index.d.ts +101 -101
- package/dist/server/index.js +16 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.browser.js +4 -982
- package/dist/server-auth/index.browser.js.map +1 -1
- package/dist/server-auth/index.d.ts +204 -785
- package/dist/server-auth/index.js +47 -1239
- package/dist/server-auth/index.js.map +1 -1
- package/dist/server-cache/index.d.ts +10 -10
- package/dist/server-cache/index.js +2 -2
- package/dist/server-cache/index.js.map +1 -1
- package/dist/server-compress/index.d.ts +4 -4
- package/dist/server-compress/index.js +1 -1
- package/dist/server-compress/index.js.map +1 -1
- package/dist/server-cookies/index.browser.js +8 -8
- package/dist/server-cookies/index.browser.js.map +1 -1
- package/dist/server-cookies/index.d.ts +17 -17
- package/dist/server-cookies/index.js +10 -10
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-cors/index.d.ts +17 -17
- package/dist/server-cors/index.js +9 -9
- package/dist/server-cors/index.js.map +1 -1
- package/dist/server-health/index.d.ts +19 -19
- package/dist/server-helmet/index.d.ts +1 -1
- package/dist/server-links/index.browser.js +12 -12
- package/dist/server-links/index.browser.js.map +1 -1
- package/dist/server-links/index.d.ts +59 -251
- package/dist/server-links/index.js +23 -502
- package/dist/server-links/index.js.map +1 -1
- package/dist/server-metrics/index.d.ts +4 -4
- package/dist/server-multipart/index.d.ts +2 -2
- package/dist/server-proxy/index.d.ts +12 -12
- package/dist/server-proxy/index.js +10 -10
- package/dist/server-proxy/index.js.map +1 -1
- package/dist/server-rate-limit/index.d.ts +22 -22
- package/dist/server-rate-limit/index.js +12 -12
- package/dist/server-rate-limit/index.js.map +1 -1
- package/dist/server-security/index.d.ts +22 -22
- package/dist/server-security/index.js +15 -15
- package/dist/server-security/index.js.map +1 -1
- package/dist/server-static/index.d.ts +14 -14
- package/dist/server-static/index.js +8 -8
- package/dist/server-static/index.js.map +1 -1
- package/dist/server-swagger/index.d.ts +25 -184
- package/dist/server-swagger/index.js +21 -724
- package/dist/server-swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +14 -14
- package/dist/sms/index.js +9 -9
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +11 -11
- package/dist/thread/index.js +17 -17
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/index.d.ts +26 -26
- package/dist/topic/index.js +16 -16
- package/dist/topic/index.js.map +1 -1
- package/dist/topic-redis/index.d.ts +1 -1
- package/dist/vite/index.d.ts +3 -3
- package/dist/vite/index.js +8 -8
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +11 -11
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +58 -58
- package/dist/websocket/index.js +13 -13
- package/dist/websocket/index.js.map +1 -1
- package/package.json +113 -52
- package/src/api-files/services/FileService.ts +5 -7
- package/src/api-jobs/index.ts +1 -1
- package/src/api-jobs/{descriptors → primitives}/$job.ts +8 -8
- package/src/api-jobs/providers/JobProvider.ts +9 -9
- package/src/api-jobs/services/JobService.ts +5 -5
- package/src/api-notifications/index.ts +5 -15
- package/src/api-notifications/{descriptors → primitives}/$notification.ts +10 -10
- package/src/api-notifications/services/NotificationSenderService.ts +3 -3
- package/src/api-parameters/index.ts +1 -1
- package/src/api-parameters/{descriptors → primitives}/$config.ts +7 -12
- package/src/api-users/index.ts +1 -1
- package/src/api-users/{descriptors → primitives}/$userRealm.ts +8 -8
- package/src/api-users/providers/UserRealmProvider.ts +1 -1
- package/src/batch/index.ts +3 -3
- package/src/batch/{descriptors → primitives}/$batch.ts +13 -16
- package/src/bucket/index.ts +8 -8
- package/src/bucket/{descriptors → primitives}/$bucket.ts +8 -8
- package/src/bucket/providers/LocalFileStorageProvider.ts +3 -3
- package/src/cache/index.ts +4 -4
- package/src/cache/{descriptors → primitives}/$cache.ts +15 -15
- package/src/cli/apps/AlephaPackageBuilderCli.ts +24 -2
- package/src/cli/commands/DrizzleCommands.ts +6 -6
- package/src/cli/commands/VerifyCommands.ts +1 -1
- package/src/cli/commands/ViteCommands.ts +6 -1
- package/src/cli/services/ProjectUtils.ts +34 -3
- package/src/command/index.ts +5 -5
- package/src/command/{descriptors → primitives}/$command.ts +9 -12
- package/src/command/providers/CliProvider.ts +10 -10
- package/src/core/Alepha.ts +30 -33
- package/src/core/constants/KIND.ts +1 -1
- package/src/core/constants/OPTIONS.ts +1 -1
- package/src/core/helpers/{descriptor.ts → primitive.ts} +18 -18
- package/src/core/helpers/ref.ts +1 -1
- package/src/core/index.shared.ts +8 -8
- package/src/core/{descriptors → primitives}/$context.ts +5 -5
- package/src/core/{descriptors → primitives}/$hook.ts +4 -4
- package/src/core/{descriptors → primitives}/$inject.ts +2 -2
- package/src/core/{descriptors → primitives}/$module.ts +9 -9
- package/src/core/{descriptors → primitives}/$use.ts +2 -2
- package/src/core/providers/CodecManager.ts +1 -1
- package/src/core/providers/JsonSchemaCodec.ts +1 -1
- package/src/core/providers/StateManager.ts +2 -2
- package/src/datetime/index.ts +3 -3
- package/src/datetime/{descriptors → primitives}/$interval.ts +6 -6
- package/src/email/index.ts +4 -4
- package/src/email/{descriptors → primitives}/$email.ts +8 -8
- package/src/file/index.ts +1 -1
- package/src/lock/index.ts +3 -3
- package/src/lock/{descriptors → primitives}/$lock.ts +10 -10
- package/src/logger/index.ts +8 -8
- package/src/logger/{descriptors → primitives}/$logger.ts +2 -2
- package/src/logger/services/Logger.ts +1 -1
- package/src/orm/constants/PG_SYMBOLS.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.ts +8 -8
- package/src/orm/{descriptors → primitives}/$entity.ts +11 -11
- package/src/orm/{descriptors → primitives}/$repository.ts +2 -2
- package/src/orm/{descriptors → primitives}/$sequence.ts +8 -8
- package/src/orm/{descriptors → primitives}/$transaction.ts +4 -4
- package/src/orm/providers/PostgresTypeProvider.ts +3 -3
- package/src/orm/providers/RepositoryProvider.ts +4 -4
- package/src/orm/providers/drivers/DatabaseProvider.ts +7 -7
- package/src/orm/services/ModelBuilder.ts +9 -9
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +5 -5
- package/src/orm/services/Repository.ts +7 -7
- package/src/orm/services/SqliteModelBuilder.ts +5 -5
- package/src/queue/index.ts +7 -7
- package/src/queue/{descriptors → primitives}/$consumer.ts +15 -15
- package/src/queue/{descriptors → primitives}/$queue.ts +12 -12
- package/src/queue/providers/WorkerProvider.ts +7 -7
- package/src/retry/index.ts +3 -3
- package/src/retry/{descriptors → primitives}/$retry.ts +14 -14
- package/src/scheduler/index.ts +3 -3
- package/src/scheduler/{descriptors → primitives}/$scheduler.ts +9 -9
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/index.ts +9 -9
- package/src/security/{descriptors → primitives}/$permission.ts +7 -7
- package/src/security/{descriptors → primitives}/$realm.ts +6 -12
- package/src/security/{descriptors → primitives}/$role.ts +12 -12
- package/src/security/{descriptors → primitives}/$serviceAccount.ts +8 -8
- package/src/server/index.browser.ts +1 -1
- package/src/server/index.ts +14 -14
- package/src/server/{descriptors → primitives}/$action.ts +13 -13
- package/src/server/{descriptors → primitives}/$route.ts +9 -9
- package/src/server/providers/NodeHttpServerProvider.ts +1 -1
- package/src/server/services/HttpClient.ts +1 -1
- package/src/server-auth/index.browser.ts +1 -1
- package/src/server-auth/index.ts +6 -6
- package/src/server-auth/{descriptors → primitives}/$auth.ts +10 -10
- package/src/server-auth/{descriptors → primitives}/$authCredentials.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGithub.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGoogle.ts +4 -4
- package/src/server-auth/providers/ServerAuthProvider.ts +4 -4
- package/src/server-cache/providers/ServerCacheProvider.ts +7 -7
- package/src/server-compress/providers/ServerCompressProvider.ts +3 -3
- package/src/server-cookies/index.browser.ts +2 -2
- package/src/server-cookies/index.ts +5 -5
- package/src/server-cookies/{descriptors → primitives}/$cookie.browser.ts +12 -12
- package/src/server-cookies/{descriptors → primitives}/$cookie.ts +13 -13
- package/src/server-cookies/providers/ServerCookiesProvider.ts +4 -4
- package/src/server-cookies/services/CookieParser.ts +1 -1
- package/src/server-cors/index.ts +3 -3
- package/src/server-cors/{descriptors → primitives}/$cors.ts +11 -13
- package/src/server-cors/providers/ServerCorsProvider.ts +5 -5
- package/src/server-links/index.browser.ts +5 -5
- package/src/server-links/index.ts +9 -9
- package/src/server-links/{descriptors → primitives}/$remote.ts +11 -11
- package/src/server-links/providers/LinkProvider.ts +7 -7
- package/src/server-links/providers/{RemoteDescriptorProvider.ts → RemotePrimitiveProvider.ts} +6 -6
- package/src/server-links/providers/ServerLinksProvider.ts +3 -3
- package/src/server-proxy/index.ts +3 -3
- package/src/server-proxy/{descriptors → primitives}/$proxy.ts +8 -8
- package/src/server-proxy/providers/ServerProxyProvider.ts +4 -4
- package/src/server-rate-limit/index.ts +6 -6
- package/src/server-rate-limit/{descriptors → primitives}/$rateLimit.ts +13 -13
- package/src/server-rate-limit/providers/ServerRateLimitProvider.ts +5 -5
- package/src/server-security/index.ts +3 -3
- package/src/server-security/{descriptors → primitives}/$basicAuth.ts +13 -13
- package/src/server-security/providers/ServerBasicAuthProvider.ts +5 -5
- package/src/server-security/providers/ServerSecurityProvider.ts +4 -4
- package/src/server-static/index.ts +3 -3
- package/src/server-static/{descriptors → primitives}/$serve.ts +8 -10
- package/src/server-static/providers/ServerStaticProvider.ts +6 -6
- package/src/server-swagger/index.ts +5 -5
- package/src/server-swagger/{descriptors → primitives}/$swagger.ts +9 -9
- package/src/server-swagger/providers/ServerSwaggerProvider.ts +11 -10
- package/src/sms/index.ts +4 -4
- package/src/sms/{descriptors → primitives}/$sms.ts +8 -8
- package/src/thread/index.ts +3 -3
- package/src/thread/{descriptors → primitives}/$thread.ts +13 -13
- package/src/thread/providers/ThreadProvider.ts +7 -9
- package/src/topic/index.ts +5 -5
- package/src/topic/{descriptors → primitives}/$subscriber.ts +14 -14
- package/src/topic/{descriptors → primitives}/$topic.ts +10 -10
- package/src/topic/providers/TopicProvider.ts +4 -4
- package/src/vite/tasks/copyAssets.ts +1 -1
- package/src/vite/tasks/generateSitemap.ts +3 -3
- package/src/vite/tasks/prerenderPages.ts +2 -2
- package/src/vite/tasks/runAlepha.ts +2 -2
- package/src/websocket/index.browser.ts +3 -3
- package/src/websocket/index.shared.ts +2 -2
- package/src/websocket/index.ts +4 -4
- package/src/websocket/interfaces/WebSocketInterfaces.ts +3 -3
- package/src/websocket/{descriptors → primitives}/$channel.ts +10 -10
- package/src/websocket/{descriptors → primitives}/$websocket.ts +8 -8
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +7 -7
- package/src/websocket/providers/WebSocketServerProvider.ts +3 -3
- package/src/websocket/services/WebSocketClient.ts +5 -5
- package/src/api-notifications/providers/MemorySmsProvider.ts +0 -20
- package/src/api-notifications/providers/SmsProvider.ts +0 -8
- /package/src/core/{descriptors → primitives}/$atom.ts +0 -0
- /package/src/core/{descriptors → primitives}/$env.ts +0 -0
- /package/src/server-auth/{descriptors → primitives}/$authApple.ts +0 -0
- /package/src/server-links/{descriptors → primitives}/$client.ts +0 -0
|
@@ -1,237 +1,14 @@
|
|
|
1
|
-
import { $context, $
|
|
2
|
-
import { $
|
|
3
|
-
import { createCipheriv, createDecipheriv, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
4
|
-
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
1
|
+
import { $context, $hook, $inject, $module, Alepha, AlephaError, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
2
|
+
import { $cookie, AlephaServerCookies, ServerCookiesProvider } from "alepha/server/cookies";
|
|
5
3
|
import { DateTimeProvider } from "alepha/datetime";
|
|
4
|
+
import { InvalidCredentialsError, SecurityError, SecurityProvider, userAccountInfoSchema } from "alepha/security";
|
|
6
5
|
import { $logger } from "alepha/logger";
|
|
7
|
-
import { $
|
|
8
|
-
import {
|
|
9
|
-
import { ReadableStream } from "node:stream/web";
|
|
6
|
+
import { $route, BadRequestError } from "alepha/server";
|
|
7
|
+
import { ServerLinksProvider, apiLinksResponseSchema } from "alepha/server/links";
|
|
10
8
|
|
|
11
|
-
//#region src/server-cookies/services/CookieParser.ts
|
|
12
|
-
var CookieParser = class {
|
|
13
|
-
parseRequestCookies(header) {
|
|
14
|
-
const cookies = {};
|
|
15
|
-
const parts = header.split(";");
|
|
16
|
-
for (const part of parts) {
|
|
17
|
-
const [key, value] = part.split("=");
|
|
18
|
-
if (!key || !value) continue;
|
|
19
|
-
cookies[key.trim()] = value.trim();
|
|
20
|
-
}
|
|
21
|
-
return cookies;
|
|
22
|
-
}
|
|
23
|
-
serializeResponseCookies(cookies, isHttps) {
|
|
24
|
-
const headers$1 = [];
|
|
25
|
-
for (const [name, cookie] of Object.entries(cookies)) {
|
|
26
|
-
if (cookie == null) {
|
|
27
|
-
headers$1.push(`${name}=; Path=/; Max-Age=0`);
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
if (!cookie.value) continue;
|
|
31
|
-
headers$1.push(this.cookieToString(name, cookie, isHttps));
|
|
32
|
-
}
|
|
33
|
-
return headers$1;
|
|
34
|
-
}
|
|
35
|
-
cookieToString(name, cookie, isHttps) {
|
|
36
|
-
const parts = [];
|
|
37
|
-
parts.push(`${name}=${cookie.value}`);
|
|
38
|
-
if (cookie.path) parts.push(`Path=${cookie.path}`);
|
|
39
|
-
if (cookie.maxAge) parts.push(`Max-Age=${cookie.maxAge}`);
|
|
40
|
-
if (cookie.secure !== false && isHttps) parts.push("Secure");
|
|
41
|
-
if (cookie.httpOnly) parts.push("HttpOnly");
|
|
42
|
-
if (cookie.sameSite) parts.push(`SameSite=${cookie.sameSite}`);
|
|
43
|
-
if (cookie.domain) parts.push(`Domain=${cookie.domain}`);
|
|
44
|
-
return parts.join("; ");
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
//#endregion
|
|
49
|
-
//#region src/server-cookies/providers/ServerCookiesProvider.ts
|
|
50
|
-
const envSchema$2 = t.object({ APP_SECRET: t.text({ default: DEFAULT_APP_SECRET }) });
|
|
51
|
-
var ServerCookiesProvider = class {
|
|
52
|
-
alepha = $inject(Alepha);
|
|
53
|
-
log = $logger();
|
|
54
|
-
cookieParser = $inject(CookieParser);
|
|
55
|
-
dateTimeProvider = $inject(DateTimeProvider);
|
|
56
|
-
env = $env(envSchema$2);
|
|
57
|
-
ALGORITHM = "aes-256-gcm";
|
|
58
|
-
IV_LENGTH = 16;
|
|
59
|
-
AUTH_TAG_LENGTH = 16;
|
|
60
|
-
SIGNATURE_LENGTH = 32;
|
|
61
|
-
onRequest = $hook({
|
|
62
|
-
on: "server:onRequest",
|
|
63
|
-
handler: async ({ request }) => {
|
|
64
|
-
request.cookies = {
|
|
65
|
-
req: this.cookieParser.parseRequestCookies(request.headers.cookie ?? ""),
|
|
66
|
-
res: {}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
onAction = $hook({
|
|
71
|
-
on: "action:onRequest",
|
|
72
|
-
handler: async ({ request }) => {
|
|
73
|
-
request.cookies = {
|
|
74
|
-
req: this.cookieParser.parseRequestCookies(request.headers.cookie ?? ""),
|
|
75
|
-
res: {}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
onSend = $hook({
|
|
80
|
-
on: "server:onSend",
|
|
81
|
-
handler: async ({ request }) => {
|
|
82
|
-
if (request.cookies && Object.keys(request.cookies.res).length > 0) {
|
|
83
|
-
const setCookieHeaders = this.cookieParser.serializeResponseCookies(request.cookies.res, request.url.protocol === "https:");
|
|
84
|
-
if (setCookieHeaders.length > 0) request.reply.headers["set-cookie"] = setCookieHeaders;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
getCookiesFromContext(cookies) {
|
|
89
|
-
const contextCookies = this.alepha.context.get("request")?.cookies;
|
|
90
|
-
if (cookies) return cookies;
|
|
91
|
-
if (contextCookies) return contextCookies;
|
|
92
|
-
throw new Error("Cookie context is not available. This method must be called within a server request cycle.");
|
|
93
|
-
}
|
|
94
|
-
getCookie(name, options, contextCookies) {
|
|
95
|
-
const cookies = this.getCookiesFromContext(contextCookies);
|
|
96
|
-
let rawValue = cookies.req[name];
|
|
97
|
-
if (!rawValue) return void 0;
|
|
98
|
-
try {
|
|
99
|
-
rawValue = decodeURIComponent(rawValue);
|
|
100
|
-
if (options.sign) {
|
|
101
|
-
const signature = rawValue.substring(0, this.SIGNATURE_LENGTH * 2);
|
|
102
|
-
const value = rawValue.substring(this.SIGNATURE_LENGTH * 2);
|
|
103
|
-
const expectedSignature = this.sign(value);
|
|
104
|
-
if (!timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expectedSignature, "hex"))) {
|
|
105
|
-
this.log.warn(`Invalid signature for cookie "${name}".`);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
rawValue = value;
|
|
109
|
-
}
|
|
110
|
-
if (options.encrypt) rawValue = this.decrypt(rawValue);
|
|
111
|
-
if (options.compress) rawValue = inflateRawSync(Buffer.from(rawValue, "base64")).toString("utf8");
|
|
112
|
-
return this.alepha.codec.decode(options.schema, JSON.parse(rawValue));
|
|
113
|
-
} catch (error) {
|
|
114
|
-
this.log.warn(`Failed to parse cookie "${name}"`, error);
|
|
115
|
-
this.deleteCookie(name, cookies);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
setCookie(name, options, data, contextCookies) {
|
|
120
|
-
const cookies = this.getCookiesFromContext(contextCookies);
|
|
121
|
-
let value = JSON.stringify(this.alepha.codec.decode(options.schema, data));
|
|
122
|
-
if (options.compress) value = deflateRawSync(value).toString("base64");
|
|
123
|
-
if (options.encrypt) value = this.encrypt(value);
|
|
124
|
-
if (options.sign) value = this.sign(value) + value;
|
|
125
|
-
const cookie = {
|
|
126
|
-
value: encodeURIComponent(value),
|
|
127
|
-
path: options.path ?? "/",
|
|
128
|
-
sameSite: options.sameSite ?? "lax",
|
|
129
|
-
secure: options.secure ?? this.alepha.isProduction(),
|
|
130
|
-
httpOnly: options.httpOnly,
|
|
131
|
-
domain: options.domain
|
|
132
|
-
};
|
|
133
|
-
if (options.ttl) cookie.maxAge = this.dateTimeProvider.duration(options.ttl).as("seconds");
|
|
134
|
-
cookies.res[name] = cookie;
|
|
135
|
-
}
|
|
136
|
-
deleteCookie(name, contextCookies) {
|
|
137
|
-
const cookies = this.getCookiesFromContext(contextCookies);
|
|
138
|
-
cookies.res[name] = null;
|
|
139
|
-
}
|
|
140
|
-
encrypt(text) {
|
|
141
|
-
const iv = randomBytes(this.IV_LENGTH);
|
|
142
|
-
const cipher = createCipheriv(this.ALGORITHM, Buffer.from(this.secretKey()), iv);
|
|
143
|
-
const encrypted = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
|
|
144
|
-
const authTag = cipher.getAuthTag();
|
|
145
|
-
return Buffer.concat([
|
|
146
|
-
iv,
|
|
147
|
-
authTag,
|
|
148
|
-
encrypted
|
|
149
|
-
]).toString("base64");
|
|
150
|
-
}
|
|
151
|
-
decrypt(encryptedText) {
|
|
152
|
-
const data = Buffer.from(encryptedText, "base64");
|
|
153
|
-
const iv = data.subarray(0, this.IV_LENGTH);
|
|
154
|
-
const authTag = data.subarray(this.IV_LENGTH, this.IV_LENGTH + this.AUTH_TAG_LENGTH);
|
|
155
|
-
const encrypted = data.subarray(this.IV_LENGTH + this.AUTH_TAG_LENGTH);
|
|
156
|
-
const decipher = createDecipheriv(this.ALGORITHM, Buffer.from(this.secretKey()), iv);
|
|
157
|
-
decipher.setAuthTag(authTag);
|
|
158
|
-
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
|
|
159
|
-
}
|
|
160
|
-
secretKey() {
|
|
161
|
-
let secret = this.env.APP_SECRET;
|
|
162
|
-
if (secret.length < 32) secret = secret.padEnd(32, "0");
|
|
163
|
-
else if (secret.length > 32) secret = secret.substring(0, 32);
|
|
164
|
-
return secret;
|
|
165
|
-
}
|
|
166
|
-
sign(data) {
|
|
167
|
-
return createHmac("sha256", this.secretKey()).update(data).digest("hex");
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
//#endregion
|
|
172
|
-
//#region src/server-cookies/descriptors/$cookie.ts
|
|
173
|
-
/**
|
|
174
|
-
* Declares a type-safe, configurable HTTP cookie.
|
|
175
|
-
* This descriptor provides methods to get, set, and delete the cookie
|
|
176
|
-
* within the server request/response cycle.
|
|
177
|
-
*/
|
|
178
|
-
const $cookie = (options) => {
|
|
179
|
-
return createDescriptor(CookieDescriptor, options);
|
|
180
|
-
};
|
|
181
|
-
var CookieDescriptor = class extends Descriptor {
|
|
182
|
-
serverCookiesProvider = $inject(ServerCookiesProvider);
|
|
183
|
-
get schema() {
|
|
184
|
-
return this.options.schema;
|
|
185
|
-
}
|
|
186
|
-
get name() {
|
|
187
|
-
return this.options.name ?? `${this.config.propertyKey}`;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Sets the cookie with the given value in the current request's response.
|
|
191
|
-
*/
|
|
192
|
-
set(value, options) {
|
|
193
|
-
this.serverCookiesProvider.setCookie(this.name, {
|
|
194
|
-
...this.options,
|
|
195
|
-
ttl: options?.ttl ?? this.options.ttl
|
|
196
|
-
}, value, options?.cookies);
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Gets the cookie value from the current request. Returns undefined if not found or invalid.
|
|
200
|
-
*/
|
|
201
|
-
get(options) {
|
|
202
|
-
return this.serverCookiesProvider.getCookie(this.name, this.options, options?.cookies);
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Deletes the cookie in the current request's response.
|
|
206
|
-
*/
|
|
207
|
-
del(options) {
|
|
208
|
-
this.serverCookiesProvider.deleteCookie(this.name, options?.cookies);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
$cookie[KIND] = CookieDescriptor;
|
|
212
|
-
|
|
213
|
-
//#endregion
|
|
214
|
-
//#region src/server-cookies/index.ts
|
|
215
|
-
/**
|
|
216
|
-
* Provides HTTP cookie management capabilities for server requests and responses with type-safe cookie descriptors.
|
|
217
|
-
*
|
|
218
|
-
* The server-cookies module enables declarative cookie handling using the `$cookie` descriptor on class properties.
|
|
219
|
-
* It offers automatic cookie parsing, secure cookie configuration, and seamless integration with server routes
|
|
220
|
-
* for managing user sessions, preferences, and authentication tokens.
|
|
221
|
-
*
|
|
222
|
-
* @see {@link $cookie}
|
|
223
|
-
* @module alepha.server.cookies
|
|
224
|
-
*/
|
|
225
|
-
const AlephaServerCookies = $module({
|
|
226
|
-
name: "alepha.server.cookies",
|
|
227
|
-
descriptors: [$cookie],
|
|
228
|
-
services: [AlephaServer, ServerCookiesProvider]
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
//#endregion
|
|
232
9
|
//#region ../../node_modules/oauth4webapi/build/index.js
|
|
233
10
|
let USER_AGENT$1;
|
|
234
|
-
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) USER_AGENT$1 = `oauth4webapi/v3.8.
|
|
11
|
+
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) USER_AGENT$1 = `oauth4webapi/v3.8.3`;
|
|
235
12
|
function looseInstanceOf(input, expected) {
|
|
236
13
|
if (input == null) return false;
|
|
237
14
|
try {
|
|
@@ -435,14 +212,14 @@ function notJson(response, ...types) {
|
|
|
435
212
|
function assertContentType(response, contentType) {
|
|
436
213
|
if (getContentType(response) !== contentType) throw notJson(response, contentType);
|
|
437
214
|
}
|
|
438
|
-
function randomBytes
|
|
215
|
+
function randomBytes() {
|
|
439
216
|
return b64u(crypto.getRandomValues(new Uint8Array(32)));
|
|
440
217
|
}
|
|
441
218
|
function generateRandomCodeVerifier() {
|
|
442
|
-
return randomBytes
|
|
219
|
+
return randomBytes();
|
|
443
220
|
}
|
|
444
221
|
function generateRandomState() {
|
|
445
|
-
return randomBytes
|
|
222
|
+
return randomBytes();
|
|
446
223
|
}
|
|
447
224
|
async function calculatePKCECodeChallenge$1(codeVerifier) {
|
|
448
225
|
assertString$1(codeVerifier, "codeVerifier");
|
|
@@ -562,10 +339,10 @@ var WWWAuthenticateChallengeError = class extends Error {
|
|
|
562
339
|
}
|
|
563
340
|
};
|
|
564
341
|
const tokenMatch = "[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+";
|
|
565
|
-
const token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]
|
|
566
|
-
const quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*\"((?:[^\"\\\\]
|
|
342
|
+
const token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}";
|
|
343
|
+
const quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*\"((?:[^\"\\\\]|\\\\[\\s\\S])*)\"";
|
|
567
344
|
const paramMatcher = "(" + tokenMatch + ")\\s*=\\s*([a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+)";
|
|
568
|
-
const schemeRE = /* @__PURE__ */ new RegExp("^[,\\s]*(" + tokenMatch + ")
|
|
345
|
+
const schemeRE = /* @__PURE__ */ new RegExp("^[,\\s]*(" + tokenMatch + ")");
|
|
569
346
|
const quotedParamRE = /* @__PURE__ */ new RegExp("^[,\\s]*" + quotedParamMatcher + "[,\\s]*(.*)");
|
|
570
347
|
const unquotedParamRE = /* @__PURE__ */ new RegExp("^[,\\s]*" + paramMatcher + "[,\\s]*(.*)");
|
|
571
348
|
const token68ParamRE = /* @__PURE__ */ new RegExp("^(" + token68Match + ")(?:$|[,\\s])(.*)");
|
|
@@ -578,11 +355,15 @@ function parseWwwAuthenticateChallenges(response) {
|
|
|
578
355
|
while (rest) {
|
|
579
356
|
let match = rest.match(schemeRE);
|
|
580
357
|
const scheme = match?.["1"].toLowerCase();
|
|
581
|
-
rest = match?.["2"];
|
|
582
358
|
if (!scheme) return;
|
|
359
|
+
const afterScheme = rest.substring(match[0].length);
|
|
360
|
+
if (afterScheme && !afterScheme.match(/^[\s,]/)) return;
|
|
361
|
+
const spaceMatch = afterScheme.match(/^\s+(.*)$/);
|
|
362
|
+
const hasParameters = !!spaceMatch;
|
|
363
|
+
rest = spaceMatch ? spaceMatch[1] : void 0;
|
|
583
364
|
const parameters = {};
|
|
584
365
|
let token68;
|
|
585
|
-
while (rest) {
|
|
366
|
+
if (hasParameters) while (rest) {
|
|
586
367
|
let key;
|
|
587
368
|
let value;
|
|
588
369
|
if (match = rest.match(quotedParamRE)) {
|
|
@@ -605,6 +386,7 @@ function parseWwwAuthenticateChallenges(response) {
|
|
|
605
386
|
}
|
|
606
387
|
return;
|
|
607
388
|
}
|
|
389
|
+
else rest = afterScheme || void 0;
|
|
608
390
|
const challenge = {
|
|
609
391
|
scheme,
|
|
610
392
|
parameters
|
|
@@ -1456,9 +1238,9 @@ function retryable(err, options) {
|
|
|
1456
1238
|
const retry = Symbol();
|
|
1457
1239
|
|
|
1458
1240
|
//#endregion
|
|
1459
|
-
//#region src/server-auth/
|
|
1241
|
+
//#region src/server-auth/primitives/$auth.ts
|
|
1460
1242
|
/**
|
|
1461
|
-
* Creates an authentication provider
|
|
1243
|
+
* Creates an authentication provider primitive for handling user login flows.
|
|
1462
1244
|
*
|
|
1463
1245
|
* Supports multiple authentication strategies: credentials (username/password), OAuth2,
|
|
1464
1246
|
* and OIDC (OpenID Connect). Handles token management, user profile retrieval, and
|
|
@@ -1492,9 +1274,9 @@ const retry = Symbol();
|
|
|
1492
1274
|
* ```
|
|
1493
1275
|
*/
|
|
1494
1276
|
const $auth = (options) => {
|
|
1495
|
-
return
|
|
1277
|
+
return createPrimitive(AuthPrimitive, options);
|
|
1496
1278
|
};
|
|
1497
|
-
var
|
|
1279
|
+
var AuthPrimitive = class extends Primitive {
|
|
1498
1280
|
securityProvider = $inject(SecurityProvider);
|
|
1499
1281
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
1500
1282
|
oauth;
|
|
@@ -1587,981 +1369,7 @@ var AuthDescriptor = class extends Descriptor {
|
|
|
1587
1369
|
}
|
|
1588
1370
|
}
|
|
1589
1371
|
};
|
|
1590
|
-
$auth[KIND] =
|
|
1591
|
-
|
|
1592
|
-
//#endregion
|
|
1593
|
-
//#region src/server-security/providers/ServerBasicAuthProvider.ts
|
|
1594
|
-
var ServerBasicAuthProvider = class {
|
|
1595
|
-
alepha = $inject(Alepha);
|
|
1596
|
-
log = $logger();
|
|
1597
|
-
routerProvider = $inject(ServerRouterProvider);
|
|
1598
|
-
realm = "Secure Area";
|
|
1599
|
-
/**
|
|
1600
|
-
* Registered basic auth descriptors with their configurations
|
|
1601
|
-
*/
|
|
1602
|
-
registeredAuths = [];
|
|
1603
|
-
/**
|
|
1604
|
-
* Register a basic auth configuration (called by descriptors)
|
|
1605
|
-
*/
|
|
1606
|
-
registerAuth(config) {
|
|
1607
|
-
this.registeredAuths.push(config);
|
|
1608
|
-
}
|
|
1609
|
-
onStart = $hook({
|
|
1610
|
-
on: "start",
|
|
1611
|
-
handler: async () => {
|
|
1612
|
-
for (const auth of this.registeredAuths) if (auth.paths) for (const pattern of auth.paths) {
|
|
1613
|
-
const matchedRoutes = this.routerProvider.getRoutes(pattern);
|
|
1614
|
-
for (const route of matchedRoutes) route.secure = { basic: {
|
|
1615
|
-
username: auth.username,
|
|
1616
|
-
password: auth.password
|
|
1617
|
-
} };
|
|
1618
|
-
}
|
|
1619
|
-
if (this.registeredAuths.length > 0) this.log.info(`Initialized with ${this.registeredAuths.length} registered basic-auth configurations.`);
|
|
1620
|
-
}
|
|
1621
|
-
});
|
|
1622
|
-
/**
|
|
1623
|
-
* Hook into server:onRequest to check basic auth
|
|
1624
|
-
*/
|
|
1625
|
-
onRequest = $hook({
|
|
1626
|
-
on: "server:onRequest",
|
|
1627
|
-
handler: async ({ route, request }) => {
|
|
1628
|
-
const routeAuth = route.secure;
|
|
1629
|
-
if (typeof routeAuth === "object" && "basic" in routeAuth && routeAuth.basic) this.checkAuth(request, routeAuth.basic);
|
|
1630
|
-
}
|
|
1631
|
-
});
|
|
1632
|
-
/**
|
|
1633
|
-
* Hook into action:onRequest to check basic auth for actions
|
|
1634
|
-
*/
|
|
1635
|
-
onActionRequest = $hook({
|
|
1636
|
-
on: "action:onRequest",
|
|
1637
|
-
handler: async ({ action, request }) => {
|
|
1638
|
-
const routeAuth = action.route.secure;
|
|
1639
|
-
if (isBasicAuth(routeAuth)) this.checkAuth(request, routeAuth.basic);
|
|
1640
|
-
}
|
|
1641
|
-
});
|
|
1642
|
-
/**
|
|
1643
|
-
* Check basic authentication
|
|
1644
|
-
*/
|
|
1645
|
-
checkAuth(request, options) {
|
|
1646
|
-
const authHeader = request.headers?.authorization;
|
|
1647
|
-
if (!authHeader || !authHeader.startsWith("Basic ")) {
|
|
1648
|
-
this.sendAuthRequired(request);
|
|
1649
|
-
throw new HttpError({
|
|
1650
|
-
status: 401,
|
|
1651
|
-
message: "Authentication required"
|
|
1652
|
-
});
|
|
1653
|
-
}
|
|
1654
|
-
const base64Credentials = authHeader.slice(6);
|
|
1655
|
-
const credentials = Buffer.from(base64Credentials, "base64").toString("utf-8");
|
|
1656
|
-
const colonIndex = credentials.indexOf(":");
|
|
1657
|
-
const username = colonIndex !== -1 ? credentials.slice(0, colonIndex) : credentials;
|
|
1658
|
-
const password = colonIndex !== -1 ? credentials.slice(colonIndex + 1) : "";
|
|
1659
|
-
if (!this.timingSafeCredentialCheck(username, password, options.username, options.password)) {
|
|
1660
|
-
this.sendAuthRequired(request);
|
|
1661
|
-
this.log.warn(`Failed basic auth attempt for user`, { username });
|
|
1662
|
-
throw new HttpError({
|
|
1663
|
-
status: 401,
|
|
1664
|
-
message: "Invalid credentials"
|
|
1665
|
-
});
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
/**
|
|
1669
|
-
* Performs a timing-safe comparison of credentials to prevent timing attacks.
|
|
1670
|
-
* Always compares both username and password to avoid leaking which one is wrong.
|
|
1671
|
-
*/
|
|
1672
|
-
timingSafeCredentialCheck(inputUsername, inputPassword, expectedUsername, expectedPassword) {
|
|
1673
|
-
const inputUserBuf = Buffer.from(inputUsername, "utf-8");
|
|
1674
|
-
const expectedUserBuf = Buffer.from(expectedUsername, "utf-8");
|
|
1675
|
-
const inputPassBuf = Buffer.from(inputPassword, "utf-8");
|
|
1676
|
-
const expectedPassBuf = Buffer.from(expectedPassword, "utf-8");
|
|
1677
|
-
return (this.safeCompare(inputUserBuf, expectedUserBuf) & this.safeCompare(inputPassBuf, expectedPassBuf)) === 1;
|
|
1678
|
-
}
|
|
1679
|
-
/**
|
|
1680
|
-
* Compares two buffers in constant time, handling different lengths safely.
|
|
1681
|
-
* Returns 1 if equal, 0 if not equal.
|
|
1682
|
-
*/
|
|
1683
|
-
safeCompare(input, expected) {
|
|
1684
|
-
if (input.length !== expected.length) {
|
|
1685
|
-
timingSafeEqual(input, input);
|
|
1686
|
-
return 0;
|
|
1687
|
-
}
|
|
1688
|
-
return timingSafeEqual(input, expected) ? 1 : 0;
|
|
1689
|
-
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Send WWW-Authenticate header
|
|
1692
|
-
*/
|
|
1693
|
-
sendAuthRequired(request) {
|
|
1694
|
-
request.reply.setHeader("WWW-Authenticate", `Basic realm="${this.realm}"`);
|
|
1695
|
-
}
|
|
1696
|
-
};
|
|
1697
|
-
const isBasicAuth = (value) => {
|
|
1698
|
-
return typeof value === "object" && !!value && "basic" in value && !!value.basic;
|
|
1699
|
-
};
|
|
1700
|
-
|
|
1701
|
-
//#endregion
|
|
1702
|
-
//#region src/server-security/descriptors/$basicAuth.ts
|
|
1703
|
-
/**
|
|
1704
|
-
* Declares HTTP Basic Authentication for server routes.
|
|
1705
|
-
* This descriptor provides methods to protect routes with username/password authentication.
|
|
1706
|
-
*/
|
|
1707
|
-
const $basicAuth = (options) => {
|
|
1708
|
-
return createDescriptor(BasicAuthDescriptor, options);
|
|
1709
|
-
};
|
|
1710
|
-
var BasicAuthDescriptor = class extends Descriptor {
|
|
1711
|
-
serverBasicAuthProvider = $inject(ServerBasicAuthProvider);
|
|
1712
|
-
get name() {
|
|
1713
|
-
return this.options.name ?? `${this.config.propertyKey}`;
|
|
1714
|
-
}
|
|
1715
|
-
onInit() {
|
|
1716
|
-
this.serverBasicAuthProvider.registerAuth(this.options);
|
|
1717
|
-
}
|
|
1718
|
-
/**
|
|
1719
|
-
* Checks basic auth for the given request using this descriptor's configuration.
|
|
1720
|
-
*/
|
|
1721
|
-
check(request, options) {
|
|
1722
|
-
const mergedOptions = {
|
|
1723
|
-
...this.options,
|
|
1724
|
-
...options
|
|
1725
|
-
};
|
|
1726
|
-
this.serverBasicAuthProvider.checkAuth(request, mergedOptions);
|
|
1727
|
-
}
|
|
1728
|
-
};
|
|
1729
|
-
$basicAuth[KIND] = BasicAuthDescriptor;
|
|
1730
|
-
|
|
1731
|
-
//#endregion
|
|
1732
|
-
//#region src/server-security/providers/ServerSecurityProvider.ts
|
|
1733
|
-
var ServerSecurityProvider = class {
|
|
1734
|
-
log = $logger();
|
|
1735
|
-
securityProvider = $inject(SecurityProvider);
|
|
1736
|
-
jwtProvider = $inject(JwtProvider);
|
|
1737
|
-
alepha = $inject(Alepha);
|
|
1738
|
-
onConfigure = $hook({
|
|
1739
|
-
on: "configure",
|
|
1740
|
-
handler: async () => {
|
|
1741
|
-
for (const action of this.alepha.descriptors($action)) {
|
|
1742
|
-
if (action.options.disabled || action.options.secure === false || this.securityProvider.getRealms().length === 0) continue;
|
|
1743
|
-
if (typeof action.options.secure !== "object") this.securityProvider.createPermission({
|
|
1744
|
-
name: action.name,
|
|
1745
|
-
group: action.group,
|
|
1746
|
-
method: action.route.method,
|
|
1747
|
-
path: action.route.path
|
|
1748
|
-
});
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
});
|
|
1752
|
-
onActionRequest = $hook({
|
|
1753
|
-
on: "action:onRequest",
|
|
1754
|
-
handler: async ({ action, request, options }) => {
|
|
1755
|
-
if (action.options.secure === false && !options.user) {
|
|
1756
|
-
this.log.trace("Skipping security check for route");
|
|
1757
|
-
return;
|
|
1758
|
-
}
|
|
1759
|
-
if (isBasicAuth(action.route.secure)) return;
|
|
1760
|
-
const permission = this.securityProvider.getPermissions().find((it) => it.path === action.route.path && it.method === action.route.method);
|
|
1761
|
-
try {
|
|
1762
|
-
request.user = this.createUserFromLocalFunctionContext(options, permission);
|
|
1763
|
-
const route = action.route;
|
|
1764
|
-
if (typeof route.secure === "object") this.check(request.user, route.secure);
|
|
1765
|
-
this.alepha.state.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
|
|
1766
|
-
} catch (error) {
|
|
1767
|
-
if (action.options.secure || permission) throw error;
|
|
1768
|
-
this.log.trace("Skipping security check for action");
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
});
|
|
1772
|
-
onRequest = $hook({
|
|
1773
|
-
on: "server:onRequest",
|
|
1774
|
-
priority: "last",
|
|
1775
|
-
handler: async ({ request, route }) => {
|
|
1776
|
-
if (route.secure === false) {
|
|
1777
|
-
this.log.trace("Skipping security check for route - explicitly disabled");
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
if (isBasicAuth(route.secure)) return;
|
|
1781
|
-
const permission = this.securityProvider.getPermissions().find((it) => it.path === route.path && it.method === route.method);
|
|
1782
|
-
if (!request.headers.authorization && !route.secure && !permission) {
|
|
1783
|
-
this.log.trace("Skipping security check for route - no authorization header and not secure");
|
|
1784
|
-
return;
|
|
1785
|
-
}
|
|
1786
|
-
try {
|
|
1787
|
-
request.user = await this.securityProvider.createUserFromToken(request.headers.authorization, { permission });
|
|
1788
|
-
if (typeof route.secure === "object") this.check(request.user, route.secure);
|
|
1789
|
-
this.alepha.state.set("alepha.server.request.user", this.alepha.codec.decode(userAccountInfoSchema, request.user));
|
|
1790
|
-
this.log.trace("User set from request token", {
|
|
1791
|
-
user: request.user,
|
|
1792
|
-
permission
|
|
1793
|
-
});
|
|
1794
|
-
} catch (error) {
|
|
1795
|
-
if (route.secure || permission) throw error;
|
|
1796
|
-
this.log.trace("Skipping security check for route - error occurred", error);
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
});
|
|
1800
|
-
check(user, secure) {
|
|
1801
|
-
if (secure.realm) {
|
|
1802
|
-
if (user.realm !== secure.realm) throw new ForbiddenError(`User must belong to realm '${secure.realm}' to access this route`);
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
/**
|
|
1806
|
-
* Get the user account token for a local action call.
|
|
1807
|
-
* There are three possible sources for the user:
|
|
1808
|
-
* - `options.user`: the user passed in the options
|
|
1809
|
-
* - `"system"`: the system user from the state (you MUST set state `server.security.system.user`)
|
|
1810
|
-
* - `"context"`: the user from the request context (you MUST be in an HTTP request context)
|
|
1811
|
-
*
|
|
1812
|
-
* Priority order: `options.user` > `"system"` > `"context"`.
|
|
1813
|
-
*
|
|
1814
|
-
* In testing environment, if no user is provided, a test user is created based on the SecurityProvider's roles.
|
|
1815
|
-
*/
|
|
1816
|
-
createUserFromLocalFunctionContext(options, permission) {
|
|
1817
|
-
const fromOptions = typeof options.user === "object" ? options.user : void 0;
|
|
1818
|
-
const type = typeof options.user === "string" ? options.user : void 0;
|
|
1819
|
-
let user;
|
|
1820
|
-
const fromContext = this.alepha.context.get("request")?.user;
|
|
1821
|
-
const fromSystem = this.alepha.state.get("alepha.server.security.system.user");
|
|
1822
|
-
if (type === "system") user = fromSystem;
|
|
1823
|
-
else if (type === "context") user = fromContext;
|
|
1824
|
-
else user = fromOptions ?? fromContext ?? fromSystem;
|
|
1825
|
-
if (!user) {
|
|
1826
|
-
if (this.alepha.isTest() && !("user" in options)) return this.createTestUser();
|
|
1827
|
-
throw new UnauthorizedError("User is required for calling this action");
|
|
1828
|
-
}
|
|
1829
|
-
const roles = user.roles ?? (this.alepha.isTest() ? this.securityProvider.getRoles().map((role) => role.name) : []);
|
|
1830
|
-
let ownership;
|
|
1831
|
-
if (permission) {
|
|
1832
|
-
const result = this.securityProvider.checkPermission(permission, ...roles);
|
|
1833
|
-
if (!result.isAuthorized) throw new ForbiddenError(`Permission '${this.securityProvider.permissionToString(permission)}' is required for this route`);
|
|
1834
|
-
ownership = result.ownership;
|
|
1835
|
-
}
|
|
1836
|
-
return {
|
|
1837
|
-
...user,
|
|
1838
|
-
ownership
|
|
1839
|
-
};
|
|
1840
|
-
}
|
|
1841
|
-
createTestUser() {
|
|
1842
|
-
return {
|
|
1843
|
-
id: randomUUID(),
|
|
1844
|
-
name: "Test",
|
|
1845
|
-
roles: this.securityProvider.getRoles().map((role) => role.name)
|
|
1846
|
-
};
|
|
1847
|
-
}
|
|
1848
|
-
onClientRequest = $hook({
|
|
1849
|
-
on: "client:onRequest",
|
|
1850
|
-
handler: async ({ request, options }) => {
|
|
1851
|
-
if (!this.alepha.isTest()) return;
|
|
1852
|
-
if ("user" in options && options.user === void 0) return;
|
|
1853
|
-
request.headers = new Headers(request.headers);
|
|
1854
|
-
if (!request.headers.has("authorization")) {
|
|
1855
|
-
const test = this.createTestUser();
|
|
1856
|
-
const user = typeof options?.user === "object" ? options.user : void 0;
|
|
1857
|
-
const sub = user?.id ?? test.id;
|
|
1858
|
-
const roles = user?.roles ?? test.roles;
|
|
1859
|
-
const token = await this.jwtProvider.create({
|
|
1860
|
-
sub,
|
|
1861
|
-
roles
|
|
1862
|
-
}, user?.realm ?? this.securityProvider.getRealms()[0]?.name);
|
|
1863
|
-
request.headers.set("authorization", `Bearer ${token}`);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
});
|
|
1867
|
-
};
|
|
1868
|
-
|
|
1869
|
-
//#endregion
|
|
1870
|
-
//#region src/server-security/index.ts
|
|
1871
|
-
/**
|
|
1872
|
-
* Plugin for Alepha Server that provides security features. Based on the Alepha Security module.
|
|
1873
|
-
*
|
|
1874
|
-
* By default, all $action will be guarded by a permission check.
|
|
1875
|
-
*
|
|
1876
|
-
* @see {@link ServerSecurityProvider}
|
|
1877
|
-
* @module alepha.server.security
|
|
1878
|
-
*/
|
|
1879
|
-
const AlephaServerSecurity = $module({
|
|
1880
|
-
name: "alepha.server.security",
|
|
1881
|
-
descriptors: [
|
|
1882
|
-
$realm,
|
|
1883
|
-
$role,
|
|
1884
|
-
$permission,
|
|
1885
|
-
$basicAuth
|
|
1886
|
-
],
|
|
1887
|
-
services: [
|
|
1888
|
-
AlephaServer,
|
|
1889
|
-
AlephaSecurity,
|
|
1890
|
-
ServerSecurityProvider,
|
|
1891
|
-
ServerBasicAuthProvider
|
|
1892
|
-
]
|
|
1893
|
-
});
|
|
1894
|
-
|
|
1895
|
-
//#endregion
|
|
1896
|
-
//#region src/server-links/schemas/apiLinksResponseSchema.ts
|
|
1897
|
-
const apiLinkSchema = t.object({
|
|
1898
|
-
name: t.text({ description: "Name of the API link, used for identification." }),
|
|
1899
|
-
group: t.optional(t.text({ description: "Group to which the API link belongs, used for categorization." })),
|
|
1900
|
-
path: t.text({ description: "Pathname used to access the API link." }),
|
|
1901
|
-
method: t.optional(t.text({ description: "HTTP method used for the API link, e.g., GET, POST, etc. If not specified, defaults to GET." })),
|
|
1902
|
-
requestBodyType: t.optional(t.text({ description: "Type of the request body for the API link. Default is application/json for POST/PUT/PATCH, null for others." })),
|
|
1903
|
-
service: t.optional(t.text({ description: "Service name associated with the API link, used for service discovery." }))
|
|
1904
|
-
});
|
|
1905
|
-
const apiLinksResponseSchema = t.object({
|
|
1906
|
-
prefix: t.optional(t.text()),
|
|
1907
|
-
links: t.array(apiLinkSchema)
|
|
1908
|
-
});
|
|
1909
|
-
|
|
1910
|
-
//#endregion
|
|
1911
|
-
//#region src/server-links/providers/LinkProvider.ts
|
|
1912
|
-
/**
|
|
1913
|
-
* Browser, SSR friendly, service to handle links.
|
|
1914
|
-
*/
|
|
1915
|
-
var LinkProvider = class LinkProvider {
|
|
1916
|
-
static path = {
|
|
1917
|
-
apiLinks: "/api/_links",
|
|
1918
|
-
apiSchema: "/api/_links/:name/schema"
|
|
1919
|
-
};
|
|
1920
|
-
log = $logger();
|
|
1921
|
-
alepha = $inject(Alepha);
|
|
1922
|
-
httpClient = $inject(HttpClient);
|
|
1923
|
-
serverLinks = [];
|
|
1924
|
-
/**
|
|
1925
|
-
* Get applicative links registered on the server.
|
|
1926
|
-
* This does not include lazy-loaded remote links.
|
|
1927
|
-
*/
|
|
1928
|
-
getServerLinks() {
|
|
1929
|
-
if (this.alepha.isBrowser()) {
|
|
1930
|
-
this.log.warn("Getting server links in the browser is not supported. Use `fetchLinks` to get links from the server.");
|
|
1931
|
-
return [];
|
|
1932
|
-
}
|
|
1933
|
-
return this.serverLinks;
|
|
1934
|
-
}
|
|
1935
|
-
/**
|
|
1936
|
-
* Register a new link for the application.
|
|
1937
|
-
*/
|
|
1938
|
-
registerLink(link) {
|
|
1939
|
-
if (this.alepha.isBrowser()) {
|
|
1940
|
-
this.log.warn("Registering links in the browser is not supported. Use `fetchLinks` to get links from the server.");
|
|
1941
|
-
return;
|
|
1942
|
-
}
|
|
1943
|
-
if (!link.handler && !link.host) throw new AlephaError("Can't create link - 'handler' or 'host' is required");
|
|
1944
|
-
if (this.serverLinks.some((l) => l.name === link.name)) this.serverLinks = this.serverLinks.filter((l) => l.name !== link.name);
|
|
1945
|
-
this.serverLinks.push(link);
|
|
1946
|
-
}
|
|
1947
|
-
get links() {
|
|
1948
|
-
const apiLinks = this.alepha.state.get("alepha.server.request.apiLinks")?.links;
|
|
1949
|
-
if (apiLinks) {
|
|
1950
|
-
if (this.alepha.isBrowser()) return apiLinks;
|
|
1951
|
-
const links = [];
|
|
1952
|
-
for (const link of apiLinks) {
|
|
1953
|
-
const originalLink = this.serverLinks.find((l) => l.name === link.name);
|
|
1954
|
-
if (originalLink) links.push(originalLink);
|
|
1955
|
-
}
|
|
1956
|
-
return links;
|
|
1957
|
-
}
|
|
1958
|
-
return this.serverLinks ?? [];
|
|
1959
|
-
}
|
|
1960
|
-
/**
|
|
1961
|
-
* Force browser to refresh links from the server.
|
|
1962
|
-
*/
|
|
1963
|
-
async fetchLinks() {
|
|
1964
|
-
const { data } = await this.httpClient.fetch(`${LinkProvider.path.apiLinks}`, {
|
|
1965
|
-
method: "GET",
|
|
1966
|
-
schema: { response: apiLinksResponseSchema }
|
|
1967
|
-
});
|
|
1968
|
-
this.alepha.state.set("alepha.server.request.apiLinks", data);
|
|
1969
|
-
return data.links;
|
|
1970
|
-
}
|
|
1971
|
-
/**
|
|
1972
|
-
* Create a virtual client that can be used to call actions.
|
|
1973
|
-
*
|
|
1974
|
-
* Use js Proxy under the hood.
|
|
1975
|
-
*/
|
|
1976
|
-
client(scope = {}) {
|
|
1977
|
-
return new Proxy({}, { get: (_, prop) => {
|
|
1978
|
-
if (typeof prop !== "string") return;
|
|
1979
|
-
return this.createVirtualAction(prop, scope);
|
|
1980
|
-
} });
|
|
1981
|
-
}
|
|
1982
|
-
/**
|
|
1983
|
-
* Check if a link with the given name exists.
|
|
1984
|
-
* @param name
|
|
1985
|
-
*/
|
|
1986
|
-
can(name) {
|
|
1987
|
-
return this.links.some((link) => link.name === name);
|
|
1988
|
-
}
|
|
1989
|
-
/**
|
|
1990
|
-
* Resolve a link by its name and call it.
|
|
1991
|
-
* - If link is local, it will call the local handler.
|
|
1992
|
-
* - If link is remote, it will make a fetch request to the remote server.
|
|
1993
|
-
*/
|
|
1994
|
-
async follow(name, config = {}, options = {}) {
|
|
1995
|
-
this.log.trace("Following link", {
|
|
1996
|
-
name,
|
|
1997
|
-
config,
|
|
1998
|
-
options
|
|
1999
|
-
});
|
|
2000
|
-
const link = await this.getLinkByName(name, options);
|
|
2001
|
-
if (link.handler && !options.request) {
|
|
2002
|
-
this.log.trace("Local link found", { name });
|
|
2003
|
-
return link.handler({
|
|
2004
|
-
method: link.method,
|
|
2005
|
-
url: new URL(`http://localhost${link.path}`),
|
|
2006
|
-
query: config.query ?? {},
|
|
2007
|
-
body: config.body ?? {},
|
|
2008
|
-
params: config.params ?? {},
|
|
2009
|
-
headers: config.headers ?? {},
|
|
2010
|
-
metadata: {},
|
|
2011
|
-
reply: new ServerReply()
|
|
2012
|
-
}, options);
|
|
2013
|
-
}
|
|
2014
|
-
this.log.trace("Remote link found", {
|
|
2015
|
-
name,
|
|
2016
|
-
host: link.host,
|
|
2017
|
-
service: link.service
|
|
2018
|
-
});
|
|
2019
|
-
return this.followRemote(link, config, options).then((response) => response.data);
|
|
2020
|
-
}
|
|
2021
|
-
createVirtualAction(name, scope = {}) {
|
|
2022
|
-
const $ = async (config = {}, options = {}) => {
|
|
2023
|
-
return this.follow(name, config, {
|
|
2024
|
-
...scope,
|
|
2025
|
-
...options
|
|
2026
|
-
});
|
|
2027
|
-
};
|
|
2028
|
-
Object.defineProperty($, "name", {
|
|
2029
|
-
value: name,
|
|
2030
|
-
writable: false
|
|
2031
|
-
});
|
|
2032
|
-
$.run = async (config = {}, options = {}) => {
|
|
2033
|
-
return this.follow(name, config, {
|
|
2034
|
-
...scope,
|
|
2035
|
-
...options
|
|
2036
|
-
});
|
|
2037
|
-
};
|
|
2038
|
-
$.fetch = async (config = {}, options = {}) => {
|
|
2039
|
-
const link = await this.getLinkByName(name, scope);
|
|
2040
|
-
return this.followRemote(link, config, options);
|
|
2041
|
-
};
|
|
2042
|
-
$.can = () => {
|
|
2043
|
-
return this.can(name);
|
|
2044
|
-
};
|
|
2045
|
-
return $;
|
|
2046
|
-
}
|
|
2047
|
-
async followRemote(link, config = {}, options = {}) {
|
|
2048
|
-
options.request ??= {};
|
|
2049
|
-
options.request.headers = new Headers(options.request.headers);
|
|
2050
|
-
const als = this.alepha.context.get("request");
|
|
2051
|
-
if (als?.headers.authorization) options.request.headers.set("authorization", als.headers.authorization);
|
|
2052
|
-
const context = this.alepha.context.get("context");
|
|
2053
|
-
if (typeof context === "string") options.request.headers.set("x-request-id", context);
|
|
2054
|
-
const action = {
|
|
2055
|
-
...link,
|
|
2056
|
-
schema: {
|
|
2057
|
-
body: t.any(),
|
|
2058
|
-
response: t.any()
|
|
2059
|
-
}
|
|
2060
|
-
};
|
|
2061
|
-
if (!link.host && link.service) action.path = `/${link.service}${action.path}`;
|
|
2062
|
-
action.path = `${action.prefix ?? "/api"}${action.path}`;
|
|
2063
|
-
action.prefix = void 0;
|
|
2064
|
-
return this.httpClient.fetchAction({
|
|
2065
|
-
host: link.host,
|
|
2066
|
-
config,
|
|
2067
|
-
options,
|
|
2068
|
-
action
|
|
2069
|
-
});
|
|
2070
|
-
}
|
|
2071
|
-
async getLinkByName(name, options = {}) {
|
|
2072
|
-
if (this.alepha.isBrowser() && !this.alepha.state.get("alepha.server.request.apiLinks")) await this.fetchLinks();
|
|
2073
|
-
const link = this.links.find((a) => a.name === name && (!options.group || a.group === options.group) && (!options.service || options.service === a.service));
|
|
2074
|
-
if (!link) {
|
|
2075
|
-
const error = new UnauthorizedError(`Action ${name} not found.`);
|
|
2076
|
-
await this.alepha.events.emit("client:onError", {
|
|
2077
|
-
route: link,
|
|
2078
|
-
error
|
|
2079
|
-
});
|
|
2080
|
-
throw error;
|
|
2081
|
-
}
|
|
2082
|
-
if (options.hostname) return {
|
|
2083
|
-
...link,
|
|
2084
|
-
host: options.hostname
|
|
2085
|
-
};
|
|
2086
|
-
return link;
|
|
2087
|
-
}
|
|
2088
|
-
};
|
|
2089
|
-
|
|
2090
|
-
//#endregion
|
|
2091
|
-
//#region src/server-links/descriptors/$client.ts
|
|
2092
|
-
/**
|
|
2093
|
-
* Create a new client.
|
|
2094
|
-
*/
|
|
2095
|
-
const $client = (scope) => {
|
|
2096
|
-
return $inject(LinkProvider).client(scope);
|
|
2097
|
-
};
|
|
2098
|
-
$client[KIND] = "$client";
|
|
2099
|
-
|
|
2100
|
-
//#endregion
|
|
2101
|
-
//#region src/server-links/descriptors/$remote.ts
|
|
2102
|
-
/**
|
|
2103
|
-
* $remote is a descriptor that allows you to define remote service access.
|
|
2104
|
-
*
|
|
2105
|
-
* Use it only when you have 2 or more services that need to communicate with each other.
|
|
2106
|
-
*
|
|
2107
|
-
* All remote services can be exposed as actions, ... or not.
|
|
2108
|
-
*
|
|
2109
|
-
* You can add a service account if you want to use a security layer.
|
|
2110
|
-
*/
|
|
2111
|
-
const $remote = (options) => {
|
|
2112
|
-
return createDescriptor(RemoteDescriptor, options);
|
|
2113
|
-
};
|
|
2114
|
-
var RemoteDescriptor = class extends Descriptor {
|
|
2115
|
-
get name() {
|
|
2116
|
-
return this.options.name ?? this.config.propertyKey;
|
|
2117
|
-
}
|
|
2118
|
-
};
|
|
2119
|
-
$remote[KIND] = RemoteDescriptor;
|
|
2120
|
-
|
|
2121
|
-
//#endregion
|
|
2122
|
-
//#region src/server-proxy/descriptors/$proxy.ts
|
|
2123
|
-
/**
|
|
2124
|
-
* Creates a proxy descriptor to forward requests to another server.
|
|
2125
|
-
*
|
|
2126
|
-
* This descriptor enables you to create reverse proxy functionality, allowing your Alepha server
|
|
2127
|
-
* to forward requests to other services while maintaining a unified API surface. It's particularly
|
|
2128
|
-
* useful for microservice architectures, API gateways, or when you need to aggregate multiple
|
|
2129
|
-
* services behind a single endpoint.
|
|
2130
|
-
*
|
|
2131
|
-
* **Key Features**
|
|
2132
|
-
*
|
|
2133
|
-
* - **Path-based routing**: Match specific paths or patterns to proxy
|
|
2134
|
-
* - **Dynamic targets**: Support both static and dynamic target resolution
|
|
2135
|
-
* - **Request/Response hooks**: Modify requests before forwarding and responses after receiving
|
|
2136
|
-
* - **URL rewriting**: Transform URLs before forwarding to the target
|
|
2137
|
-
* - **Conditional proxying**: Enable/disable proxies based on environment or conditions
|
|
2138
|
-
*
|
|
2139
|
-
* @example
|
|
2140
|
-
* **Basic proxy setup:**
|
|
2141
|
-
* ```ts
|
|
2142
|
-
* import { $proxy } from "alepha/server/proxy";
|
|
2143
|
-
*
|
|
2144
|
-
* class ApiGateway {
|
|
2145
|
-
* // Forward all /api/* requests to external service
|
|
2146
|
-
* api = $proxy({
|
|
2147
|
-
* path: "/api/*",
|
|
2148
|
-
* target: "https://api.example.com"
|
|
2149
|
-
* });
|
|
2150
|
-
* }
|
|
2151
|
-
* ```
|
|
2152
|
-
*
|
|
2153
|
-
* @example
|
|
2154
|
-
* **Dynamic target with environment-based routing:**
|
|
2155
|
-
* ```ts
|
|
2156
|
-
* class ApiGateway {
|
|
2157
|
-
* // Route to different environments based on configuration
|
|
2158
|
-
* api = $proxy({
|
|
2159
|
-
* path: "/api/*",
|
|
2160
|
-
* target: () => process.env.NODE_ENV === "production"
|
|
2161
|
-
* ? "https://api.prod.example.com"
|
|
2162
|
-
* : "https://api.dev.example.com"
|
|
2163
|
-
* });
|
|
2164
|
-
* }
|
|
2165
|
-
* ```
|
|
2166
|
-
*
|
|
2167
|
-
* @example
|
|
2168
|
-
* **Advanced proxy with request/response modification:**
|
|
2169
|
-
* ```ts
|
|
2170
|
-
* class SecureProxy {
|
|
2171
|
-
* secure = $proxy({
|
|
2172
|
-
* path: "/secure/*",
|
|
2173
|
-
* target: "https://secure-api.example.com",
|
|
2174
|
-
* beforeRequest: async (request, proxyRequest) => {
|
|
2175
|
-
* // Add authentication headers
|
|
2176
|
-
* proxyRequest.headers = {
|
|
2177
|
-
* ...proxyRequest.headers,
|
|
2178
|
-
* 'Authorization': `Bearer ${await getServiceToken()}`,
|
|
2179
|
-
* 'X-Forwarded-For': request.headers['x-forwarded-for'] || request.ip
|
|
2180
|
-
* };
|
|
2181
|
-
* },
|
|
2182
|
-
* afterResponse: async (request, proxyResponse) => {
|
|
2183
|
-
* // Log response for monitoring
|
|
2184
|
-
* console.log(`Proxied ${request.url} -> ${proxyResponse.status}`);
|
|
2185
|
-
* },
|
|
2186
|
-
* rewrite: (url) => {
|
|
2187
|
-
* // Remove /secure prefix when forwarding
|
|
2188
|
-
* url.pathname = url.pathname.replace('/secure', '');
|
|
2189
|
-
* }
|
|
2190
|
-
* });
|
|
2191
|
-
* }
|
|
2192
|
-
* ```
|
|
2193
|
-
*
|
|
2194
|
-
* @example
|
|
2195
|
-
* **Conditional proxy based on feature flags:**
|
|
2196
|
-
* ```ts
|
|
2197
|
-
* class FeatureProxy {
|
|
2198
|
-
* newApi = $proxy({
|
|
2199
|
-
* path: "/v2/*",
|
|
2200
|
-
* target: "https://new-api.example.com",
|
|
2201
|
-
* disabled: !process.env.ENABLE_V2_API // Disable if feature flag is off
|
|
2202
|
-
* });
|
|
2203
|
-
* }
|
|
2204
|
-
* ```
|
|
2205
|
-
*/
|
|
2206
|
-
const $proxy = (options) => {
|
|
2207
|
-
return createDescriptor(ProxyDescriptor, options);
|
|
2208
|
-
};
|
|
2209
|
-
var ProxyDescriptor = class extends Descriptor {};
|
|
2210
|
-
$proxy[KIND] = ProxyDescriptor;
|
|
2211
|
-
|
|
2212
|
-
//#endregion
|
|
2213
|
-
//#region src/server-proxy/providers/ServerProxyProvider.ts
|
|
2214
|
-
var ServerProxyProvider = class {
|
|
2215
|
-
log = $logger();
|
|
2216
|
-
routerProvider = $inject(ServerRouterProvider);
|
|
2217
|
-
alepha = $inject(Alepha);
|
|
2218
|
-
configure = $hook({
|
|
2219
|
-
on: "configure",
|
|
2220
|
-
handler: () => {
|
|
2221
|
-
for (const proxy of this.alepha.descriptors($proxy)) this.createProxy(proxy.options);
|
|
2222
|
-
}
|
|
2223
|
-
});
|
|
2224
|
-
createProxy(options) {
|
|
2225
|
-
if (options.disabled) return;
|
|
2226
|
-
const path = options.path;
|
|
2227
|
-
const target = typeof options.target === "function" ? options.target() : options.target;
|
|
2228
|
-
if (!path.endsWith("/*")) throw new AlephaError("Proxy path should end with '/*'");
|
|
2229
|
-
const handler = this.createProxyHandler(target, options);
|
|
2230
|
-
for (const method of routeMethods) this.routerProvider.createRoute({
|
|
2231
|
-
method,
|
|
2232
|
-
path,
|
|
2233
|
-
handler
|
|
2234
|
-
});
|
|
2235
|
-
this.log.info("Proxying", {
|
|
2236
|
-
path,
|
|
2237
|
-
target
|
|
2238
|
-
});
|
|
2239
|
-
}
|
|
2240
|
-
createProxyHandler(target, options) {
|
|
2241
|
-
return async (request) => {
|
|
2242
|
-
const url = new URL(target + request.url.pathname);
|
|
2243
|
-
if (request.url.search) url.search = request.url.search;
|
|
2244
|
-
options.rewrite?.(url);
|
|
2245
|
-
const requestInit = {
|
|
2246
|
-
url: url.toString(),
|
|
2247
|
-
method: request.method,
|
|
2248
|
-
headers: {
|
|
2249
|
-
...request.headers,
|
|
2250
|
-
"accept-encoding": "identity"
|
|
2251
|
-
},
|
|
2252
|
-
body: this.getRawRequestBody(request)
|
|
2253
|
-
};
|
|
2254
|
-
if (requestInit.body) requestInit.duplex = "half";
|
|
2255
|
-
if (options.beforeRequest) await options.beforeRequest(request, requestInit);
|
|
2256
|
-
this.log.debug("Proxying request", {
|
|
2257
|
-
url: url.toString(),
|
|
2258
|
-
method: request.method,
|
|
2259
|
-
headers: request.headers
|
|
2260
|
-
});
|
|
2261
|
-
const response = await fetch(requestInit.url, requestInit);
|
|
2262
|
-
request.reply.status = response.status;
|
|
2263
|
-
request.reply.headers = Object.fromEntries(response.headers.entries());
|
|
2264
|
-
request.reply.body = response.body;
|
|
2265
|
-
this.log.debug("Received response", {
|
|
2266
|
-
status: request.reply.status,
|
|
2267
|
-
headers: request.reply.headers
|
|
2268
|
-
});
|
|
2269
|
-
if (options.afterResponse) await options.afterResponse(request, response);
|
|
2270
|
-
};
|
|
2271
|
-
}
|
|
2272
|
-
getRawRequestBody(req) {
|
|
2273
|
-
const { method } = req;
|
|
2274
|
-
if (method === "GET" || method === "HEAD" || method === "OPTIONS") return;
|
|
2275
|
-
if (req.raw?.web?.req) return req.raw.web.req.body;
|
|
2276
|
-
if (req.raw?.node?.req) {
|
|
2277
|
-
const nodeReq = req.raw.node.req;
|
|
2278
|
-
return ReadableStream.from(nodeReq);
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
};
|
|
2282
|
-
|
|
2283
|
-
//#endregion
|
|
2284
|
-
//#region src/server-proxy/index.ts
|
|
2285
|
-
/**
|
|
2286
|
-
* Plugin for Alepha that provides a proxy server functionality.
|
|
2287
|
-
*
|
|
2288
|
-
* @see {@link $proxy}
|
|
2289
|
-
* @module alepha.server.proxy
|
|
2290
|
-
*/
|
|
2291
|
-
const AlephaServerProxy = $module({
|
|
2292
|
-
name: "alepha.server.proxy",
|
|
2293
|
-
descriptors: [$proxy],
|
|
2294
|
-
services: [AlephaServer, ServerProxyProvider]
|
|
2295
|
-
});
|
|
2296
|
-
|
|
2297
|
-
//#endregion
|
|
2298
|
-
//#region src/server-links/providers/RemoteDescriptorProvider.ts
|
|
2299
|
-
const envSchema$1 = t.object({ SERVER_API_PREFIX: t.text({
|
|
2300
|
-
description: "Prefix for all API routes (e.g. $action).",
|
|
2301
|
-
default: "/api"
|
|
2302
|
-
}) });
|
|
2303
|
-
var RemoteDescriptorProvider = class {
|
|
2304
|
-
env = $env(envSchema$1);
|
|
2305
|
-
alepha = $inject(Alepha);
|
|
2306
|
-
proxyProvider = $inject(ServerProxyProvider);
|
|
2307
|
-
linkProvider = $inject(LinkProvider);
|
|
2308
|
-
remotes = [];
|
|
2309
|
-
log = $logger();
|
|
2310
|
-
getRemotes() {
|
|
2311
|
-
return this.remotes;
|
|
2312
|
-
}
|
|
2313
|
-
configure = $hook({
|
|
2314
|
-
on: "configure",
|
|
2315
|
-
handler: async () => {
|
|
2316
|
-
const remotes = this.alepha.descriptors($remote);
|
|
2317
|
-
for (const remote of remotes) await this.registerRemote(remote);
|
|
2318
|
-
}
|
|
2319
|
-
});
|
|
2320
|
-
start = $hook({
|
|
2321
|
-
on: "start",
|
|
2322
|
-
handler: async () => {
|
|
2323
|
-
for (const remote of this.remotes) {
|
|
2324
|
-
const token = typeof remote.serviceAccount?.token === "function" ? await remote.serviceAccount.token() : void 0;
|
|
2325
|
-
if (!remote.internal) continue;
|
|
2326
|
-
const { links } = await remote.links({ authorization: token });
|
|
2327
|
-
for (const link of links) {
|
|
2328
|
-
let path = link.path.replace(remote.prefix, "");
|
|
2329
|
-
if (link.service) path = `/${link.service}${path}`;
|
|
2330
|
-
this.linkProvider.registerLink({
|
|
2331
|
-
...link,
|
|
2332
|
-
prefix: remote.prefix,
|
|
2333
|
-
path,
|
|
2334
|
-
method: link.method ?? "GET",
|
|
2335
|
-
host: remote.url,
|
|
2336
|
-
service: remote.name
|
|
2337
|
-
});
|
|
2338
|
-
}
|
|
2339
|
-
this.log.info(`Remote '${remote.name}' OK`, {
|
|
2340
|
-
links: remote.links.length,
|
|
2341
|
-
prefix: remote.prefix
|
|
2342
|
-
});
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
});
|
|
2346
|
-
async registerRemote(value) {
|
|
2347
|
-
const options = value.options;
|
|
2348
|
-
const url = typeof options.url === "string" ? options.url : options.url();
|
|
2349
|
-
const linkPath = LinkProvider.path.apiLinks;
|
|
2350
|
-
const name = value.name;
|
|
2351
|
-
const proxy = typeof options.proxy === "object" ? options.proxy : {};
|
|
2352
|
-
const remote = {
|
|
2353
|
-
url,
|
|
2354
|
-
name,
|
|
2355
|
-
prefix: "/api",
|
|
2356
|
-
serviceAccount: options.serviceAccount,
|
|
2357
|
-
proxy: !!options.proxy,
|
|
2358
|
-
internal: !proxy.noInternal,
|
|
2359
|
-
schema: async (opts) => {
|
|
2360
|
-
const { authorization, name: name$1 } = opts;
|
|
2361
|
-
return await fetch(`${url}${linkPath}/${name$1}/schema`, { headers: new Headers(authorization ? { authorization } : {}) }).then((it) => it.json());
|
|
2362
|
-
},
|
|
2363
|
-
links: async (opts) => {
|
|
2364
|
-
const { authorization } = opts;
|
|
2365
|
-
const remoteApi = await this.fetchLinks.run({
|
|
2366
|
-
service: name,
|
|
2367
|
-
url: `${url}${linkPath}`,
|
|
2368
|
-
authorization
|
|
2369
|
-
});
|
|
2370
|
-
if (remoteApi.prefix != null) remote.prefix = remoteApi.prefix;
|
|
2371
|
-
return remoteApi;
|
|
2372
|
-
}
|
|
2373
|
-
};
|
|
2374
|
-
this.remotes.push(remote);
|
|
2375
|
-
if (options.proxy) this.proxyProvider.createProxy({
|
|
2376
|
-
path: `${this.env.SERVER_API_PREFIX}/${name}/*`,
|
|
2377
|
-
target: url,
|
|
2378
|
-
rewrite: (url$1) => {
|
|
2379
|
-
url$1.pathname = url$1.pathname.replace(`${this.env.SERVER_API_PREFIX}/${name}`, remote.prefix);
|
|
2380
|
-
},
|
|
2381
|
-
...proxy
|
|
2382
|
-
});
|
|
2383
|
-
}
|
|
2384
|
-
fetchLinks = $retry({
|
|
2385
|
-
max: 10,
|
|
2386
|
-
backoff: { initial: 1e3 },
|
|
2387
|
-
onError: (_, attempt, { service, url }) => {
|
|
2388
|
-
this.log.warn(`Failed to fetch links, retry (${attempt})...`, {
|
|
2389
|
-
service,
|
|
2390
|
-
url
|
|
2391
|
-
});
|
|
2392
|
-
},
|
|
2393
|
-
handler: async (opts) => {
|
|
2394
|
-
const { url, authorization } = opts;
|
|
2395
|
-
const response = await fetch(url, { headers: new Headers(authorization ? { authorization } : {}) });
|
|
2396
|
-
if (!response.ok) throw new Error(`Failed to fetch links from ${url}`);
|
|
2397
|
-
return this.alepha.codec.decode(apiLinksResponseSchema, await response.json());
|
|
2398
|
-
}
|
|
2399
|
-
});
|
|
2400
|
-
};
|
|
2401
|
-
|
|
2402
|
-
//#endregion
|
|
2403
|
-
//#region src/server-links/providers/ServerLinksProvider.ts
|
|
2404
|
-
const envSchema = t.object({ SERVER_API_PREFIX: t.text({
|
|
2405
|
-
description: "Prefix for all API routes (e.g. $action).",
|
|
2406
|
-
default: "/api"
|
|
2407
|
-
}) });
|
|
2408
|
-
var ServerLinksProvider = class {
|
|
2409
|
-
env = $env(envSchema);
|
|
2410
|
-
alepha = $inject(Alepha);
|
|
2411
|
-
linkProvider = $inject(LinkProvider);
|
|
2412
|
-
remoteProvider = $inject(RemoteDescriptorProvider);
|
|
2413
|
-
serverTimingProvider = $inject(ServerTimingProvider);
|
|
2414
|
-
get prefix() {
|
|
2415
|
-
return this.env.SERVER_API_PREFIX;
|
|
2416
|
-
}
|
|
2417
|
-
onRoute = $hook({
|
|
2418
|
-
on: "configure",
|
|
2419
|
-
handler: () => {
|
|
2420
|
-
for (const action of this.alepha.descriptors($action)) this.linkProvider.registerLink({
|
|
2421
|
-
name: action.name,
|
|
2422
|
-
group: action.group,
|
|
2423
|
-
schema: action.options.schema,
|
|
2424
|
-
requestBodyType: action.getBodyContentType(),
|
|
2425
|
-
secured: action.options.secure ?? true,
|
|
2426
|
-
method: action.method === "GET" ? void 0 : action.method,
|
|
2427
|
-
prefix: action.prefix,
|
|
2428
|
-
path: action.path,
|
|
2429
|
-
handler: (config, options = {}) => action.run(config, options)
|
|
2430
|
-
});
|
|
2431
|
-
}
|
|
2432
|
-
});
|
|
2433
|
-
/**
|
|
2434
|
-
* First API - Get all API links for the user.
|
|
2435
|
-
*
|
|
2436
|
-
* This is based on the user's permissions.
|
|
2437
|
-
*/
|
|
2438
|
-
links = $route({
|
|
2439
|
-
path: LinkProvider.path.apiLinks,
|
|
2440
|
-
schema: { response: apiLinksResponseSchema },
|
|
2441
|
-
handler: ({ user, headers: headers$1 }) => {
|
|
2442
|
-
return this.getUserApiLinks({
|
|
2443
|
-
user,
|
|
2444
|
-
authorization: headers$1.authorization
|
|
2445
|
-
});
|
|
2446
|
-
}
|
|
2447
|
-
});
|
|
2448
|
-
/**
|
|
2449
|
-
* Second API - Get schema for a specific API link.
|
|
2450
|
-
*
|
|
2451
|
-
* Note: Body/Response schema are not included in `links` API because it's TOO BIG.
|
|
2452
|
-
* I mean for 150+ links, you got 50ms of serialization time.
|
|
2453
|
-
*/
|
|
2454
|
-
schema = $route({
|
|
2455
|
-
path: LinkProvider.path.apiSchema,
|
|
2456
|
-
schema: {
|
|
2457
|
-
params: t.object({ name: t.text() }),
|
|
2458
|
-
response: t.json()
|
|
2459
|
-
},
|
|
2460
|
-
handler: ({ params, user, headers: headers$1 }) => {
|
|
2461
|
-
return this.getSchemaByName(params.name, {
|
|
2462
|
-
user,
|
|
2463
|
-
authorization: headers$1.authorization
|
|
2464
|
-
});
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
async getSchemaByName(name, options = {}) {
|
|
2468
|
-
const authorization = options.authorization;
|
|
2469
|
-
const api = await this.getUserApiLinks({
|
|
2470
|
-
user: options.user,
|
|
2471
|
-
authorization
|
|
2472
|
-
});
|
|
2473
|
-
for (const link of api.links) if (link.name === name) {
|
|
2474
|
-
if (link.service) return this.remoteProvider.getRemotes().find((it) => it.name === link.service)?.schema({
|
|
2475
|
-
name,
|
|
2476
|
-
authorization
|
|
2477
|
-
});
|
|
2478
|
-
return this.linkProvider.getServerLinks().find((it) => it.name === name)?.schema ?? {};
|
|
2479
|
-
}
|
|
2480
|
-
return {};
|
|
2481
|
-
}
|
|
2482
|
-
/**
|
|
2483
|
-
* Retrieves API links for the user based on their permissions.
|
|
2484
|
-
* Will check on local links and remote links.
|
|
2485
|
-
*/
|
|
2486
|
-
async getUserApiLinks(options) {
|
|
2487
|
-
const { user } = options;
|
|
2488
|
-
let permissions;
|
|
2489
|
-
let permissionMap;
|
|
2490
|
-
const hasSecurity = this.alepha.has(SecurityProvider);
|
|
2491
|
-
if (hasSecurity && user) {
|
|
2492
|
-
permissions = this.alepha.inject(SecurityProvider).getPermissions(user);
|
|
2493
|
-
permissionMap = new Map(permissions.map((it) => [`${it.group}:${it.name}`, it]));
|
|
2494
|
-
}
|
|
2495
|
-
const userLinks = [];
|
|
2496
|
-
for (const permission of permissions ?? []) if (!permission.path && !permission.method && permission.name && permission.group) userLinks.push({
|
|
2497
|
-
path: "",
|
|
2498
|
-
name: permission.name,
|
|
2499
|
-
group: permission.group
|
|
2500
|
-
});
|
|
2501
|
-
for (const link of this.linkProvider.getServerLinks()) {
|
|
2502
|
-
if (link.host) continue;
|
|
2503
|
-
if (hasSecurity && link.secured) {
|
|
2504
|
-
if (!user) continue;
|
|
2505
|
-
if (typeof link.secured === "object" && link.secured.realm) {
|
|
2506
|
-
if (user.realm !== link.secured.realm) continue;
|
|
2507
|
-
} else if (permissionMap) {
|
|
2508
|
-
if (!permissionMap.has(`${link.group}:${link.name}`)) continue;
|
|
2509
|
-
}
|
|
2510
|
-
}
|
|
2511
|
-
userLinks.push({
|
|
2512
|
-
name: link.name,
|
|
2513
|
-
group: link.group,
|
|
2514
|
-
requestBodyType: link.requestBodyType,
|
|
2515
|
-
method: link.method,
|
|
2516
|
-
path: link.path
|
|
2517
|
-
});
|
|
2518
|
-
}
|
|
2519
|
-
this.serverTimingProvider.beginTiming("fetchRemoteLinks");
|
|
2520
|
-
const promises = this.remoteProvider.getRemotes().filter((it) => it.proxy).map(async (remote) => {
|
|
2521
|
-
const { links, prefix } = await remote.links(options);
|
|
2522
|
-
return links.map((link) => {
|
|
2523
|
-
let path = link.path.replace(prefix ?? "/api", "");
|
|
2524
|
-
if (link.service) path = `/${link.service}${path}`;
|
|
2525
|
-
return {
|
|
2526
|
-
...link,
|
|
2527
|
-
path,
|
|
2528
|
-
proxy: true,
|
|
2529
|
-
service: remote.name
|
|
2530
|
-
};
|
|
2531
|
-
});
|
|
2532
|
-
});
|
|
2533
|
-
userLinks.push(...(await Promise.all(promises)).flat());
|
|
2534
|
-
this.serverTimingProvider.endTiming("fetchRemoteLinks");
|
|
2535
|
-
return {
|
|
2536
|
-
prefix: this.env.SERVER_API_PREFIX,
|
|
2537
|
-
links: userLinks
|
|
2538
|
-
};
|
|
2539
|
-
}
|
|
2540
|
-
};
|
|
2541
|
-
|
|
2542
|
-
//#endregion
|
|
2543
|
-
//#region src/server-links/index.ts
|
|
2544
|
-
/**
|
|
2545
|
-
* Provides server-side link management and remote capabilities for client-server interactions.
|
|
2546
|
-
*
|
|
2547
|
-
* The server-links module enables declarative link definitions using `$remote` and `$client` descriptors,
|
|
2548
|
-
* facilitating seamless API endpoint management and client-server communication. It integrates with server
|
|
2549
|
-
* security features to ensure safe and controlled access to resources.
|
|
2550
|
-
*
|
|
2551
|
-
* @see {@link $remote}
|
|
2552
|
-
* @see {@link $client}
|
|
2553
|
-
* @module alepha.server.links
|
|
2554
|
-
*/
|
|
2555
|
-
const AlephaServerLinks = $module({
|
|
2556
|
-
name: "alepha.server.links",
|
|
2557
|
-
descriptors: [$remote, $client],
|
|
2558
|
-
services: [
|
|
2559
|
-
AlephaServer,
|
|
2560
|
-
ServerLinksProvider,
|
|
2561
|
-
RemoteDescriptorProvider,
|
|
2562
|
-
LinkProvider
|
|
2563
|
-
]
|
|
2564
|
-
});
|
|
1372
|
+
$auth[KIND] = AuthPrimitive;
|
|
2565
1373
|
|
|
2566
1374
|
//#endregion
|
|
2567
1375
|
//#region src/server-auth/constants/routes.ts
|
|
@@ -2631,7 +1439,7 @@ var ServerAuthProvider = class {
|
|
|
2631
1439
|
schema: tokensSchema
|
|
2632
1440
|
});
|
|
2633
1441
|
get identities() {
|
|
2634
|
-
return this.alepha.
|
|
1442
|
+
return this.alepha.primitives($auth).filter((auth) => !auth.options.disabled);
|
|
2635
1443
|
}
|
|
2636
1444
|
getAuthenticationProviders(filters = {}) {
|
|
2637
1445
|
const providers = [];
|
|
@@ -2985,16 +1793,27 @@ var ServerAuthProvider = class {
|
|
|
2985
1793
|
};
|
|
2986
1794
|
|
|
2987
1795
|
//#endregion
|
|
2988
|
-
//#region src/server-auth/
|
|
1796
|
+
//#region src/server-auth/schemas/authenticationProviderSchema.ts
|
|
1797
|
+
const authenticationProviderSchema = t.object({
|
|
1798
|
+
name: t.text({ description: "Name of the authentication provider." }),
|
|
1799
|
+
type: t.enum([
|
|
1800
|
+
"OAUTH2",
|
|
1801
|
+
"OIDC",
|
|
1802
|
+
"CREDENTIALS"
|
|
1803
|
+
], { description: "Type of the authentication provider." })
|
|
1804
|
+
}, { title: "AuthenticationProvider" });
|
|
1805
|
+
|
|
1806
|
+
//#endregion
|
|
1807
|
+
//#region src/server-auth/primitives/$authCredentials.ts
|
|
2989
1808
|
/**
|
|
2990
|
-
* Already configured Credentials authentication
|
|
1809
|
+
* Already configured Credentials authentication primitive.
|
|
2991
1810
|
*
|
|
2992
1811
|
* Uses username and password to authenticate users.
|
|
2993
1812
|
*/
|
|
2994
1813
|
const $authCredentials = (realm, options = {}) => {
|
|
2995
1814
|
const name = "credentials";
|
|
2996
1815
|
const account = realm.login ? realm.login(name) : options.account;
|
|
2997
|
-
if (!account) throw new AlephaError("Credentials authentication requires a login function in the realm
|
|
1816
|
+
if (!account) throw new AlephaError("Credentials authentication requires a login function in the realm primitive.");
|
|
2998
1817
|
return $auth({
|
|
2999
1818
|
realm,
|
|
3000
1819
|
name,
|
|
@@ -3003,9 +1822,9 @@ const $authCredentials = (realm, options = {}) => {
|
|
|
3003
1822
|
};
|
|
3004
1823
|
|
|
3005
1824
|
//#endregion
|
|
3006
|
-
//#region src/server-auth/
|
|
1825
|
+
//#region src/server-auth/primitives/$authGithub.ts
|
|
3007
1826
|
/**
|
|
3008
|
-
* Already configured GitHub authentication
|
|
1827
|
+
* Already configured GitHub authentication primitive.
|
|
3009
1828
|
*
|
|
3010
1829
|
* Uses OAuth2 to authenticate users via their GitHub accounts.
|
|
3011
1830
|
* Upon successful authentication, it links the GitHub account to a user session.
|
|
@@ -3023,7 +1842,7 @@ const $authGithub = (realm, options = {}) => {
|
|
|
3023
1842
|
const disabled = !env.GITHUB_CLIENT_ID || !env.GITHUB_CLIENT_SECRET;
|
|
3024
1843
|
const name = "github";
|
|
3025
1844
|
const account = options.account ?? (realm.link ? realm.link(name) : void 0);
|
|
3026
|
-
if (!account) throw new AlephaError("Authentication requires a link function in the realm
|
|
1845
|
+
if (!account) throw new AlephaError("Authentication requires a link function in the realm primitive.");
|
|
3027
1846
|
return $auth({
|
|
3028
1847
|
realm,
|
|
3029
1848
|
name,
|
|
@@ -3063,9 +1882,9 @@ const $authGithub = (realm, options = {}) => {
|
|
|
3063
1882
|
};
|
|
3064
1883
|
|
|
3065
1884
|
//#endregion
|
|
3066
|
-
//#region src/server-auth/
|
|
1885
|
+
//#region src/server-auth/primitives/$authGoogle.ts
|
|
3067
1886
|
/**
|
|
3068
|
-
* Already configured Google authentication
|
|
1887
|
+
* Already configured Google authentication primitive.
|
|
3069
1888
|
*
|
|
3070
1889
|
* Uses OpenID Connect (OIDC) to authenticate users via their Google accounts.
|
|
3071
1890
|
* Upon successful authentication, it links the Google account to a user session.
|
|
@@ -3083,7 +1902,7 @@ const $authGoogle = (realm, options = {}) => {
|
|
|
3083
1902
|
const disabled = !env.GOOGLE_CLIENT_ID || !env.GOOGLE_CLIENT_SECRET;
|
|
3084
1903
|
const name = "google";
|
|
3085
1904
|
const account = options.account ?? (realm.link ? realm.link(name) : void 0);
|
|
3086
|
-
if (!account) throw new AlephaError("Authentication requires a link function in the realm
|
|
1905
|
+
if (!account) throw new AlephaError("Authentication requires a link function in the realm primitive.");
|
|
3087
1906
|
return $auth({
|
|
3088
1907
|
realm,
|
|
3089
1908
|
name,
|
|
@@ -3098,17 +1917,6 @@ const $authGoogle = (realm, options = {}) => {
|
|
|
3098
1917
|
});
|
|
3099
1918
|
};
|
|
3100
1919
|
|
|
3101
|
-
//#endregion
|
|
3102
|
-
//#region src/server-auth/schemas/authenticationProviderSchema.ts
|
|
3103
|
-
const authenticationProviderSchema = t.object({
|
|
3104
|
-
name: t.text({ description: "Name of the authentication provider." }),
|
|
3105
|
-
type: t.enum([
|
|
3106
|
-
"OAUTH2",
|
|
3107
|
-
"OIDC",
|
|
3108
|
-
"CREDENTIALS"
|
|
3109
|
-
], { description: "Type of the authentication provider." })
|
|
3110
|
-
}, { title: "AuthenticationProvider" });
|
|
3111
|
-
|
|
3112
1920
|
//#endregion
|
|
3113
1921
|
//#region src/server-auth/index.ts
|
|
3114
1922
|
/**
|
|
@@ -3126,10 +1934,10 @@ const authenticationProviderSchema = t.object({
|
|
|
3126
1934
|
*/
|
|
3127
1935
|
const AlephaServerAuth = $module({
|
|
3128
1936
|
name: "alepha.server.auth",
|
|
3129
|
-
|
|
1937
|
+
primitives: [$auth],
|
|
3130
1938
|
services: [AlephaServerCookies, ServerAuthProvider]
|
|
3131
1939
|
});
|
|
3132
1940
|
|
|
3133
1941
|
//#endregion
|
|
3134
|
-
export { $auth, $authCredentials, $authGithub, $authGoogle, AlephaServerAuth,
|
|
1942
|
+
export { $auth, $authCredentials, $authGithub, $authGoogle, AlephaServerAuth, AuthPrimitive, ServerAuthProvider, alephaServerAuthRoutes, authenticationProviderSchema, tokenResponseSchema, tokensSchema, userinfoResponseSchema };
|
|
3135
1943
|
//# sourceMappingURL=index.js.map
|