@webda/core 4.0.0-beta.6 → 4.0.0-beta.7

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 (138) hide show
  1. package/README.md +6 -5
  2. package/lib/application/application.d.ts.map +1 -1
  3. package/lib/application/application.js +6 -5
  4. package/lib/application/application.js.map +1 -1
  5. package/lib/application/iconfiguration.d.ts +31 -0
  6. package/lib/application/iconfiguration.d.ts.map +1 -1
  7. package/lib/application/iconfiguration.js.map +1 -1
  8. package/lib/application/unpackedapplication.d.ts.map +1 -1
  9. package/lib/application/unpackedapplication.js +2 -1
  10. package/lib/application/unpackedapplication.js.map +1 -1
  11. package/lib/bin/cli-phase.d.ts +18 -2
  12. package/lib/bin/cli-phase.d.ts.map +1 -1
  13. package/lib/bin/cli-phase.js +25 -0
  14. package/lib/bin/cli-phase.js.map +1 -1
  15. package/lib/bin/cli.d.ts +8 -0
  16. package/lib/bin/cli.d.ts.map +1 -1
  17. package/lib/bin/cli.js +94 -35
  18. package/lib/bin/cli.js.map +1 -1
  19. package/lib/configurations/configuration.service.d.ts +7 -0
  20. package/lib/configurations/configuration.service.d.ts.map +1 -1
  21. package/lib/configurations/configuration.service.js +18 -5
  22. package/lib/configurations/configuration.service.js.map +1 -1
  23. package/lib/configurations/kubernetesconfiguration.service.d.ts.map +1 -1
  24. package/lib/configurations/kubernetesconfiguration.service.js +1 -4
  25. package/lib/configurations/kubernetesconfiguration.service.js.map +1 -1
  26. package/lib/contexts/httpcontext.d.ts +15 -1
  27. package/lib/contexts/httpcontext.d.ts.map +1 -1
  28. package/lib/contexts/httpcontext.js +61 -19
  29. package/lib/contexts/httpcontext.js.map +1 -1
  30. package/lib/contexts/operationcontext.d.ts +6 -0
  31. package/lib/contexts/operationcontext.d.ts.map +1 -1
  32. package/lib/contexts/operationcontext.js +16 -2
  33. package/lib/contexts/operationcontext.js.map +1 -1
  34. package/lib/contexts/restcontext.d.ts +110 -0
  35. package/lib/contexts/restcontext.d.ts.map +1 -0
  36. package/lib/contexts/restcontext.js +247 -0
  37. package/lib/contexts/restcontext.js.map +1 -0
  38. package/lib/contexts/streamingcontext.d.ts +71 -0
  39. package/lib/contexts/streamingcontext.d.ts.map +1 -0
  40. package/lib/contexts/streamingcontext.js +93 -0
  41. package/lib/contexts/streamingcontext.js.map +1 -0
  42. package/lib/contexts/webcontext.d.ts +20 -0
  43. package/lib/contexts/webcontext.d.ts.map +1 -1
  44. package/lib/contexts/webcontext.js +43 -10
  45. package/lib/contexts/webcontext.js.map +1 -1
  46. package/lib/contexts/websocketcontext.d.ts +39 -0
  47. package/lib/contexts/websocketcontext.d.ts.map +1 -0
  48. package/lib/contexts/websocketcontext.js +67 -0
  49. package/lib/contexts/websocketcontext.js.map +1 -0
  50. package/lib/core/asyncqueue.d.ts +50 -0
  51. package/lib/core/asyncqueue.d.ts.map +1 -0
  52. package/lib/core/asyncqueue.js +96 -0
  53. package/lib/core/asyncqueue.js.map +1 -0
  54. package/lib/core/core.d.ts +18 -0
  55. package/lib/core/core.d.ts.map +1 -1
  56. package/lib/core/core.js +72 -7
  57. package/lib/core/core.js.map +1 -1
  58. package/lib/core/icore.d.ts +14 -1
  59. package/lib/core/icore.d.ts.map +1 -1
  60. package/lib/core/icore.js.map +1 -1
  61. package/lib/core/instancestorage.d.ts +1 -0
  62. package/lib/core/instancestorage.d.ts.map +1 -1
  63. package/lib/core/instancestorage.js +1 -0
  64. package/lib/core/instancestorage.js.map +1 -1
  65. package/lib/core/operations.d.ts +49 -6
  66. package/lib/core/operations.d.ts.map +1 -1
  67. package/lib/core/operations.js +187 -24
  68. package/lib/core/operations.js.map +1 -1
  69. package/lib/deployers/git.d.ts +4 -2
  70. package/lib/deployers/git.d.ts.map +1 -1
  71. package/lib/deployers/git.js +44 -5
  72. package/lib/deployers/git.js.map +1 -1
  73. package/lib/errors/errors.d.ts +15 -0
  74. package/lib/errors/errors.d.ts.map +1 -1
  75. package/lib/errors/errors.js +20 -0
  76. package/lib/errors/errors.js.map +1 -1
  77. package/lib/index.d.ts +5 -0
  78. package/lib/index.d.ts.map +1 -1
  79. package/lib/index.js +5 -0
  80. package/lib/index.js.map +1 -1
  81. package/lib/rest/restoperationstransport.service.d.ts +108 -0
  82. package/lib/rest/restoperationstransport.service.d.ts.map +1 -1
  83. package/lib/rest/restoperationstransport.service.js +348 -9
  84. package/lib/rest/restoperationstransport.service.js.map +1 -1
  85. package/lib/rest/router.service.d.ts +1 -1
  86. package/lib/rest/router.service.d.ts.map +1 -1
  87. package/lib/rest/router.service.js.map +1 -1
  88. package/lib/services/authenticatedencryption.d.ts +25 -0
  89. package/lib/services/authenticatedencryption.d.ts.map +1 -0
  90. package/lib/services/authenticatedencryption.js +56 -0
  91. package/lib/services/authenticatedencryption.js.map +1 -0
  92. package/lib/services/cloudbinary.d.ts.map +1 -1
  93. package/lib/services/cloudbinary.js +3 -2
  94. package/lib/services/cloudbinary.js.map +1 -1
  95. package/lib/services/command.d.ts +7 -1
  96. package/lib/services/command.d.ts.map +1 -1
  97. package/lib/services/command.js +4 -0
  98. package/lib/services/command.js.map +1 -1
  99. package/lib/services/cryptoservice.service.d.ts +405 -25
  100. package/lib/services/cryptoservice.service.d.ts.map +1 -1
  101. package/lib/services/cryptoservice.service.js +779 -72
  102. package/lib/services/cryptoservice.service.js.map +1 -1
  103. package/lib/services/httpserver.service.d.ts.map +1 -1
  104. package/lib/services/httpserver.service.js +15 -9
  105. package/lib/services/httpserver.service.js.map +1 -1
  106. package/lib/services/icryptoservice.d.ts +11 -0
  107. package/lib/services/icryptoservice.d.ts.map +1 -1
  108. package/lib/services/icryptoservice.js +2 -0
  109. package/lib/services/icryptoservice.js.map +1 -1
  110. package/lib/services/mailer.service.d.ts +4 -0
  111. package/lib/services/mailer.service.d.ts.map +1 -1
  112. package/lib/services/mailer.service.js +7 -1
  113. package/lib/services/mailer.service.js.map +1 -1
  114. package/lib/services/operationstransport.d.ts +13 -0
  115. package/lib/services/operationstransport.d.ts.map +1 -1
  116. package/lib/services/operationstransport.js +28 -6
  117. package/lib/services/operationstransport.js.map +1 -1
  118. package/lib/services/pki.encrypter.d.ts +214 -0
  119. package/lib/services/pki.encrypter.d.ts.map +1 -0
  120. package/lib/services/pki.encrypter.js +350 -0
  121. package/lib/services/pki.encrypter.js.map +1 -0
  122. package/lib/services/secretscheck.d.ts +120 -0
  123. package/lib/services/secretscheck.d.ts.map +1 -0
  124. package/lib/services/secretscheck.js +322 -0
  125. package/lib/services/secretscheck.js.map +1 -0
  126. package/lib/services/servicecommands.d.ts +8 -4
  127. package/lib/services/servicecommands.d.ts.map +1 -1
  128. package/lib/services/servicecommands.js +14 -5
  129. package/lib/services/servicecommands.js.map +1 -1
  130. package/lib/session/manager.model.d.ts +3 -1
  131. package/lib/session/manager.model.d.ts.map +1 -1
  132. package/lib/session/manager.model.js +6 -3
  133. package/lib/session/manager.model.js.map +1 -1
  134. package/lib/test/objects.d.ts.map +1 -1
  135. package/lib/test/objects.js +3 -1
  136. package/lib/test/objects.js.map +1 -1
  137. package/package.json +12 -11
  138. package/webda.module.json +135 -41
