@webda/azure 0.0.0-stage → 4.0.0-beta.13

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.
Files changed (68) hide show
  1. package/LICENSE +166 -0
  2. package/README.md +248 -2
  3. package/lib/auth.d.ts +30 -0
  4. package/lib/auth.d.ts.map +1 -0
  5. package/lib/auth.js +70 -0
  6. package/lib/auth.js.map +1 -0
  7. package/lib/deployers/arm.service.d.ts +108 -0
  8. package/lib/deployers/arm.service.d.ts.map +1 -0
  9. package/lib/deployers/arm.service.js +280 -0
  10. package/lib/deployers/arm.service.js.map +1 -0
  11. package/lib/deployers/containerapps.service.d.ts +156 -0
  12. package/lib/deployers/containerapps.service.d.ts.map +1 -0
  13. package/lib/deployers/containerapps.service.js +455 -0
  14. package/lib/deployers/containerapps.service.js.map +1 -0
  15. package/lib/deployers/functions-entrypoint.d.ts +48 -0
  16. package/lib/deployers/functions-entrypoint.d.ts.map +1 -0
  17. package/lib/deployers/functions-entrypoint.js +78 -0
  18. package/lib/deployers/functions-entrypoint.js.map +1 -0
  19. package/lib/deployers/functions.service.d.ts +66 -0
  20. package/lib/deployers/functions.service.d.ts.map +1 -0
  21. package/lib/deployers/functions.service.js +322 -0
  22. package/lib/deployers/functions.service.js.map +1 -0
  23. package/lib/deployers/functionspackager.service.d.ts +43 -0
  24. package/lib/deployers/functionspackager.service.d.ts.map +1 -0
  25. package/lib/deployers/functionspackager.service.js +151 -0
  26. package/lib/deployers/functionspackager.service.js.map +1 -0
  27. package/lib/index.d.ts +15 -0
  28. package/lib/index.d.ts.map +1 -0
  29. package/lib/index.js +18 -0
  30. package/lib/index.js.map +1 -0
  31. package/lib/services/azure-parameters.d.ts +41 -0
  32. package/lib/services/azure-parameters.d.ts.map +1 -0
  33. package/lib/services/azure-parameters.js +43 -0
  34. package/lib/services/azure-parameters.js.map +1 -0
  35. package/lib/services/blob.service.d.ts +157 -0
  36. package/lib/services/blob.service.d.ts.map +1 -0
  37. package/lib/services/blob.service.js +428 -0
  38. package/lib/services/blob.service.js.map +1 -0
  39. package/lib/services/contributors.d.ts +47 -0
  40. package/lib/services/contributors.d.ts.map +1 -0
  41. package/lib/services/contributors.js +2 -0
  42. package/lib/services/contributors.js.map +1 -0
  43. package/lib/services/cosmos.service.d.ts +211 -0
  44. package/lib/services/cosmos.service.d.ts.map +1 -0
  45. package/lib/services/cosmos.service.js +554 -0
  46. package/lib/services/cosmos.service.js.map +1 -0
  47. package/lib/services/functionserver.service.d.ts +42 -0
  48. package/lib/services/functionserver.service.d.ts.map +1 -0
  49. package/lib/services/functionserver.service.js +223 -0
  50. package/lib/services/functionserver.service.js.map +1 -0
  51. package/lib/services/keyvault.service.d.ts +91 -0
  52. package/lib/services/keyvault.service.d.ts.map +1 -0
  53. package/lib/services/keyvault.service.js +225 -0
  54. package/lib/services/keyvault.service.js.map +1 -0
  55. package/lib/services/monitorlogger.service.d.ts +66 -0
  56. package/lib/services/monitorlogger.service.d.ts.map +1 -0
  57. package/lib/services/monitorlogger.service.js +131 -0
  58. package/lib/services/monitorlogger.service.js.map +1 -0
  59. package/lib/services/servicebus.service.d.ts +128 -0
  60. package/lib/services/servicebus.service.d.ts.map +1 -0
  61. package/lib/services/servicebus.service.js +324 -0
  62. package/lib/services/servicebus.service.js.map +1 -0
  63. package/lib/template.d.ts +53 -0
  64. package/lib/template.d.ts.map +1 -0
  65. package/lib/template.js +74 -0
  66. package/lib/template.js.map +1 -0
  67. package/package.json +77 -3
  68. package/webda.module.json +1817 -0
