@kindgi/env-schema 0.1.5 → 0.1.6-rc.0

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/src/values.ts CHANGED
@@ -19,6 +19,11 @@ export const EXPORT_SIGNING_KEY_PATH_VAR = 'KINDGI_EXPORT_SIGNING_KEY_PATH';
19
19
  export const EXPORT_SIGNING_KEY_VAR = 'KINDGI_EXPORT_SIGNING_KEY';
20
20
  export const EXPORT_SIGNING_KMS_KEY_VAR = 'KINDGI_EXPORT_SIGNING_KMS_KEY';
21
21
 
22
+ /** Retired export public keys (PEM, concatenated): a file's absolute path, or its base64 value; at most one. */
23
+ export const EXPORT_SIGNING_RETIRED_PUBLIC_KEYS_PATH_VAR =
24
+ 'KINDGI_EXPORT_SIGNING_RETIRED_PUBLIC_KEYS_PATH';
25
+ export const EXPORT_SIGNING_RETIRED_PUBLIC_KEYS_VAR = 'KINDGI_EXPORT_SIGNING_RETIRED_PUBLIC_KEYS';
26
+
22
27
  /** The license key the server checks at startup outside development mode. */
23
28
  export const LICENSE_KEY_VAR = 'KINDGI_LICENSE_KEY';
24
29
 
@@ -79,6 +84,9 @@ export const AUTH_TURNSTILE_SITE_KEY_VAR = 'KINDGI_AUTH_TURNSTILE_SITE_KEY';
79
84
  /** Which hops in front of the runtime to trust for the client's address: a hop count, or IPs/CIDRs. */
80
85
  export const TRUSTED_PROXIES_VAR = 'KINDGI_TRUSTED_PROXIES';
81
86
 
87
+ /** Whether a tenant's admins may change its identity providers (`on` / `off`). */
88
+ export const AUTH_TENANT_PROVIDERS_VAR = 'KINDGI_AUTH_TENANT_PROVIDERS';
89
+
82
90
  /** A browser session's absolute lifetime, in milliseconds. */
83
91
  export const SESSION_TTL_MS_VAR = 'KINDGI_SESSION_TTL_MS';
84
92
 
@@ -162,6 +170,95 @@ export function parsePublicUrl(raw: string | undefined): string | undefined {
162
170
  return url.href.replace(/\/+$/, '');
163
171
  }
164
172
 
173
+ /** The Azure Key Vault key that wraps DEKs (postgres backend, KMS `azure`). */
174
+ export const AZURE_KEY_ID_VAR = 'KINDGI_SECRETS_AZURE_KEY_ID';
175
+
176
+ /** A Key Vault key, as `KINDGI_SECRETS_AZURE_KEY_ID` names it. */
177
+ export interface AzureKeyId {
178
+ /** `https://<vault>.vault.azure.net/keys/<name>`, without a version or trailing slash. */
179
+ readonly keyUrl: string;
180
+ /** The vault's origin, `https://<vault>.vault.azure.net`. */
181
+ readonly vaultUrl: string;
182
+ readonly keyName: string;
183
+ }
184
+
185
+ /**
186
+ * `KINDGI_SECRETS_AZURE_KEY_ID`: a Key Vault key's https URL **without a
187
+ * version** (`https://<vault>.vault.azure.net/keys/<name>`, any Azure
188
+ * cloud's vault or Managed HSM host). New DEKs are wrapped with the
189
+ * key's current version, and each records the version it used, so a URL
190
+ * pinned to one version is refused: it would outlive the key's rotation.
191
+ * Unset or blank: `undefined`.
192
+ */
193
+ export function parseAzureKeyId(raw: string | undefined): AzureKeyId | undefined {
194
+ if (raw === undefined || raw.trim() === '') return undefined;
195
+ const value = raw.trim();
196
+ let url: URL | undefined;
197
+ try {
198
+ url = new URL(value);
199
+ } catch {
200
+ url = undefined;
201
+ }
202
+ const path = url?.pathname.match(/^\/keys\/([^/]+)(?:\/([^/]*))?\/?$/);
203
+ if (
204
+ url === undefined ||
205
+ path === null ||
206
+ path === undefined ||
207
+ url.protocol !== 'https:' ||
208
+ url.username !== '' ||
209
+ url.password !== '' ||
210
+ url.search !== '' ||
211
+ url.hash !== '' ||
212
+ !/^[0-9A-Za-z-]{1,127}$/.test(path[1] ?? '')
213
+ ) {
214
+ throw new Error(
215
+ `${AZURE_KEY_ID_VAR} must be a Key Vault key's URL without a version, like https://my-vault.vault.azure.net/keys/kindgi-secrets. Got: ${value}.`,
216
+ );
217
+ }
218
+ const version = path[2];
219
+ if (version !== undefined && version !== '') {
220
+ throw new Error(
221
+ `${AZURE_KEY_ID_VAR} names one version of the key (${version}). Give the key without it, ${url.origin}/keys/${path[1]}: new secrets are wrapped with the key's current version, so a pinned version would outlive the key's rotation.`,
222
+ );
223
+ }
224
+ const keyName = path[1] as string;
225
+ return { keyUrl: `${url.origin}/keys/${keyName}`, vaultUrl: url.origin, keyName };
226
+ }
227
+
228
+ /** The Azure Key Vault the `secret-manager` backend keeps secrets in (manager `azure`). */
229
+ export const AZURE_VAULT_URL_VAR = 'KINDGI_SECRETS_AZURE_VAULT_URL';
230
+
231
+ /**
232
+ * `KINDGI_SECRETS_AZURE_VAULT_URL`: a vault's https origin
233
+ * (`https://<vault>.vault.azure.net`, any Azure cloud's vault host), with
234
+ * nothing after it but an optional `/`. Returns the origin. Unset or
235
+ * blank: `undefined`.
236
+ */
237
+ export function parseAzureVaultUrl(raw: string | undefined): string | undefined {
238
+ if (raw === undefined || raw.trim() === '') return undefined;
239
+ const value = raw.trim();
240
+ let url: URL | undefined;
241
+ try {
242
+ url = new URL(value);
243
+ } catch {
244
+ url = undefined;
245
+ }
246
+ if (
247
+ url === undefined ||
248
+ url.protocol !== 'https:' ||
249
+ (url.pathname !== '/' && url.pathname !== '') ||
250
+ url.username !== '' ||
251
+ url.password !== '' ||
252
+ url.search !== '' ||
253
+ url.hash !== ''
254
+ ) {
255
+ throw new Error(
256
+ `${AZURE_VAULT_URL_VAR} must be a Key Vault's URL with nothing after the host, like https://my-kindgi-secrets.vault.azure.net. Got: ${value}.`,
257
+ );
258
+ }
259
+ return url.origin;
260
+ }
261
+
165
262
  function isExactOrigin(value: string): boolean {
166
263
  let url: URL;
167
264
  try {