@@ -0,0 +1,214 @@
1
+ import { KeyObject } from "crypto";
2
+ import type { EncrypterContext, StringEncrypter } from "./cryptoservice.service.js";
3
+ /**
4
+ * Options of the `pki` encrypter, in `parameters.configurationEncryption.encrypters.pki`
5
+ */
6
+ export interface PkiEncrypterOptions {
7
+ /**
8
+ * Key id used to encrypt new values
9
+ *
10
+ * Its public key must be available: `<publicKeys>/<activeKey>.pub.pem`
11
+ */
12
+ activeKey?: string;
13
+ /**
14
+ * Directory of the public keys, relative to the application: `<kid>.pub.pem`
15
+ *
16
+ * Commit it with the application, any developer or CI job can then encrypt a value.
17
+ *
18
+ * @default ".webda/keys"
19
+ */
20
+ publicKeys?: string;
21
+ /**
22
+ * Directory of the private keys at runtime, a Kubernetes Secret mount for example: `<kid>.pem` or `<kid>`
23
+ *
24
+ * @default env WEBDA_PKI_PRIVATE_KEYS_DIR, then "/etc/webda/pki"
25
+ */
26
+ privateKeys?: string;
27
+ }
28
+ /**
29
+ * Version of the `pki` encrypted format
30
+ */
31
+ export declare const PKI_FORMAT_V1 = "v1";
32
+ /**
33
+ * Default directory of the public keys, relative to the application
34
+ */
35
+ export declare const PKI_DEFAULT_PUBLIC_KEYS = ".webda/keys";
36
+ /**
37
+ * Default directory of the private keys
38
+ */
39
+ export declare const PKI_DEFAULT_PRIVATE_KEYS = "/etc/webda/pki";
40
+ /**
41
+ * Environment variable overriding the private keys directory
42
+ */
43
+ export declare const PKI_PRIVATE_KEYS_DIR_ENV = "WEBDA_PKI_PRIVATE_KEYS_DIR";
44
+ /**
45
+ * Environment variable prefix holding one private key PEM: `WEBDA_PKI_PRIVATE_KEY_<KID>`
46
+ */
47
+ export declare const PKI_PRIVATE_KEY_ENV_PREFIX = "WEBDA_PKI_PRIVATE_KEY_";
48
+ /**
49
+ * Environment variable holding the passphrase of the private keys
50
+ */
51
+ export declare const PKI_PASSPHRASE_ENV = "WEBDA_PKI_PASSPHRASE";
52
+ /**
53
+ * Minimum RSA modulus length
54
+ */
55
+ export declare const PKI_MIN_BITS = 3072;
56
+ /**
57
+ * Check a key id
58
+ * @param kid - the key id
59
+ * @returns the key id
60
+ */
61
+ export declare function checkKid(kid: string): string;
62
+ /**
63
+ * Name of the environment variable holding the private key of a kid
64
+ * @param kid - the key id
65
+ * @returns the variable name
66
+ */
67
+ export declare function getPrivateKeyEnv(kid: string): string;
68
+ /**
69
+ * Parsed `pki` encrypted value
70
+ */
71
+ export interface PkiValue {
72
+ kid: string;
73
+ wrappedKey: string;
74
+ ciphertext: string;
75
+ }
76
+ /**
77
+ * Parse a `v1:<kid>:<wrappedKey>:<ciphertext>` value
78
+ * @param data - the encrypted value, without `crypt:pki:`
79
+ * @returns the parts
80
+ */
81
+ export declare function parsePkiValue(data: string): PkiValue;
82
+ /**
83
+ * Public and private keys of the `pki` encrypter
84
+ *
85
+ * The keys are loaded lazily and cached by kid.
86
+ */
87
+ export declare class PkiKeyring {
88
+ /**
89
+ * Key id used to encrypt
90
+ */
91
+ readonly activeKey?: string;
92
+ /**
93
+ * Absolute directory of the public keys
94
+ */
95
+ readonly publicKeysDir: string;
96
+ /**
97
+ * Absolute directory of the private keys
98
+ */
99
+ readonly privateKeysDir: string;
100
+ protected publicKeys: Map<string, KeyObject>;
101
+ protected privateKeys: Map<string, KeyObject>;
102
+ /**
103
+ * @param options - the encrypter options
104
+ * @param appPath - the application path, relative directories resolve against it
105
+ */
106
+ constructor(options?: PkiEncrypterOptions, appPath?: string);
107
+ /**
108
+ * List the kids of a directory
109
+ * @param dir - the directory
110
+ * @param suffix - the file suffix
111
+ * @param optionalSuffix - also accept files without the suffix
112
+ * @returns the sorted kids
113
+ */
114
+ protected static listDir(dir: string, suffix: string, optionalSuffix: boolean): string[];
115
+ /**
116
+ * List the kids having a public key
117
+ * @returns the kids
118
+ */
119
+ listKids(): string[];
120
+ /**
121
+ * List the kids having a private key file
122
+ * @returns the kids
123
+ */
124
+ listPrivateKids(): string[];
125
+ /**
126
+ * Get the public key of a kid
127
+ *
128
+ * From `<publicKeys>/<kid>.pub.pem`, or derived from its private key when it is available
129
+ *
130
+ * @param kid - the key id
131
+ * @returns the public key
132
+ */
133
+ getPublicKey(kid: string): KeyObject;
134
+ /**
135
+ * Find the source of a private key
136
+ * @param kid - the key id
137
+ * @returns the environment variable or file name, undefined if not found
138
+ */
139
+ protected findPrivateKey(kid: string): {
140
+ env?: string;
141
+ file?: string;
142
+ } | undefined;
143
+ /**
144
+ * Check if the private key of a kid is available
145
+ * @param kid - the key id
146
+ * @returns true if available
147
+ */
148
+ hasPrivateKey(kid: string): boolean;
149
+ /**
150
+ * Get the private key of a kid
151
+ *
152
+ * From `WEBDA_PKI_PRIVATE_KEY_<KID>`, then `<privateKeys>/<kid>.pem` or `<privateKeys>/<kid>`.
153
+ * The passphrase, if any, is read from `WEBDA_PKI_PASSPHRASE`.
154
+ *
155
+ * @param kid - the key id
156
+ * @returns the private key
157
+ */
158
+ getPrivateKey(kid: string): KeyObject;
159
+ }
160
+ /**
161
+ * Asymmetric encrypter: hybrid RSA-OAEP-256 + AES-256-GCM
162
+ *
163
+ * The public keys are committed with the application, so anyone can encrypt a value. The private keys only live
164
+ * in the runtime (a Kubernetes Secret mount or environment variables), so only the application can decrypt.
165
+ *
166
+ * Format: `v1:<kid>:<base64(wrappedKey)>:<base64(iv | tag | ciphertext)>`, the kid is authenticated.
167
+ */
168
+ export declare class PkiEncrypter implements StringEncrypter {
169
+ protected keyring: PkiKeyring;
170
+ /**
171
+ * Serialized configuration of the keyring, to keep its cache when unchanged
172
+ */
173
+ protected configuration: string;
174
+ /**
175
+ * Configure the keyring
176
+ * @param options - the encrypter options
177
+ * @param context - the encryption context
178
+ */
179
+ configure(options?: PkiEncrypterOptions, context?: EncrypterContext): void;
180
+ /**
181
+ * Get the keyring, with the default options when not configured
182
+ * @returns the keyring
183
+ */
184
+ getKeyring(): PkiKeyring;
185
+ /**
186
+ * Additional authenticated data binding the format and the kid
187
+ * @param kid - the key id
188
+ * @returns the AAD
189
+ */
190
+ protected static aad(kid: string): Uint8Array;
191
+ /**
192
+ * Encrypt with the public key of the active key
193
+ * @param data - the plain value
194
+ * @returns the encrypted value
195
+ */
196
+ encrypt(data: string): Promise<string>;
197
+ /**
198
+ * Decrypt with the private key of the value kid
199
+ * @param data - the encrypted value
200
+ * @returns the plain value
201
+ */
202
+ decrypt(data: string): Promise<string>;
203
+ /**
204
+ * A value needs an upgrade when it was not encrypted with the active key
205
+ * @param data - the encrypted value
206
+ * @returns true to re-encrypt it
207
+ */
208
+ needsUpgrade(data: string): boolean;
209
+ }
210
+ /**
211
+ * The `pki` encrypter instance, registered by CryptoService
212
+ */
213
+ export declare const pkiEncrypter: PkiEncrypter;
214
+ //# sourceMappingURL=pki.encrypter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pki.encrypter.d.ts","sourceRoot":"","sources":["../../src/services/pki.encrypter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,350 @@
1
+ import { constants, createPrivateKey, createPublicKey, privateDecrypt, publicEncrypt, randomBytes } from "crypto";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import { AuthenticatedEncryption } from "./authenticatedencryption.js";
5
+ /**
6
+ * Version of the `pki` encrypted format
7
+ */
8
+ export const PKI_FORMAT_V1 = "v1";
9
+ /**
10
+ * Default directory of the public keys, relative to the application
11
+ */
12
+ export const PKI_DEFAULT_PUBLIC_KEYS = ".webda/keys";
13
+ /**
14
+ * Default directory of the private keys
15
+ */
16
+ export const PKI_DEFAULT_PRIVATE_KEYS = "/etc/webda/pki";
17
+ /**
18
+ * Environment variable overriding the private keys directory
19
+ */
20
+ export const PKI_PRIVATE_KEYS_DIR_ENV = "WEBDA_PKI_PRIVATE_KEYS_DIR";
21
+ /**
22
+ * Environment variable prefix holding one private key PEM: `WEBDA_PKI_PRIVATE_KEY_<KID>`
23
+ */
24
+ export const PKI_PRIVATE_KEY_ENV_PREFIX = "WEBDA_PKI_PRIVATE_KEY_";
25
+ /**
26
+ * Environment variable holding the passphrase of the private keys
27
+ */
28
+ export const PKI_PASSPHRASE_ENV = "WEBDA_PKI_PASSPHRASE";
29
+ /**
30
+ * Minimum RSA modulus length
31
+ */
32
+ export const PKI_MIN_BITS = 3072;
33
+ /**
34
+ * Valid key id
35
+ */
36
+ const KID = /^[A-Za-z0-9_.-]+$/;
37
+ /**
38
+ * Check a key id
39
+ * @param kid - the key id
40
+ * @returns the key id
41
+ */
42
+ export function checkKid(kid) {
43
+ if (typeof kid !== "string" || !KID.test(kid)) {
44
+ throw new Error(`Invalid key id '${kid}', use letters, digits, '_', '-' and '.' only`);
45
+ }
46
+ return kid;
47
+ }
48
+ /**
49
+ * Name of the environment variable holding the private key of a kid
50
+ * @param kid - the key id
51
+ * @returns the variable name
52
+ */
53
+ export function getPrivateKeyEnv(kid) {
54
+ return PKI_PRIVATE_KEY_ENV_PREFIX + kid.toUpperCase().replace(/[-.]/g, "_");
55
+ }
56
+ /**
57
+ * Check that a key can be used by the `pki` encrypter
58
+ * @param key - the key
59
+ * @param kid - the key id, for the message
60
+ * @returns the key
61
+ */
62
+ function checkKey(key, kid) {
63
+ if (key.asymmetricKeyType !== "rsa") {
64
+ throw new Error(`Key '${kid}' is not an RSA key (${key.asymmetricKeyType})`);
65
+ }
66
+ if ((key.asymmetricKeyDetails?.modulusLength ?? 0) < PKI_MIN_BITS) {
67
+ throw new Error(`Key '${kid}' is too small, RSA ${PKI_MIN_BITS} bits at least is required`);
68
+ }
69
+ return key;
70
+ }
71
+ /**
72
+ * Parse a `v1:<kid>:<wrappedKey>:<ciphertext>` value
73
+ * @param data - the encrypted value, without `crypt:pki:`
74
+ * @returns the parts
75
+ */
76
+ export function parsePkiValue(data) {
77
+ const parts = typeof data === "string" ? data.split(":") : [];
78
+ if (parts.length !== 4 || parts[0] !== PKI_FORMAT_V1 || !KID.test(parts[1])) {
79
+ throw new Error("Invalid pki encrypted data");
80
+ }
81
+ return { kid: parts[1], wrappedKey: parts[2], ciphertext: parts[3] };
82
+ }
83
+ /**
84
+ * Public and private keys of the `pki` encrypter
85
+ *
86
+ * The keys are loaded lazily and cached by kid.
87
+ */
88
+ export class PkiKeyring {
89
+ /**
90
+ * Key id used to encrypt
91
+ */
92
+ activeKey;
93
+ /**
94
+ * Absolute directory of the public keys
95
+ */
96
+ publicKeysDir;
97
+ /**
98
+ * Absolute directory of the private keys
99
+ */
100
+ privateKeysDir;
101
+ publicKeys = new Map();
102
+ privateKeys = new Map();
103
+ /**
104
+ * @param options - the encrypter options
105
+ * @param appPath - the application path, relative directories resolve against it
106
+ */
107
+ constructor(options = {}, appPath = process.cwd()) {
108
+ if (options.activeKey !== undefined) {
109
+ this.activeKey = checkKid(options.activeKey);
110
+ }
111
+ this.publicKeysDir = resolve(appPath, options.publicKeys ?? PKI_DEFAULT_PUBLIC_KEYS);
112
+ this.privateKeysDir = resolve(appPath, options.privateKeys ?? process.env[PKI_PRIVATE_KEYS_DIR_ENV] ?? PKI_DEFAULT_PRIVATE_KEYS);
113
+ }
114
+ /**
115
+ * List the kids of a directory
116
+ * @param dir - the directory
117
+ * @param suffix - the file suffix
118
+ * @param optionalSuffix - also accept files without the suffix
119
+ * @returns the sorted kids
120
+ */
121
+ static listDir(dir, suffix, optionalSuffix) {
122
+ if (!existsSync(dir)) {
123
+ return [];
124
+ }
125
+ const kids = new Set();
126
+ for (const file of readdirSync(dir)) {
127
+ // Kubernetes Secret mounts hold `..data` and `..<timestamp>` entries
128
+ if (file.startsWith(".") || !statSync(join(dir, file)).isFile()) {
129
+ continue;
130
+ }
131
+ let kid;
132
+ if (file.endsWith(suffix)) {
133
+ kid = file.substring(0, file.length - suffix.length);
134
+ }
135
+ else if (optionalSuffix && !file.includes(".pem")) {
136
+ kid = file;
137
+ }
138
+ if (kid && KID.test(kid)) {
139
+ kids.add(kid);
140
+ }
141
+ }
142
+ return [...kids].sort();
143
+ }
144
+ /**
145
+ * List the kids having a public key
146
+ * @returns the kids
147
+ */
148
+ listKids() {
149
+ return PkiKeyring.listDir(this.publicKeysDir, ".pub.pem", false);
150
+ }
151
+ /**
152
+ * List the kids having a private key file
153
+ * @returns the kids
154
+ */
155
+ listPrivateKids() {
156
+ return PkiKeyring.listDir(this.privateKeysDir, ".pem", true);
157
+ }
158
+ /**
159
+ * Get the public key of a kid
160
+ *
161
+ * From `<publicKeys>/<kid>.pub.pem`, or derived from its private key when it is available
162
+ *
163
+ * @param kid - the key id
164
+ * @returns the public key
165
+ */
166
+ getPublicKey(kid) {
167
+ checkKid(kid);
168
+ if (!this.publicKeys.has(kid)) {
169
+ const file = join(this.publicKeysDir, `${kid}.pub.pem`);
170
+ let key;
171
+ if (existsSync(file)) {
172
+ try {
173
+ key = createPublicKey(readFileSync(file));
174
+ }
175
+ catch (err) {
176
+ throw new Error(`Cannot load public key '${kid}' from ${file}: ${err.message}`);
177
+ }
178
+ }
179
+ else if (this.hasPrivateKey(kid)) {
180
+ key = createPublicKey(this.getPrivateKey(kid));
181
+ }
182
+ else {
183
+ throw new Error(`No public key for active key '${kid}' in ${this.publicKeysDir}`);
184
+ }
185
+ this.publicKeys.set(kid, checkKey(key, kid));
186
+ }
187
+ return this.publicKeys.get(kid);
188
+ }
189
+ /**
190
+ * Find the source of a private key
191
+ * @param kid - the key id
192
+ * @returns the environment variable or file name, undefined if not found
193
+ */
194
+ findPrivateKey(kid) {
195
+ const env = getPrivateKeyEnv(kid);
196
+ if (process.env[env]) {
197
+ return { env };
198
+ }
199
+ for (const file of [join(this.privateKeysDir, `${kid}.pem`), join(this.privateKeysDir, kid)]) {
200
+ if (existsSync(file) && statSync(file).isFile()) {
201
+ return { file };
202
+ }
203
+ }
204
+ return undefined;
205
+ }
206
+ /**
207
+ * Check if the private key of a kid is available
208
+ * @param kid - the key id
209
+ * @returns true if available
210
+ */
211
+ hasPrivateKey(kid) {
212
+ return this.privateKeys.has(kid) || this.findPrivateKey(kid) !== undefined;
213
+ }
214
+ /**
215
+ * Get the private key of a kid
216
+ *
217
+ * From `WEBDA_PKI_PRIVATE_KEY_<KID>`, then `<privateKeys>/<kid>.pem` or `<privateKeys>/<kid>`.
218
+ * The passphrase, if any, is read from `WEBDA_PKI_PASSPHRASE`.
219
+ *
220
+ * @param kid - the key id
221
+ * @returns the private key
222
+ */
223
+ getPrivateKey(kid) {
224
+ checkKid(kid);
225
+ if (!this.privateKeys.has(kid)) {
226
+ const source = this.findPrivateKey(kid);
227
+ if (!source) {
228
+ const available = this.listPrivateKids();
229
+ throw new Error(`No private key for kid '${kid}' (available: ${available.length ? available.join(", ") : "none"} in ${this.privateKeysDir})`);
230
+ }
231
+ const origin = source.env ?? source.file;
232
+ let key;
233
+ try {
234
+ key = createPrivateKey({
235
+ key: source.env ? process.env[source.env] : readFileSync(source.file),
236
+ passphrase: process.env[PKI_PASSPHRASE_ENV]
237
+ });
238
+ }
239
+ catch (err) {
240
+ // The error never contains the key material
241
+ throw new Error(`Cannot load private key '${kid}' from ${origin}: ${err.message}`);
242
+ }
243
+ this.privateKeys.set(kid, checkKey(key, kid));
244
+ }
245
+ return this.privateKeys.get(kid);
246
+ }
247
+ }
248
+ /**
249
+ * Asymmetric encrypter: hybrid RSA-OAEP-256 + AES-256-GCM
250
+ *
251
+ * The public keys are committed with the application, so anyone can encrypt a value. The private keys only live
252
+ * in the runtime (a Kubernetes Secret mount or environment variables), so only the application can decrypt.
253
+ *
254
+ * Format: `v1:<kid>:<base64(wrappedKey)>:<base64(iv | tag | ciphertext)>`, the kid is authenticated.
255
+ */
256
+ export class PkiEncrypter {
257
+ keyring;
258
+ /**
259
+ * Serialized configuration of the keyring, to keep its cache when unchanged
260
+ */
261
+ configuration;
262
+ /**
263
+ * Configure the keyring
264
+ * @param options - the encrypter options
265
+ * @param context - the encryption context
266
+ */
267
+ configure(options = {}, context) {
268
+ const appPath = context?.appPath ?? process.cwd();
269
+ const configuration = JSON.stringify([options, appPath, process.env[PKI_PRIVATE_KEYS_DIR_ENV]]);
270
+ if (this.keyring && configuration === this.configuration) {
271
+ return;
272
+ }
273
+ this.keyring = new PkiKeyring(options, appPath);
274
+ this.configuration = configuration;
275
+ }
276
+ /**
277
+ * Get the keyring, with the default options when not configured
278
+ * @returns the keyring
279
+ */
280
+ getKeyring() {
281
+ if (!this.keyring) {
282
+ this.configure();
283
+ }
284
+ return this.keyring;
285
+ }
286
+ /**
287
+ * Additional authenticated data binding the format and the kid
288
+ * @param kid - the key id
289
+ * @returns the AAD
290
+ */
291
+ static aad(kid) {
292
+ return new Uint8Array(Buffer.from(`${PKI_FORMAT_V1}:${kid}`));
293
+ }
294
+ /**
295
+ * Encrypt with the public key of the active key
296
+ * @param data - the plain value
297
+ * @returns the encrypted value
298
+ */
299
+ async encrypt(data) {
300
+ const keyring = this.getKeyring();
301
+ const kid = keyring.activeKey;
302
+ if (!kid) {
303
+ throw new Error("No active key, set parameters.configurationEncryption.encrypters.pki.activeKey");
304
+ }
305
+ const publicKey = keyring.getPublicKey(kid);
306
+ const dataKey = new Uint8Array(randomBytes(32));
307
+ const ciphertext = AuthenticatedEncryption.encrypt(dataKey, data, PkiEncrypter.aad(kid));
308
+ const wrappedKey = publicEncrypt({ key: publicKey, padding: constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256" }, dataKey).toString("base64");
309
+ return `${PKI_FORMAT_V1}:${kid}:${wrappedKey}:${ciphertext}`;
310
+ }
311
+ /**
312
+ * Decrypt with the private key of the value kid
313
+ * @param data - the encrypted value
314
+ * @returns the plain value
315
+ */
316
+ async decrypt(data) {
317
+ const { kid, wrappedKey, ciphertext } = parsePkiValue(data);
318
+ const privateKey = this.getKeyring().getPrivateKey(kid);
319
+ let dataKey;
320
+ try {
321
+ dataKey = new Uint8Array(privateDecrypt({ key: privateKey, padding: constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256" }, new Uint8Array(Buffer.from(wrappedKey, "base64"))));
322
+ }
323
+ catch {
324
+ throw new Error("Wrong key or altered data");
325
+ }
326
+ if (dataKey.length !== 32) {
327
+ throw new Error("Wrong key or altered data");
328
+ }
329
+ return AuthenticatedEncryption.decrypt(dataKey, ciphertext, PkiEncrypter.aad(kid));
330
+ }
331
+ /**
332
+ * A value needs an upgrade when it was not encrypted with the active key
333
+ * @param data - the encrypted value
334
+ * @returns true to re-encrypt it
335
+ */
336
+ needsUpgrade(data) {
337
+ const activeKey = this.getKeyring().activeKey;
338
+ try {
339
+ return activeKey !== undefined && parsePkiValue(data).kid !== activeKey;
340
+ }
341
+ catch {
342
+ return true;
343
+ }
344
+ }
345
+ }
346
+ /**
347
+ * The `pki` encrypter instance, registered by CryptoService
348
+ */
349
+ export const pkiEncrypter = new PkiEncrypter();
350
+ //# sourceMappingURL=pki.encrypter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pki.encrypter.js","sourceRoot":"","sources":["../../src/services/pki.encrypter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,eAAe,EAEf,cAAc,EACd,aAAa,EACb,WAAW,EACZ,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AA6BvE;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AACrD;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;AACzD;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,4BAA4B,CAAC;AACrE;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;AACnE;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AACzD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC;;GAEG;AACH,MAAM,GAAG,GAAG,mBAAmB,CAAC;AAEhC;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,+CAA+C,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,0BAA0B,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,GAAc,EAAE,GAAW;IAC3C,IAAI,GAAG,CAAC,iBAAiB,KAAK,KAAK,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,wBAAwB,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,aAAa,IAAI,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,uBAAuB,YAAY,4BAA4B,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAWD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,aAAa,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACrB;;OAEG;IACM,SAAS,CAAU;IAC5B;;OAEG;IACM,aAAa,CAAS;IAC/B;;OAEG;IACM,cAAc,CAAS;IACtB,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1C,WAAW,GAAG,IAAI,GAAG,EAAqB,CAAC;IAErD;;;OAGG;IACH,YAAY,OAAO,GAAwB,EAAE,EAAE,OAAO,GAAW,OAAO,CAAC,GAAG,EAAE;QAC5E,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC,CAAC;QACrF,IAAI,CAAC,cAAc,GAAG,OAAO,CAC3B,OAAO,EACP,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,wBAAwB,CACzF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACO,MAAM,CAAC,OAAO,CAAC,GAAW,EAAE,MAAc,EAAE,cAAuB;QAC3E,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,qEAAqE;YACrE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBAChE,SAAS;YACX,CAAC;YACD,IAAI,GAAW,CAAC;YAChB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YACvD,CAAC;iBAAM,IAAI,cAAc,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpD,GAAG,GAAG,IAAI,CAAC;YACb,CAAC;YACD,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;;;OAOG;IACH,YAAY,CAAC,GAAW;QACtB,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,GAAG,UAAU,CAAC,CAAC;YACxD,IAAI,GAAc,CAAC;YACnB,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC;oBACH,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC5C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,UAAU,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClF,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;YACjD,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,QAAQ,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;YACpF,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACO,cAAc,CAAC,GAAW;QAClC,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YAC7F,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBAChD,OAAO,EAAE,IAAI,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IAC7E,CAAC;IAED;;;;;;;;OAQG;IACH,aAAa,CAAC,GAAW;QACvB,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CACb,2BAA2B,GAAG,iBAAiB,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,cAAc,GAAG,CAC7H,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC;YACzC,IAAI,GAAc,CAAC;YACnB,IAAI,CAAC;gBACH,GAAG,GAAG,gBAAgB,CAAC;oBACrB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;oBACrE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;iBAC5C,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,4CAA4C;gBAC5C,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,UAAU,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACrF,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,YAAY;IACb,OAAO,CAAa;IAC9B;;OAEG;IACO,aAAa,CAAS;IAEhC;;;;OAIG;IACH,SAAS,CAAC,OAAO,GAAwB,EAAE,EAAE,OAA0B;QACrE,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAClD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;QAChG,IAAI,IAAI,CAAC,OAAO,IAAI,aAAa,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACO,MAAM,CAAC,GAAG,CAAC,GAAW;QAC9B,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC;QAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAC;QACpG,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACzF,MAAM,UAAU,GAAG,aAAa,CAC9B,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,EAAE,EACjF,OAAO,CACR,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,OAAO,GAAG,aAAa,IAAI,GAAG,IAAI,UAAU,IAAI,UAAU,EAAE,CAAC;IAC/D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,IAAY;QACxB,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,OAAmB,CAAC;QACxB,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,UAAU,CACtB,cAAc,CACZ,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAClF,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAClD,CACF,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,uBAAuB,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACrF,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,IAAY;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;QAC9C,IAAI,CAAC;YACH,OAAO,SAAS,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC;QAC1E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC"}