@@ -0,0 +1,223 @@
1
+ import { isIP } from "node:net";
2
+ import { Writable } from "node:stream";
3
+ import { useLog } from "@webda/workout";
4
+ import { CronService, emitCoreEvent, HttpContext, runWithContext, Service, ServiceParameters, traceRequest, useCore, useRouter, WebContext, WebdaError } from "@webda/core";
5
+ /** Azure Functions HTTP adapter settings. */
6
+ export class AzureFunctionServerParameters extends ServiceParameters {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.requestIdHeader = "x-request-id";
10
+ }
11
+ }
12
+ /** Collect bytes directly, preserving binary responses from write() and streaming routes. */
13
+ class AzureFunctionContext extends WebContext {
14
+ /**
15
+ * Initialize the Azure integration.
16
+ * @param http - HTTP request context
17
+ */
18
+ constructor(http) {
19
+ const chunks = [];
20
+ super(http, new Writable({
21
+ /**
22
+ * Perform write.
23
+ * @override
24
+ */
25
+ write(chunk, _encoding, callback) {
26
+ chunks.push(Buffer.from(chunk));
27
+ callback();
28
+ }
29
+ }));
30
+ this.savedHeaders = {};
31
+ this.chunks = chunks;
32
+ }
33
+ /**
34
+ * Perform write.
35
+ * @override
36
+ */
37
+ write(output, encoding, callback) {
38
+ if (Buffer.isBuffer(output)) {
39
+ if (this.statusCode === 204)
40
+ this.statusCode = 200;
41
+ return this._stream.write(output);
42
+ }
43
+ const result = super.write(output, encoding, callback);
44
+ if (this._body !== undefined) {
45
+ this._stream.write(this._body);
46
+ this._body = undefined;
47
+ }
48
+ return result;
49
+ }
50
+ /**
51
+ * Perform reset response.
52
+ * @override
53
+ */
54
+ resetResponse() {
55
+ super.resetResponse();
56
+ this.chunks.length = 0;
57
+ this.savedHeaders = {};
58
+ }
59
+ /** Retain headers flushed by streaming routes until the Functions response is returned.
60
+ * @override
61
+ */
62
+ getResponseHeaders() {
63
+ return (this.savedHeaders = { ...this.savedHeaders, ...super.getResponseHeaders() });
64
+ }
65
+ }
66
+ /** Run Webda routes and event handlers inside the Azure Functions v4 runtime.
67
+ * @WebdaModda
68
+ */
69
+ export class AzureFunctionServer extends Service {
70
+ /**
71
+ * Execute an Azure HTTP request through the Webda router.
72
+ * @param request - Azure Functions HTTP request
73
+ * @param invocation - Azure invocation metadata
74
+ * @returns The handle request result
75
+ */
76
+ async handleRequest(request, invocation) {
77
+ const url = new URL(request.url), headers = Object.fromEntries(request.headers.entries());
78
+ const clientIp = this.getClientIp(headers);
79
+ const http = new HttpContext(url.host, request.method, url.pathname + url.search, url.protocol === "http:" ? "http" : "https", Number(url.port || (url.protocol === "http:" ? 80 : 443)), headers).setClientIp(clientIp || "");
80
+ if (!["GET", "HEAD"].includes(request.method))
81
+ http.setBody(Buffer.from(await request.arrayBuffer()));
82
+ const context = new AzureFunctionContext(http);
83
+ await context.init();
84
+ await emitCoreEvent("Webda.NewContext", { context, info: { http } });
85
+ return traceRequest({
86
+ protocol: "http",
87
+ method: request.method,
88
+ path: url.pathname,
89
+ scheme: url.protocol === "http:" ? "http" : "https",
90
+ headers: Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v])),
91
+ clientIp
92
+ }, async (handle) => {
93
+ const result = await runWithContext(context, async () => {
94
+ try {
95
+ await emitCoreEvent("Webda.Request", { context });
96
+ if (this.parameters.requestIdHeader)
97
+ context.setHeader(this.parameters.requestIdHeader, invocation.invocationId);
98
+ const origin = headers.origin;
99
+ if (origin) {
100
+ if (!(await useRouter()["checkCORSRequest"](context))) {
101
+ // No Access-Control-* for a refused origin, but the answer still depends on it
102
+ context.setHeader("Vary", "Origin");
103
+ throw new WebdaError.Unauthorized("Origin not allowed");
104
+ }
105
+ // Access-Control-Allow-Origin/-Credentials are set by the Router
106
+ }
107
+ if (url.protocol === "https:")
108
+ context.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
109
+ await useRouter().execute(context);
110
+ }
111
+ catch (error) {
112
+ if (error instanceof WebdaError.HttpError) {
113
+ context.statusCode = error.getResponseCode();
114
+ if (error instanceof WebdaError.Redirect)
115
+ context.setHeader("Location", error.location);
116
+ }
117
+ else if (typeof error === "number")
118
+ context.statusCode = error;
119
+ else {
120
+ context.statusCode = 500;
121
+ this.log("ERROR", "Azure Function request failed");
122
+ }
123
+ }
124
+ await emitCoreEvent("Webda.Result", { context });
125
+ const responseHeaders = { ...context.getResponseHeaders() };
126
+ await context.end();
127
+ const merged = { ...responseHeaders, ...context.getResponseHeaders() };
128
+ const resultHeaders = Object.fromEntries(Object.entries(merged)
129
+ .filter(([name, value]) => value !== undefined &&
130
+ (name.toLowerCase() !== "set-cookie" || !Object.keys(context.getResponseCookies() ?? {}).length))
131
+ .map(([key, value]) => [key, Array.isArray(value) ? value.join(", ") : String(value)]));
132
+ const cookies = Object.values(context.getResponseCookies() ?? {}).map(cookie => {
133
+ const options = cookie.options ?? {};
134
+ const sameSite = options.sameSite === true ? "strict" : options.sameSite;
135
+ return {
136
+ name: cookie.name,
137
+ value: cookie.value,
138
+ domain: options.domain,
139
+ path: options.path,
140
+ secure: options.secure,
141
+ httpOnly: options.httpOnly,
142
+ expires: options.expires,
143
+ maxAge: options.maxAge,
144
+ sameSite: typeof sameSite === "string"
145
+ ? (sameSite[0].toUpperCase() + sameSite.slice(1).toLowerCase())
146
+ : undefined
147
+ };
148
+ });
149
+ const body = Buffer.concat(context.chunks);
150
+ return {
151
+ status: context.getResponseCode(),
152
+ headers: resultHeaders,
153
+ cookies,
154
+ body: request.method === "HEAD" || body.length === 0 ? undefined : body
155
+ };
156
+ });
157
+ try {
158
+ handle.setStatus(result.status);
159
+ }
160
+ catch (err) {
161
+ useLog("WARN", "Request tracer failed to record the status", err);
162
+ }
163
+ return result;
164
+ });
165
+ }
166
+ /**
167
+ * Resolve the client address from the rightmost X-Forwarded-For entry, without any port. Never throws.
168
+ * @param headers - the request headers
169
+ * @returns the address, undefined if unknown or invalid
170
+ */
171
+ getClientIp(headers) {
172
+ try {
173
+ let last = Object.entries(headers)
174
+ .find(([name]) => name.toLowerCase() === "x-forwarded-for")?.[1]
175
+ ?.split(",")
176
+ .pop()
177
+ ?.trim();
178
+ if (!last)
179
+ return undefined;
180
+ // [v6]:port, v4:port (a bare v6 contains several colons and is kept as is)
181
+ const bracketed = last.match(/^\[([^\]]+)\](?::\d+)?$/);
182
+ if (bracketed)
183
+ last = bracketed[1];
184
+ else if (last.split(":").length === 2)
185
+ last = last.split(":")[0];
186
+ return isIP(last) ? last : undefined;
187
+ }
188
+ catch (err) {
189
+ useLog("WARN", "Cannot resolve the client address", err);
190
+ return undefined;
191
+ }
192
+ }
193
+ /**
194
+ * Dispatch an Azure binding event to configured handler services.
195
+ * @param source - Azure binding event source
196
+ * @param event - Received event payload
197
+ * @param context - Webda or Azure invocation context
198
+ */
199
+ async handleEvent(source, event, context) {
200
+ let handled = false;
201
+ for (const service of Object.values(useCore().getServices())) {
202
+ if (typeof service.handleAzureEvent === "function") {
203
+ handled =
204
+ (await service.handleAzureEvent(source, event, context)) || handled;
205
+ }
206
+ }
207
+ if (!handled)
208
+ throw new WebdaError.NotImplemented(`No Azure ${source} event handler is configured`);
209
+ }
210
+ /**
211
+ * Execute only the declared cron matching the exported identifier, through its operation
212
+ * @param id - Secret name or exported cron identifier
213
+ */
214
+ async handleCron(id) {
215
+ const crons = CronService.resolveCrons().filter(cron => CronService.getExportId(cron) === id);
216
+ if (!crons.length)
217
+ throw new WebdaError.NotFound("Azure timer does not match a declared Webda cron");
218
+ for (const cron of crons)
219
+ await CronService.execute(cron, true);
220
+ }
221
+ }
222
+ AzureFunctionServer.Parameters = AzureFunctionServerParameters;
223
+ //# sourceMappingURL=functionserver.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functionserver.service.js","sources":["../../src/services/functionserver.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { SecretClient } from "@azure/keyvault-secrets";
2
+ import { ConfigurationProvider, SecretString, Service } from "@webda/core";
3
+ import { AzureParameters, AzureServiceParameters } from "./azure-parameters.js";
4
+ import { AzureContributor, AzureDeployerInfo, AzureResourceContribution } from "./contributors.js";
5
+ /** Settings for the Key Vault service and configuration encrypter. */
6
+ export declare class AzureKeyVaultParameters extends AzureParameters {
7
+ vaultUrl: string;
8
+ keyId?: string;
9
+ }
10
+ type AzureEncryptionOptions = AzureServiceParameters & {
11
+ keyId?: string;
12
+ };
13
+ /** Authenticated envelope encryption: only the random AES key leaves this process. */
14
+ export declare const azureEncrypter: {
15
+ /** Configure the encryption pass before application services are created.
16
+ * @param options - Azure credential and key settings for this configuration pass
17
+ */
18
+ configure(options: AzureEncryptionOptions): void;
19
+ /**
20
+ * Encrypt a configuration value with a wrapped AES key.
21
+ * @param data - Model data or encrypted envelope
22
+ * @param options - Encryption or packaging options
23
+ * @returns The encrypt result
24
+ */
25
+ encrypt(data: string, options?: string | AzureEncryptionOptions): Promise<string>;
26
+ /**
27
+ * Decrypt and authenticate an Azure envelope.
28
+ * @param data - Model data or encrypted envelope
29
+ * @param params - Raw configuration parameters
30
+ * @returns The decrypt result
31
+ */
32
+ decrypt(data: string, params?: AzureServiceParameters): Promise<string>;
33
+ };
34
+ /** Key Vault secrets as a configuration source, with Key Vault envelope encryption.
35
+ * @WebdaModda
36
+ */
37
+ export declare class AzureKeyVault extends Service<AzureKeyVaultParameters> implements ConfigurationProvider, AzureContributor {
38
+ static Parameters: typeof AzureKeyVaultParameters;
39
+ protected client: SecretClient;
40
+ /**
41
+ * Perform init.
42
+ * @override
43
+ */
44
+ init(): Promise<this>;
45
+ /**
46
+ * Key Vault has no push-based configuration subscription; ConfigurationService polls.
47
+ * @param _id - Configuration source identifier
48
+ * @param _callback - Unused configuration change callback
49
+ * @returns The can trigger configuration result
50
+ */
51
+ canTriggerConfiguration(_id: string, _callback: () => void): boolean;
52
+ /**
53
+ * Retrieve a secret without exposing its value to JSON or logs.
54
+ * @param id - Secret name or exported cron identifier
55
+ * @returns Masked secret value
56
+ */
57
+ getSecret(id: string): Promise<SecretString>;
58
+ /**
59
+ * Load a JSON configuration document. Secret fields can use crypt:azure: values.
60
+ * @param id - Secret name or exported cron identifier
61
+ * @returns Resolved configuration object
62
+ */
63
+ getConfiguration(id: string): Promise<Record<string, any>>;
64
+ /**
65
+ * Resolve whole-value ${keyvault:secret-name} references in a configuration document.
66
+ * @param configuration - Configuration tree to resolve
67
+ * @returns Configuration with secret references resolved
68
+ */
69
+ resolveReferences<T>(configuration: T): Promise<T>;
70
+ /**
71
+ * Encrypt a configuration value with a wrapped AES key.
72
+ * @param data - Model data or encrypted envelope
73
+ * @param keyId - key id
74
+ * @returns The encrypt result
75
+ */
76
+ encrypt(data: string, keyId?: string | undefined): Promise<string>;
77
+ /**
78
+ * Decrypt and authenticate an Azure envelope.
79
+ * @param data - Model data or encrypted envelope
80
+ * @returns The decrypt result
81
+ */
82
+ decrypt(data: string): Promise<SecretString>;
83
+ /**
84
+ * Describe the Azure resources and identity permissions required by this service.
85
+ * @param deployer - Deployment scope and identity helpers
86
+ * @returns The azure resources result
87
+ */
88
+ getAzureResources(deployer: AzureDeployerInfo): AzureResourceContribution;
89
+ }
90
+ export {};
91
+ //# sourceMappingURL=keyvault.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyvault.service.d.ts","sources":["../../src/services/keyvault.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAiB,YAAY,EAAE,OAAO,EAAc,MAAM,aAAa,CAAC;AAEtG,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAsB,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAEnG,sEAAsE;AACtE,qBAAa,uBAAwB,SAAQ,eAAe;IAC1D,QAAQ,EAAG,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,KAAK,sBAAsB,GAAG,sBAAsB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAmB1E,sFAAsF;AACtF,eAAO,MAAM,cAAc;IACzB;;OAEG;IACH,SAAS,UAAU,sBAAsB,GAAG,IAAI;IAGhD;;;;;OAKG;IACG,OAAO,OAAO,MAAM,YAAW,MAAM,GAAG,sBAAsB,GAA0B,OAAO,CAAC,MAAM,CAAC;IA8B7G;;;;;OAKG;IACG,OAAO,OAAO,MAAM,WAAU,sBAAsB,GAA0B,OAAO,CAAC,MAAM,CAAC;CAiCpG,CAAC;AAIF;;GAEG;AACH,qBAAa,aAAc,SAAQ,OAAO,CAAC,uBAAuB,CAAE,YAAW,qBAAqB,EAAE,gBAAgB;IACpH,MAAM,CAAC,UAAU,iCAA2B;IAC5C,SAAS,CAAC,MAAM,EAAG,YAAY,CAAC;IAEhC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAI1B;IAED;;;;;OAKG;IACH,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAEnE;IAED;;;;OAIG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAWjD;IAED;;;;OAIG;IACG,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAY/D;IAED;;;;OAIG;IACG,iBAAiB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAevD;IAED;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,qBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;IAED;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAEjD;IAED;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,yBAAyB,CASxE;CACF"}
@@ -0,0 +1,225 @@
1
+ import { CryptographyClient } from "@azure/keyvault-keys";
2
+ import { SecretClient } from "@azure/keyvault-secrets";
3
+ import { CryptoService, SecretString, Service, WebdaError } from "@webda/core";
4
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
5
+ import { AzureParameters, getAzureCredential } from "./azure-parameters.js";
6
+ /** Settings for the Key Vault service and configuration encrypter. */
7
+ export class AzureKeyVaultParameters extends AzureParameters {
8
+ }
9
+ let configuredEncryption = {};
10
+ /**
11
+ * Validate key identifiers before sending credentials or wrapped keys to their endpoints.
12
+ * @param keyId - key id
13
+ * @returns The validate key id result
14
+ */
15
+ function validateKeyId(keyId) {
16
+ if (!/^https:\/\/[a-zA-Z0-9-]+\.vault\.(?:azure\.net|azure\.cn|usgovcloudapi\.net)\/keys\/[a-zA-Z0-9-]+(?:\/[a-zA-Z0-9-]+)?$/.test(keyId)) {
17
+ throw new WebdaError.CodeError("AZURE_KEY_ID", "A full Azure Key Vault key URL is required");
18
+ }
19
+ return keyId;
20
+ }
21
+ /** Authenticated envelope encryption: only the random AES key leaves this process. */
22
+ export const azureEncrypter = {
23
+ /** Configure the encryption pass before application services are created.
24
+ * @param options - Azure credential and key settings for this configuration pass
25
+ */
26
+ configure(options) {
27
+ configuredEncryption = { ...options };
28
+ },
29
+ /**
30
+ * Encrypt a configuration value with a wrapped AES key.
31
+ * @param data - Model data or encrypted envelope
32
+ * @param options - Encryption or packaging options
33
+ * @returns The encrypt result
34
+ */
35
+ async encrypt(data, options = configuredEncryption) {
36
+ const params = typeof options === "string" ? { keyId: options } : options;
37
+ const keyId = validateKeyId(params.keyId ?? process.env.WEBDA_AZURE_KEY_ID ?? "");
38
+ const key = randomBytes(32);
39
+ try {
40
+ const client = new CryptographyClient(keyId, getAzureCredential(params));
41
+ const wrapped = await client.wrapKey("RSA-OAEP-256", key);
42
+ // Pin the actual key version so rotating the vault key does not break existing values.
43
+ const resolvedKeyId = validateKeyId(wrapped.keyID ?? keyId);
44
+ if (new URL(resolvedKeyId).origin !== new URL(keyId).origin || resolvedKeyId.split("/").length !== 6) {
45
+ throw new WebdaError.CodeError("AZURE_KEY_VERSION", "Key Vault must return a versioned key identifier");
46
+ }
47
+ const iv = randomBytes(12);
48
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
49
+ cipher.setAAD(Buffer.from(`1:${resolvedKeyId}`));
50
+ const ciphertext = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
51
+ const envelope = {
52
+ version: 1,
53
+ keyId: resolvedKeyId,
54
+ wrappedKey: Buffer.from(wrapped.result).toString("base64url"),
55
+ iv: iv.toString("base64url"),
56
+ tag: cipher.getAuthTag().toString("base64url"),
57
+ ciphertext: ciphertext.toString("base64url")
58
+ };
59
+ return Buffer.from(JSON.stringify(envelope)).toString("base64url");
60
+ }
61
+ finally {
62
+ key.fill(0);
63
+ }
64
+ },
65
+ /**
66
+ * Decrypt and authenticate an Azure envelope.
67
+ * @param data - Model data or encrypted envelope
68
+ * @param params - Raw configuration parameters
69
+ * @returns The decrypt result
70
+ */
71
+ async decrypt(data, params = configuredEncryption) {
72
+ let key;
73
+ try {
74
+ const envelope = JSON.parse(Buffer.from(data, "base64url").toString());
75
+ if (envelope.version !== 1)
76
+ throw new Error();
77
+ validateKeyId(envelope.keyId);
78
+ const decode = (value, size) => {
79
+ if (typeof value !== "string" || !/^[\w-]*$/.test(value))
80
+ throw new Error();
81
+ const bytes = Buffer.from(value, "base64url");
82
+ if (bytes.toString("base64url") !== value || (size !== undefined && bytes.length !== size))
83
+ throw new Error();
84
+ return bytes;
85
+ };
86
+ const iv = decode(envelope.iv, 12), tag = decode(envelope.tag, 16);
87
+ const ciphertext = decode(envelope.ciphertext), wrappedKey = decode(envelope.wrappedKey);
88
+ if (!wrappedKey.length || envelope.keyId.split("/").length !== 6)
89
+ throw new Error();
90
+ const client = new CryptographyClient(envelope.keyId, getAzureCredential(params));
91
+ const unwrapped = await client.unwrapKey("RSA-OAEP-256", wrappedKey);
92
+ key = Buffer.from(unwrapped.result);
93
+ unwrapped.result.fill(0);
94
+ if (key.length !== 32)
95
+ throw new Error();
96
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
97
+ decipher.setAAD(Buffer.from(`1:${envelope.keyId}`));
98
+ decipher.setAuthTag(tag);
99
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
100
+ }
101
+ catch {
102
+ // SDK exceptions can contain requests; never expose them with configuration secrets.
103
+ throw new WebdaError.CodeError("AZURE_DECRYPT_FAILED", "Unable to decrypt Azure configuration value");
104
+ }
105
+ finally {
106
+ key?.fill(0);
107
+ }
108
+ }
109
+ };
110
+ CryptoService.registerEncrypter("azure", azureEncrypter);
111
+ /** Key Vault secrets as a configuration source, with Key Vault envelope encryption.
112
+ * @WebdaModda
113
+ */
114
+ export class AzureKeyVault extends Service {
115
+ /**
116
+ * Perform init.
117
+ * @override
118
+ */
119
+ async init() {
120
+ await super.init();
121
+ this.client = new SecretClient(this.parameters.vaultUrl, getAzureCredential(this.parameters));
122
+ return this;
123
+ }
124
+ /**
125
+ * Key Vault has no push-based configuration subscription; ConfigurationService polls.
126
+ * @param _id - Configuration source identifier
127
+ * @param _callback - Unused configuration change callback
128
+ * @returns The can trigger configuration result
129
+ */
130
+ canTriggerConfiguration(_id, _callback) {
131
+ return false;
132
+ }
133
+ /**
134
+ * Retrieve a secret without exposing its value to JSON or logs.
135
+ * @param id - Secret name or exported cron identifier
136
+ * @returns Masked secret value
137
+ */
138
+ async getSecret(id) {
139
+ let secret;
140
+ try {
141
+ secret = await this.client.getSecret(id);
142
+ }
143
+ catch (error) {
144
+ if (error.statusCode === 404)
145
+ throw new WebdaError.NotFound("Key Vault secret was not found");
146
+ throw new WebdaError.ServiceUnavailable("Unable to retrieve Key Vault secret");
147
+ }
148
+ if (secret.value === undefined)
149
+ throw new WebdaError.NotFound("Key Vault secret has no value");
150
+ return new SecretString(secret.value, "azure");
151
+ }
152
+ /**
153
+ * Load a JSON configuration document. Secret fields can use crypt:azure: values.
154
+ * @param id - Secret name or exported cron identifier
155
+ * @returns Resolved configuration object
156
+ */
157
+ async getConfiguration(id) {
158
+ const value = await this.getSecret(id);
159
+ let configuration;
160
+ try {
161
+ configuration = JSON.parse(value.getValue());
162
+ }
163
+ catch {
164
+ throw new WebdaError.BadRequest("Key Vault configuration must be a JSON object");
165
+ }
166
+ if (!configuration || typeof configuration !== "object" || Array.isArray(configuration)) {
167
+ throw new WebdaError.BadRequest("Key Vault configuration must be a JSON object");
168
+ }
169
+ return this.resolveReferences(configuration);
170
+ }
171
+ /**
172
+ * Resolve whole-value ${keyvault:secret-name} references in a configuration document.
173
+ * @param configuration - Configuration tree to resolve
174
+ * @returns Configuration with secret references resolved
175
+ */
176
+ async resolveReferences(configuration) {
177
+ const resolve = async (value) => {
178
+ if (typeof value === "string") {
179
+ const match = /^\$\{keyvault:([a-zA-Z0-9-]+)\}$/.exec(value);
180
+ return match ? this.getSecret(match[1]) : value;
181
+ }
182
+ if (Array.isArray(value))
183
+ return Promise.all(value.map(resolve));
184
+ if (value && typeof value === "object" && !(value instanceof SecretString)) {
185
+ return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, child]) => [key, await resolve(child)])));
186
+ }
187
+ return value;
188
+ };
189
+ return (await resolve(configuration));
190
+ }
191
+ /**
192
+ * Encrypt a configuration value with a wrapped AES key.
193
+ * @param data - Model data or encrypted envelope
194
+ * @param keyId - key id
195
+ * @returns The encrypt result
196
+ */
197
+ encrypt(data, keyId = this.parameters.keyId) {
198
+ return azureEncrypter.encrypt(data, { ...this.parameters, keyId });
199
+ }
200
+ /**
201
+ * Decrypt and authenticate an Azure envelope.
202
+ * @param data - Model data or encrypted envelope
203
+ * @returns The decrypt result
204
+ */
205
+ async decrypt(data) {
206
+ return new SecretString(await azureEncrypter.decrypt(data, this.parameters), "azure");
207
+ }
208
+ /**
209
+ * Describe the Azure resources and identity permissions required by this service.
210
+ * @param deployer - Deployment scope and identity helpers
211
+ * @returns The azure resources result
212
+ */
213
+ getAzureResources(deployer) {
214
+ const name = new URL(this.parameters.vaultUrl).hostname.split(".")[0];
215
+ const scope = `/subscriptions/${deployer.resources.subscriptionId}/resourceGroups/${deployer.resources.resourceGroup}/providers/Microsoft.KeyVault/vaults/${name}`;
216
+ return {
217
+ roleAssignments: ["4633458b-17de-408a-b874-0445c86b69e6", "12338af0-0e69-4776-bea7-57ae8d297424"].map(role => ({
218
+ scope,
219
+ roleDefinitionId: `/subscriptions/${deployer.resources.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/${role}`
220
+ }))
221
+ };
222
+ }
223
+ }
224
+ AzureKeyVault.Parameters = AzureKeyVaultParameters;
225
+ //# sourceMappingURL=keyvault.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyvault.service.js","sources":["../../src/services/keyvault.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { LogsIngestionClient } from "@azure/monitor-ingestion";
2
+ import { Service } from "@webda/core";
3
+ import { WorkerLogLevel, WorkerMessage } from "@webda/workout";
4
+ import { AzureParameters } from "./azure-parameters.js";
5
+ /** Azure Monitor Logs Ingestion settings. */
6
+ export declare class AzureMonitorLoggerParameters extends AzureParameters {
7
+ endpoint: string;
8
+ ruleId: string;
9
+ streamName: string;
10
+ logLevel: WorkerLogLevel;
11
+ batchSize: number;
12
+ flushInterval: number;
13
+ maxBufferedLogs: number;
14
+ }
15
+ /** Columns declared in the Data Collection Rule's stream. */
16
+ export interface AzureLogRecord extends Record<string, unknown> {
17
+ TimeGenerated: string;
18
+ Level: WorkerLogLevel;
19
+ Message: string;
20
+ }
21
+ /** Forward Webda logs to a custom Azure Monitor table.
22
+ * @WebdaModda
23
+ */
24
+ export declare class AzureMonitorLogger extends Service<AzureMonitorLoggerParameters> {
25
+ static Parameters: typeof AzureMonitorLoggerParameters;
26
+ protected client: LogsIngestionClient;
27
+ protected buffer: AzureLogRecord[];
28
+ protected sending?: Promise<void>;
29
+ protected timer?: ReturnType<typeof setInterval>;
30
+ protected messageListener?: (message: WorkerMessage) => void;
31
+ protected resultListenerOff?: () => void;
32
+ /** Number of records dropped because the bounded buffer was full. */
33
+ droppedLogs: number;
34
+ /** Last delivery error, available to health checks without recursively logging it. */
35
+ lastDeliveryFailed: boolean;
36
+ /**
37
+ * Perform init.
38
+ * @override
39
+ */
40
+ init(): Promise<this>;
41
+ /**
42
+ * Buffer one record. SecretString values retain their masked representation.
43
+ * @param level - Worker log level
44
+ * @param args - Log arguments
45
+ */
46
+ _log(level: WorkerLogLevel, ...args: unknown[]): void;
47
+ /**
48
+ * Serialize flushes; failed records stay at the front for the next scheduled retry.
49
+ * @returns Completion of the current flush attempt
50
+ */
51
+ sendLogs(): Promise<void>;
52
+ /**
53
+ * Deliver buffered records in bounded batches.
54
+ */
55
+ protected flush(): Promise<void>;
56
+ /**
57
+ * Detach log forwarding and stop scheduled flushing.
58
+ */
59
+ protected removeListeners(): void;
60
+ /**
61
+ * Perform stop.
62
+ * @override
63
+ */
64
+ stop(): Promise<void>;
65
+ }
66
+ //# sourceMappingURL=monitorlogger.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitorlogger.service.d.ts","sources":["../../src/services/monitorlogger.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAA6B,MAAM,aAAa,CAAC;AACjE,OAAO,EAA8B,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3F,OAAO,EAAE,eAAe,EAAsB,MAAM,uBAAuB,CAAC;AAE5E,6CAA6C;AAC7C,qBAAa,4BAA6B,SAAQ,eAAe;IAC/D,QAAQ,EAAG,MAAM,CAAC;IAClB,MAAM,EAAG,MAAM,CAAC;IAChB,UAAU,EAAG,MAAM,CAAC;IACpB,QAAQ,EAAE,cAAc,CAAU;IAClC,SAAS,SAAO;IAChB,aAAa,SAAQ;IACrB,eAAe,SAAS;CACzB;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,OAAO,CAAC,4BAA4B,CAAC;IAC3E,MAAM,CAAC,UAAU,sCAAgC;IACjD,SAAS,CAAC,MAAM,EAAG,mBAAmB,CAAC;IACvC,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,CAAM;IACxC,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,SAAS,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;IACjD,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IACzC,qEAAqE;IACrE,WAAW,SAAK;IAChB,sFAAsF;IACtF,kBAAkB,UAAS;IAE3B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B1B;IAED;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAOpD;IAED;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAMxB;IAED;;OAEG;IACH,UAAgB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAerC;IAED;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,IAAI,CAOhC;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAK1B;CACF"}