@cipherstash/stack 0.13.0 → 0.15.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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/{chunk-46PDK2Z6.js → chunk-MD6742R6.js} +1 -1
- package/dist/{chunk-46PDK2Z6.js.map → chunk-MD6742R6.js.map} +1 -1
- package/dist/{chunk-O4MBO4DJ.js → chunk-YPAPL3IC.js} +2 -2
- package/dist/{client-bW-5wG9Y.d.cts → client-DQyqn0oT.d.cts} +1 -1
- package/dist/{client-CZLBiToT.d.ts → client-Dv60lAyy.d.ts} +1 -1
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/drizzle/index.cjs +4 -2
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +2 -2
- package/dist/drizzle/index.d.ts +2 -2
- package/dist/drizzle/index.js +5 -3
- package/dist/drizzle/index.js.map +1 -1
- package/dist/dynamodb/index.d.cts +2 -2
- package/dist/dynamodb/index.d.ts +2 -2
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +2 -2
- package/dist/identity/index.js +63 -3
- package/dist/identity/index.js.map +1 -1
- package/dist/index.cjs +6 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -7
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/supabase/index.d.cts +2 -2
- package/dist/supabase/index.d.ts +2 -2
- package/dist/{types-public-WADaA-TW.d.ts → types-public-DX3mGqoi.d.cts} +3 -3
- package/dist/{types-public-WADaA-TW.d.cts → types-public-DX3mGqoi.d.ts} +3 -3
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +1 -1
- package/dist/types-public.d.ts +1 -1
- package/dist/types-public.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-EHDOOLWU.js +0 -357
- package/dist/chunk-EHDOOLWU.js.map +0 -1
- package/dist/chunk-GXGEW6T4.js +0 -68
- package/dist/chunk-GXGEW6T4.js.map +0 -1
- package/dist/secrets/index.cjs +0 -3143
- package/dist/secrets/index.cjs.map +0 -1
- package/dist/secrets/index.d.cts +0 -225
- package/dist/secrets/index.d.ts +0 -225
- package/dist/secrets/index.js +0 -14
- package/dist/secrets/index.js.map +0 -1
- /package/dist/{chunk-O4MBO4DJ.js.map → chunk-YPAPL3IC.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '../errors/index.cjs';
|
|
2
|
-
import '../types-public-
|
|
2
|
+
import '../types-public-DX3mGqoi.cjs';
|
|
3
3
|
import '@byteslice/result';
|
|
4
4
|
import '@cipherstash/protect-ffi';
|
|
5
|
-
export { E as Encryption, a as EncryptionClient, n as noClientError } from '../client-
|
|
5
|
+
export { E as Encryption, a as EncryptionClient, n as noClientError } from '../client-DQyqn0oT.cjs';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import '../identity/index.cjs';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '../errors/index.js';
|
|
2
|
-
import '../types-public-
|
|
2
|
+
import '../types-public-DX3mGqoi.js';
|
|
3
3
|
import '@byteslice/result';
|
|
4
4
|
import '@cipherstash/protect-ffi';
|
|
5
|
-
export { E as Encryption, a as EncryptionClient, n as noClientError } from '../client-
|
|
5
|
+
export { E as Encryption, a as EncryptionClient, n as noClientError } from '../client-Dv60lAyy.js';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import '../identity/index.js';
|
package/dist/encryption/index.js
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
Encryption,
|
|
3
3
|
EncryptionClient,
|
|
4
4
|
noClientError
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-YPAPL3IC.js";
|
|
6
6
|
import "../chunk-4RNBI3UH.js";
|
|
7
7
|
import "../chunk-GNLU3I27.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-MD6742R6.js";
|
|
9
9
|
import "../chunk-Q5FTQLYG.js";
|
|
10
10
|
import "../chunk-LBMC4D6D.js";
|
|
11
11
|
export {
|
package/dist/identity/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
loadWorkSpaceId
|
|
3
|
-
} from "../chunk-GXGEW6T4.js";
|
|
4
1
|
import {
|
|
5
2
|
logger
|
|
6
3
|
} from "../chunk-Q5FTQLYG.js";
|
|
@@ -8,6 +5,69 @@ import {
|
|
|
8
5
|
EncryptionErrorTypes
|
|
9
6
|
} from "../chunk-LBMC4D6D.js";
|
|
10
7
|
|
|
8
|
+
// src/utils/config/index.ts
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
function getWorkspaceCrn(tomlString) {
|
|
12
|
+
let currentSection = "";
|
|
13
|
+
let workspaceCrn;
|
|
14
|
+
const lines = tomlString.split(/\r?\n/);
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const trimmedLine = line.trim();
|
|
17
|
+
if (!trimmedLine || trimmedLine.startsWith("#")) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const sectionMatch = trimmedLine.match(/^\[([^\]]+)\]$/);
|
|
21
|
+
if (sectionMatch) {
|
|
22
|
+
currentSection = sectionMatch[1];
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const kvMatch = trimmedLine.match(/^(\w+)\s*=\s*"([^"]+)"$/);
|
|
26
|
+
if (kvMatch) {
|
|
27
|
+
const [_, key, value] = kvMatch;
|
|
28
|
+
if (currentSection === "auth" && key === "workspace_crn") {
|
|
29
|
+
workspaceCrn = value;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return workspaceCrn;
|
|
35
|
+
}
|
|
36
|
+
function extractWorkspaceIdFromCrn(crn) {
|
|
37
|
+
const match = crn.match(/crn:[^:]+:([^:]+)$/);
|
|
38
|
+
if (!match) {
|
|
39
|
+
throw new Error("Invalid CRN format");
|
|
40
|
+
}
|
|
41
|
+
return match[1];
|
|
42
|
+
}
|
|
43
|
+
function loadWorkSpaceId(suppliedCrn) {
|
|
44
|
+
const configPath = path.join(process.cwd(), "cipherstash.toml");
|
|
45
|
+
if (suppliedCrn) {
|
|
46
|
+
return extractWorkspaceIdFromCrn(suppliedCrn);
|
|
47
|
+
}
|
|
48
|
+
if (!fs.existsSync(configPath) && !process.env.CS_WORKSPACE_CRN) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
if (process.env.CS_WORKSPACE_CRN) {
|
|
54
|
+
return extractWorkspaceIdFromCrn(process.env.CS_WORKSPACE_CRN);
|
|
55
|
+
}
|
|
56
|
+
if (!fs.existsSync(configPath)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const tomlString = fs.readFileSync(configPath, "utf8");
|
|
62
|
+
const workspaceCrn = getWorkspaceCrn(tomlString);
|
|
63
|
+
if (!workspaceCrn) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return extractWorkspaceIdFromCrn(workspaceCrn);
|
|
69
|
+
}
|
|
70
|
+
|
|
11
71
|
// src/identity/index.ts
|
|
12
72
|
import { withResult } from "@byteslice/result";
|
|
13
73
|
var LockContext = class {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/identity/index.ts"],"sourcesContent":["import { type EncryptionError, EncryptionErrorTypes } from '@/errors'\nimport { loadWorkSpaceId } from '@/utils/config'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\n\nexport type CtsRegions = 'ap-southeast-2'\n\nexport type IdentifyOptions = {\n fetchFromCts?: boolean\n}\n\nexport type CtsToken = {\n accessToken: string\n expiry: number\n}\n\nexport type Context = {\n identityClaim: string[]\n}\n\nexport type LockContextOptions = {\n context?: Context\n ctsToken?: CtsToken\n}\n\nexport type GetLockContextResponse = {\n ctsToken: CtsToken\n context: Context\n}\n\n/**\n * Manages CipherStash lock contexts for row-level access control.\n *\n * A `LockContext` ties encryption/decryption operations to an authenticated\n * user identity via CTS (CipherStash Token Service). Call {@link identify}\n * with a user's JWT to obtain a CTS token, then pass the `LockContext`\n * to `.withLockContext()` on any encrypt/decrypt operation.\n *\n * @example\n * ```typescript\n * import { LockContext } from \"@cipherstash/stack/identity\"\n *\n * const lc = new LockContext()\n * const identified = await lc.identify(userJwt)\n *\n * if (identified.failure) throw new Error(identified.failure.message)\n *\n * const result = await client\n * .encrypt(value, { column: users.email, table: users })\n * .withLockContext(identified.data)\n * ```\n */\nexport class LockContext {\n private ctsToken: CtsToken | undefined\n private workspaceId: string\n private context: Context\n\n constructor({\n context = { identityClaim: ['sub'] },\n ctsToken,\n }: LockContextOptions = {}) {\n const workspaceId = loadWorkSpaceId()\n\n if (!workspaceId) {\n throw new Error(\n 'You have not defined a workspace ID in your config file, or the CS_WORKSPACE_CRN environment variable.',\n )\n }\n\n if (ctsToken) {\n this.ctsToken = ctsToken\n }\n\n this.workspaceId = workspaceId\n this.context = context\n logger.debug('Successfully initialized the EQL lock context.')\n }\n\n /**\n * Exchange a user's JWT for a CTS token and bind it to this lock context.\n *\n * @param jwtToken - A valid OIDC / JWT token for the current user.\n * @returns A `Result` containing this `LockContext` (now authenticated) or an error.\n *\n * @example\n * ```typescript\n * const lc = new LockContext()\n * const result = await lc.identify(userJwt)\n * if (result.failure) {\n * console.error(\"Auth failed:\", result.failure.message)\n * }\n * ```\n */\n async identify(\n jwtToken: string,\n ): Promise<Result<LockContext, EncryptionError>> {\n const workspaceId = this.workspaceId\n\n const ctsEndpoint =\n process.env.CS_CTS_ENDPOINT ||\n 'https://ap-southeast-2.aws.auth.viturhosted.net'\n\n const ctsFetchResult = await withResult(\n () =>\n fetch(`${ctsEndpoint}/api/authorize`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n workspaceId,\n oidcToken: jwtToken,\n }),\n }),\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n\n if (ctsFetchResult.failure) {\n return ctsFetchResult\n }\n\n const identifiedLockContext = await withResult(\n async () => {\n const ctsToken = (await ctsFetchResult.data.json()) as CtsToken\n\n if (!ctsToken.accessToken) {\n throw new Error(\n 'The response from the CipherStash API did not contain an access token. Please contact support.',\n )\n }\n\n this.ctsToken = ctsToken\n return this\n },\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n\n return identifiedLockContext\n }\n\n /**\n * Retrieve the current CTS token and context for use with encryption operations.\n *\n * Must be called after {@link identify}. Returns the token/context pair that\n * `.withLockContext()` expects.\n *\n * @returns A `Result` containing the CTS token and identity context, or an error\n * if {@link identify} has not been called.\n */\n getLockContext(): Promise<Result<GetLockContextResponse, EncryptionError>> {\n return withResult(\n () => {\n if (!this.ctsToken?.accessToken || !this.ctsToken?.expiry) {\n throw new Error(\n 'The CTS token is not set. Please call identify() with a users JWT token, or pass an existing CTS token to the LockContext constructor before calling getLockContext().',\n )\n }\n\n return {\n context: this.context,\n ctsToken: this.ctsToken,\n }\n },\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n }\n}\n"],"mappings":";;;;;;;;;;;AAGA,SAAsB,kBAAkB;AAiDjC,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY;AAAA,IACV,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE;AAAA,IACnC;AAAA,EACF,IAAwB,CAAC,GAAG;AAC1B,UAAM,cAAc,gBAAgB;AAEpC,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,WAAO,MAAM,gDAAgD;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,SACJ,UAC+C;AAC/C,UAAM,cAAc,KAAK;AAEzB,UAAM,cACJ,QAAQ,IAAI,mBACZ;AAEF,UAAM,iBAAiB,MAAM;AAAA,MAC3B,MACE,MAAM,GAAG,WAAW,kBAAkB;AAAA,QACpC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH,CAAC;AAAA,MACH,CAAC,WAAW;AAAA,QACV,MAAM,qBAAqB;AAAA,QAC3B,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAEA,QAAI,eAAe,SAAS;AAC1B,aAAO;AAAA,IACT;AAEA,UAAM,wBAAwB,MAAM;AAAA,MAClC,YAAY;AACV,cAAM,WAAY,MAAM,eAAe,KAAK,KAAK;AAEjD,YAAI,CAAC,SAAS,aAAa;AACzB,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,aAAK,WAAW;AAChB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,WAAW;AAAA,QACV,MAAM,qBAAqB;AAAA,QAC3B,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,iBAA2E;AACzE,WAAO;AAAA,MACL,MAAM;AACJ,YAAI,CAAC,KAAK,UAAU,eAAe,CAAC,KAAK,UAAU,QAAQ;AACzD,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,UACL,SAAS,KAAK;AAAA,UACd,UAAU,KAAK;AAAA,QACjB;AAAA,MACF;AAAA,MACA,CAAC,WAAW;AAAA,QACV,MAAM,qBAAqB;AAAA,QAC3B,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/config/index.ts","../../src/identity/index.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\n/**\n * A lightweight function that parses a TOML-like string\n * and returns the `workspace_crn` value found under `[auth]`.\n *\n * @param tomlString The contents of the TOML file as a string.\n * @returns The workspace_crn if found, otherwise undefined.\n */\nfunction getWorkspaceCrn(tomlString: string): string | undefined {\n let currentSection = ''\n let workspaceCrn: string | undefined\n\n const lines = tomlString.split(/\\r?\\n/)\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n continue\n }\n\n const sectionMatch = trimmedLine.match(/^\\[([^\\]]+)\\]$/)\n if (sectionMatch) {\n currentSection = sectionMatch[1]\n continue\n }\n\n const kvMatch = trimmedLine.match(/^(\\w+)\\s*=\\s*\"([^\"]+)\"$/)\n if (kvMatch) {\n const [_, key, value] = kvMatch\n\n if (currentSection === 'auth' && key === 'workspace_crn') {\n workspaceCrn = value\n break\n }\n }\n }\n\n return workspaceCrn\n}\n\n/**\n * Extracts the workspace ID from a CRN string.\n * CRN format: crn:region.aws:ID\n *\n * @param crn The CRN string to extract from\n * @returns The workspace ID portion of the CRN\n */\nexport function extractWorkspaceIdFromCrn(crn: string): string {\n const match = crn.match(/crn:[^:]+:([^:]+)$/)\n if (!match) {\n throw new Error('Invalid CRN format')\n }\n return match[1]\n}\n\nexport function loadWorkSpaceId(suppliedCrn?: string): string {\n const configPath = path.join(process.cwd(), 'cipherstash.toml')\n\n if (suppliedCrn) {\n return extractWorkspaceIdFromCrn(suppliedCrn)\n }\n\n if (!fs.existsSync(configPath) && !process.env.CS_WORKSPACE_CRN) {\n throw new Error(\n 'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n )\n }\n\n // Environment variables take precedence over config files\n if (process.env.CS_WORKSPACE_CRN) {\n return extractWorkspaceIdFromCrn(process.env.CS_WORKSPACE_CRN)\n }\n\n if (!fs.existsSync(configPath)) {\n throw new Error(\n 'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n )\n }\n\n const tomlString = fs.readFileSync(configPath, 'utf8')\n const workspaceCrn = getWorkspaceCrn(tomlString)\n\n if (!workspaceCrn) {\n throw new Error(\n 'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n )\n }\n\n return extractWorkspaceIdFromCrn(workspaceCrn)\n}\n","import { type EncryptionError, EncryptionErrorTypes } from '@/errors'\nimport { loadWorkSpaceId } from '@/utils/config'\nimport { logger } from '@/utils/logger'\nimport { type Result, withResult } from '@byteslice/result'\n\nexport type CtsRegions = 'ap-southeast-2'\n\nexport type IdentifyOptions = {\n fetchFromCts?: boolean\n}\n\nexport type CtsToken = {\n accessToken: string\n expiry: number\n}\n\nexport type Context = {\n identityClaim: string[]\n}\n\nexport type LockContextOptions = {\n context?: Context\n ctsToken?: CtsToken\n}\n\nexport type GetLockContextResponse = {\n ctsToken: CtsToken\n context: Context\n}\n\n/**\n * Manages CipherStash lock contexts for row-level access control.\n *\n * A `LockContext` ties encryption/decryption operations to an authenticated\n * user identity via CTS (CipherStash Token Service). Call {@link identify}\n * with a user's JWT to obtain a CTS token, then pass the `LockContext`\n * to `.withLockContext()` on any encrypt/decrypt operation.\n *\n * @example\n * ```typescript\n * import { LockContext } from \"@cipherstash/stack/identity\"\n *\n * const lc = new LockContext()\n * const identified = await lc.identify(userJwt)\n *\n * if (identified.failure) throw new Error(identified.failure.message)\n *\n * const result = await client\n * .encrypt(value, { column: users.email, table: users })\n * .withLockContext(identified.data)\n * ```\n */\nexport class LockContext {\n private ctsToken: CtsToken | undefined\n private workspaceId: string\n private context: Context\n\n constructor({\n context = { identityClaim: ['sub'] },\n ctsToken,\n }: LockContextOptions = {}) {\n const workspaceId = loadWorkSpaceId()\n\n if (!workspaceId) {\n throw new Error(\n 'You have not defined a workspace ID in your config file, or the CS_WORKSPACE_CRN environment variable.',\n )\n }\n\n if (ctsToken) {\n this.ctsToken = ctsToken\n }\n\n this.workspaceId = workspaceId\n this.context = context\n logger.debug('Successfully initialized the EQL lock context.')\n }\n\n /**\n * Exchange a user's JWT for a CTS token and bind it to this lock context.\n *\n * @param jwtToken - A valid OIDC / JWT token for the current user.\n * @returns A `Result` containing this `LockContext` (now authenticated) or an error.\n *\n * @example\n * ```typescript\n * const lc = new LockContext()\n * const result = await lc.identify(userJwt)\n * if (result.failure) {\n * console.error(\"Auth failed:\", result.failure.message)\n * }\n * ```\n */\n async identify(\n jwtToken: string,\n ): Promise<Result<LockContext, EncryptionError>> {\n const workspaceId = this.workspaceId\n\n const ctsEndpoint =\n process.env.CS_CTS_ENDPOINT ||\n 'https://ap-southeast-2.aws.auth.viturhosted.net'\n\n const ctsFetchResult = await withResult(\n () =>\n fetch(`${ctsEndpoint}/api/authorize`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n workspaceId,\n oidcToken: jwtToken,\n }),\n }),\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n\n if (ctsFetchResult.failure) {\n return ctsFetchResult\n }\n\n const identifiedLockContext = await withResult(\n async () => {\n const ctsToken = (await ctsFetchResult.data.json()) as CtsToken\n\n if (!ctsToken.accessToken) {\n throw new Error(\n 'The response from the CipherStash API did not contain an access token. Please contact support.',\n )\n }\n\n this.ctsToken = ctsToken\n return this\n },\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n\n return identifiedLockContext\n }\n\n /**\n * Retrieve the current CTS token and context for use with encryption operations.\n *\n * Must be called after {@link identify}. Returns the token/context pair that\n * `.withLockContext()` expects.\n *\n * @returns A `Result` containing the CTS token and identity context, or an error\n * if {@link identify} has not been called.\n */\n getLockContext(): Promise<Result<GetLockContextResponse, EncryptionError>> {\n return withResult(\n () => {\n if (!this.ctsToken?.accessToken || !this.ctsToken?.expiry) {\n throw new Error(\n 'The CTS token is not set. Please call identify() with a users JWT token, or pass an existing CTS token to the LockContext constructor before calling getLockContext().',\n )\n }\n\n return {\n context: this.context,\n ctsToken: this.ctsToken,\n }\n },\n (error) => ({\n type: EncryptionErrorTypes.CtsTokenError,\n message: error.message,\n }),\n )\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,21 +15,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.ts
|
|
31
21
|
var index_exports = {};
|
|
32
22
|
__export(index_exports, {
|
|
33
23
|
Encryption: () => Encryption,
|
|
34
|
-
Secrets: () => Secrets,
|
|
35
24
|
encryptedColumn: () => encryptedColumn,
|
|
36
25
|
encryptedField: () => encryptedField,
|
|
37
26
|
encryptedTable: () => encryptedTable,
|
|
@@ -920,11 +909,11 @@ var import_result3 = require("@byteslice/result");
|
|
|
920
909
|
|
|
921
910
|
// src/encryption/helpers/model-helpers.ts
|
|
922
911
|
var import_protect_ffi4 = require("@cipherstash/protect-ffi");
|
|
923
|
-
function setNestedValue(obj,
|
|
912
|
+
function setNestedValue(obj, path, value) {
|
|
924
913
|
const FORBIDDEN_KEYS = ["__proto__", "prototype", "constructor"];
|
|
925
914
|
let current = obj;
|
|
926
|
-
for (let i = 0; i <
|
|
927
|
-
const part =
|
|
915
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
916
|
+
const part = path[i];
|
|
928
917
|
if (FORBIDDEN_KEYS.includes(part)) {
|
|
929
918
|
throw new Error(`[encryption]: Forbidden key "${part}" in field path`);
|
|
930
919
|
}
|
|
@@ -933,7 +922,7 @@ function setNestedValue(obj, path2, value) {
|
|
|
933
922
|
}
|
|
934
923
|
current = current[part];
|
|
935
924
|
}
|
|
936
|
-
const lastKey =
|
|
925
|
+
const lastKey = path[path.length - 1];
|
|
937
926
|
if (FORBIDDEN_KEYS.includes(lastKey)) {
|
|
938
927
|
throw new Error(`[encryption]: Forbidden key "${lastKey}" in field path`);
|
|
939
928
|
}
|
|
@@ -1010,7 +999,7 @@ function prepareFieldsForEncryption(model, table) {
|
|
|
1010
999
|
continue;
|
|
1011
1000
|
}
|
|
1012
1001
|
if (typeof value === "object" && !isEncryptedPayload(value) && !columnPaths2.includes(fullKey)) {
|
|
1013
|
-
if (columnPaths2.some((
|
|
1002
|
+
if (columnPaths2.some((path) => path.startsWith(fullKey))) {
|
|
1014
1003
|
processNestedFields(
|
|
1015
1004
|
value,
|
|
1016
1005
|
fullKey,
|
|
@@ -1188,7 +1177,7 @@ function prepareBulkModelsForOperation(models, table) {
|
|
|
1188
1177
|
continue;
|
|
1189
1178
|
}
|
|
1190
1179
|
if (typeof value === "object" && !isEncryptedPayload(value) && !columnPaths.includes(fullKey)) {
|
|
1191
|
-
if (columnPaths.some((
|
|
1180
|
+
if (columnPaths.some((path) => path.startsWith(fullKey))) {
|
|
1192
1181
|
processNestedFields(
|
|
1193
1182
|
value,
|
|
1194
1183
|
fullKey,
|
|
@@ -2798,357 +2787,9 @@ var Encryption = async (config) => {
|
|
|
2798
2787
|
}
|
|
2799
2788
|
return result.data;
|
|
2800
2789
|
};
|
|
2801
|
-
|
|
2802
|
-
// src/utils/config/index.ts
|
|
2803
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
2804
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
2805
|
-
function extractWorkspaceIdFromCrn(crn) {
|
|
2806
|
-
const match = crn.match(/crn:[^:]+:([^:]+)$/);
|
|
2807
|
-
if (!match) {
|
|
2808
|
-
throw new Error("Invalid CRN format");
|
|
2809
|
-
}
|
|
2810
|
-
return match[1];
|
|
2811
|
-
}
|
|
2812
|
-
|
|
2813
|
-
// src/secrets/index.ts
|
|
2814
|
-
var Secrets = class {
|
|
2815
|
-
encryptionClient = null;
|
|
2816
|
-
config;
|
|
2817
|
-
apiBaseUrl = process.env.STASH_API_URL || "https://dashboard.cipherstash.com/api/secrets";
|
|
2818
|
-
secretsSchema = encryptedTable("secrets", {
|
|
2819
|
-
value: encryptedColumn("value")
|
|
2820
|
-
});
|
|
2821
|
-
constructor(config) {
|
|
2822
|
-
const workspaceCRN = config.workspaceCRN ?? process.env.CS_WORKSPACE_CRN;
|
|
2823
|
-
const clientId = config.clientId ?? process.env.CS_CLIENT_ID;
|
|
2824
|
-
const clientKey = config.clientKey ?? process.env.CS_CLIENT_KEY;
|
|
2825
|
-
const accessKey = config.accessKey ?? process.env.CS_CLIENT_ACCESS_KEY;
|
|
2826
|
-
if (!workspaceCRN || !clientId || !clientKey || !accessKey) {
|
|
2827
|
-
throw new Error(
|
|
2828
|
-
"Missing required configuration or environment variables."
|
|
2829
|
-
);
|
|
2830
|
-
}
|
|
2831
|
-
this.config = {
|
|
2832
|
-
environment: config.environment,
|
|
2833
|
-
workspaceCRN,
|
|
2834
|
-
clientId,
|
|
2835
|
-
clientKey,
|
|
2836
|
-
accessKey
|
|
2837
|
-
};
|
|
2838
|
-
}
|
|
2839
|
-
initPromise = null;
|
|
2840
|
-
/**
|
|
2841
|
-
* Initialize the Secrets client and underlying Encryption client
|
|
2842
|
-
*/
|
|
2843
|
-
async ensureInitialized() {
|
|
2844
|
-
if (!this.initPromise) {
|
|
2845
|
-
this.initPromise = this._doInit();
|
|
2846
|
-
}
|
|
2847
|
-
return this.initPromise;
|
|
2848
|
-
}
|
|
2849
|
-
async _doInit() {
|
|
2850
|
-
logger.debug("Initializing the Secrets client.");
|
|
2851
|
-
this.encryptionClient = await Encryption({
|
|
2852
|
-
schemas: [this.secretsSchema],
|
|
2853
|
-
config: {
|
|
2854
|
-
workspaceCrn: this.config.workspaceCRN,
|
|
2855
|
-
clientId: this.config.clientId,
|
|
2856
|
-
clientKey: this.config.clientKey,
|
|
2857
|
-
accessKey: this.config.accessKey,
|
|
2858
|
-
keyset: { name: this.config.environment }
|
|
2859
|
-
}
|
|
2860
|
-
});
|
|
2861
|
-
logger.debug("Successfully initialized the Secrets client.");
|
|
2862
|
-
}
|
|
2863
|
-
/**
|
|
2864
|
-
* Get the authorization header for API requests
|
|
2865
|
-
*/
|
|
2866
|
-
getAuthHeader() {
|
|
2867
|
-
return `Bearer ${this.config.accessKey}`;
|
|
2868
|
-
}
|
|
2869
|
-
/**
|
|
2870
|
-
* Make an API request with error handling.
|
|
2871
|
-
*
|
|
2872
|
-
* For GET requests, `params` are appended as URL query parameters.
|
|
2873
|
-
* For POST requests, `body` is sent as JSON in the request body.
|
|
2874
|
-
*/
|
|
2875
|
-
async apiRequest(method, path2, options) {
|
|
2876
|
-
try {
|
|
2877
|
-
let url = `${this.apiBaseUrl}${path2}`;
|
|
2878
|
-
if (options?.params) {
|
|
2879
|
-
const searchParams = new URLSearchParams(options.params);
|
|
2880
|
-
url = `${url}?${searchParams.toString()}`;
|
|
2881
|
-
}
|
|
2882
|
-
logger.debug(`Secrets API request: ${method} ${path2}`);
|
|
2883
|
-
const headers = {
|
|
2884
|
-
"Content-Type": "application/json",
|
|
2885
|
-
Authorization: this.getAuthHeader()
|
|
2886
|
-
};
|
|
2887
|
-
const response = await fetch(url, {
|
|
2888
|
-
method,
|
|
2889
|
-
headers,
|
|
2890
|
-
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
2891
|
-
});
|
|
2892
|
-
if (!response.ok) {
|
|
2893
|
-
const errorText = await response.text();
|
|
2894
|
-
let errorMessage = `API request failed with status ${response.status}`;
|
|
2895
|
-
try {
|
|
2896
|
-
const errorJson = JSON.parse(errorText);
|
|
2897
|
-
errorMessage = errorJson.message || errorJson.error || errorMessage;
|
|
2898
|
-
} catch {
|
|
2899
|
-
errorMessage = errorText || errorMessage;
|
|
2900
|
-
}
|
|
2901
|
-
logger.error(`Secrets API error on ${method} ${path2}: ${errorMessage}`);
|
|
2902
|
-
return {
|
|
2903
|
-
failure: {
|
|
2904
|
-
type: "ApiError",
|
|
2905
|
-
message: errorMessage
|
|
2906
|
-
}
|
|
2907
|
-
};
|
|
2908
|
-
}
|
|
2909
|
-
logger.debug(`Secrets API request successful: ${method} ${path2}`);
|
|
2910
|
-
const data = await response.json();
|
|
2911
|
-
return { data };
|
|
2912
|
-
} catch (error) {
|
|
2913
|
-
const message = error instanceof Error ? error.message : "Unknown network error occurred";
|
|
2914
|
-
logger.error(`Secrets network error on ${method} ${path2}: ${message}`);
|
|
2915
|
-
return {
|
|
2916
|
-
failure: {
|
|
2917
|
-
type: "NetworkError",
|
|
2918
|
-
message
|
|
2919
|
-
}
|
|
2920
|
-
};
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
/**
|
|
2924
|
-
* Store an encrypted secret in the vault.
|
|
2925
|
-
* The value is encrypted locally before being sent to the API.
|
|
2926
|
-
*
|
|
2927
|
-
* API: POST /api/secrets/set
|
|
2928
|
-
*
|
|
2929
|
-
* @param name - The name of the secret
|
|
2930
|
-
* @param value - The plaintext value to encrypt and store
|
|
2931
|
-
* @returns A Result containing the API response or an error
|
|
2932
|
-
*/
|
|
2933
|
-
async set(name, value) {
|
|
2934
|
-
logger.debug("Setting secret");
|
|
2935
|
-
await this.ensureInitialized();
|
|
2936
|
-
if (!this.encryptionClient) {
|
|
2937
|
-
return {
|
|
2938
|
-
failure: {
|
|
2939
|
-
type: "ClientError",
|
|
2940
|
-
message: "Failed to initialize Encryption client"
|
|
2941
|
-
}
|
|
2942
|
-
};
|
|
2943
|
-
}
|
|
2944
|
-
const encryptResult = await this.encryptionClient.encrypt(value, {
|
|
2945
|
-
column: this.secretsSchema.value,
|
|
2946
|
-
table: this.secretsSchema
|
|
2947
|
-
});
|
|
2948
|
-
if (encryptResult.failure) {
|
|
2949
|
-
logger.error("Failed to encrypt secret");
|
|
2950
|
-
return {
|
|
2951
|
-
failure: {
|
|
2952
|
-
type: "EncryptionError",
|
|
2953
|
-
message: encryptResult.failure.message
|
|
2954
|
-
}
|
|
2955
|
-
};
|
|
2956
|
-
}
|
|
2957
|
-
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
2958
|
-
return await this.apiRequest("POST", "/set", {
|
|
2959
|
-
body: {
|
|
2960
|
-
workspaceId,
|
|
2961
|
-
environment: this.config.environment,
|
|
2962
|
-
name,
|
|
2963
|
-
encryptedValue: encryptedToPgComposite(encryptResult.data)
|
|
2964
|
-
}
|
|
2965
|
-
});
|
|
2966
|
-
}
|
|
2967
|
-
/**
|
|
2968
|
-
* Retrieve and decrypt a secret from the vault.
|
|
2969
|
-
* The secret is decrypted locally after retrieval.
|
|
2970
|
-
*
|
|
2971
|
-
* API: GET /api/secrets/get?workspaceId=...&environment=...&name=...
|
|
2972
|
-
*
|
|
2973
|
-
* @param name - The name of the secret to retrieve
|
|
2974
|
-
* @returns A Result containing the decrypted value or an error
|
|
2975
|
-
*/
|
|
2976
|
-
async get(name) {
|
|
2977
|
-
logger.debug("Getting secret");
|
|
2978
|
-
await this.ensureInitialized();
|
|
2979
|
-
if (!this.encryptionClient) {
|
|
2980
|
-
return {
|
|
2981
|
-
failure: {
|
|
2982
|
-
type: "ClientError",
|
|
2983
|
-
message: "Failed to initialize Encryption client"
|
|
2984
|
-
}
|
|
2985
|
-
};
|
|
2986
|
-
}
|
|
2987
|
-
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
2988
|
-
const apiResult = await this.apiRequest("GET", "/get", {
|
|
2989
|
-
params: {
|
|
2990
|
-
workspaceId,
|
|
2991
|
-
environment: this.config.environment,
|
|
2992
|
-
name
|
|
2993
|
-
}
|
|
2994
|
-
});
|
|
2995
|
-
if (apiResult.failure) {
|
|
2996
|
-
return apiResult;
|
|
2997
|
-
}
|
|
2998
|
-
const decryptResult = await this.encryptionClient.decrypt(
|
|
2999
|
-
apiResult.data.encryptedValue.data
|
|
3000
|
-
);
|
|
3001
|
-
if (decryptResult.failure) {
|
|
3002
|
-
logger.error("Failed to decrypt secret");
|
|
3003
|
-
return {
|
|
3004
|
-
failure: {
|
|
3005
|
-
type: "DecryptionError",
|
|
3006
|
-
message: decryptResult.failure.message
|
|
3007
|
-
}
|
|
3008
|
-
};
|
|
3009
|
-
}
|
|
3010
|
-
if (typeof decryptResult.data !== "string") {
|
|
3011
|
-
logger.error("Decrypted secret value is not a string");
|
|
3012
|
-
return {
|
|
3013
|
-
failure: {
|
|
3014
|
-
type: "DecryptionError",
|
|
3015
|
-
message: "Decrypted value is not a string"
|
|
3016
|
-
}
|
|
3017
|
-
};
|
|
3018
|
-
}
|
|
3019
|
-
return { data: decryptResult.data };
|
|
3020
|
-
}
|
|
3021
|
-
/**
|
|
3022
|
-
* Retrieve and decrypt many secrets from the vault.
|
|
3023
|
-
* The secrets are decrypted locally after retrieval.
|
|
3024
|
-
* This method only triggers a single network request to the ZeroKMS.
|
|
3025
|
-
*
|
|
3026
|
-
* API: GET /api/secrets/get-many?workspaceId=...&environment=...&names=name1,name2,...
|
|
3027
|
-
*
|
|
3028
|
-
* Constraints:
|
|
3029
|
-
* - Minimum 2 secret names required
|
|
3030
|
-
* - Maximum 100 secret names per request
|
|
3031
|
-
*
|
|
3032
|
-
* @param names - The names of the secrets to retrieve (min 2, max 100)
|
|
3033
|
-
* @returns A Result containing an object mapping secret names to their decrypted values
|
|
3034
|
-
*/
|
|
3035
|
-
async getMany(names) {
|
|
3036
|
-
logger.debug(`Getting ${names.length} secrets.`);
|
|
3037
|
-
await this.ensureInitialized();
|
|
3038
|
-
if (!this.encryptionClient) {
|
|
3039
|
-
return {
|
|
3040
|
-
failure: {
|
|
3041
|
-
type: "ClientError",
|
|
3042
|
-
message: "Failed to initialize Encryption client"
|
|
3043
|
-
}
|
|
3044
|
-
};
|
|
3045
|
-
}
|
|
3046
|
-
if (names.length < 2) {
|
|
3047
|
-
return {
|
|
3048
|
-
failure: {
|
|
3049
|
-
type: "ClientError",
|
|
3050
|
-
message: "At least 2 secret names are required for getMany"
|
|
3051
|
-
}
|
|
3052
|
-
};
|
|
3053
|
-
}
|
|
3054
|
-
if (names.length > 100) {
|
|
3055
|
-
return {
|
|
3056
|
-
failure: {
|
|
3057
|
-
type: "ClientError",
|
|
3058
|
-
message: "Maximum 100 secret names per request"
|
|
3059
|
-
}
|
|
3060
|
-
};
|
|
3061
|
-
}
|
|
3062
|
-
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3063
|
-
const apiResult = await this.apiRequest(
|
|
3064
|
-
"GET",
|
|
3065
|
-
"/get-many",
|
|
3066
|
-
{
|
|
3067
|
-
params: {
|
|
3068
|
-
workspaceId,
|
|
3069
|
-
environment: this.config.environment,
|
|
3070
|
-
names: names.join(",")
|
|
3071
|
-
}
|
|
3072
|
-
}
|
|
3073
|
-
);
|
|
3074
|
-
if (apiResult.failure) {
|
|
3075
|
-
return apiResult;
|
|
3076
|
-
}
|
|
3077
|
-
const dataToDecrypt = apiResult.data.map((item) => ({
|
|
3078
|
-
name: item.name,
|
|
3079
|
-
value: item.encryptedValue.data
|
|
3080
|
-
}));
|
|
3081
|
-
const decryptResult = await this.encryptionClient.bulkDecryptModels(dataToDecrypt);
|
|
3082
|
-
if (decryptResult.failure) {
|
|
3083
|
-
logger.error(
|
|
3084
|
-
`Failed to decrypt secrets: ${decryptResult.failure.message}`
|
|
3085
|
-
);
|
|
3086
|
-
return {
|
|
3087
|
-
failure: {
|
|
3088
|
-
type: "DecryptionError",
|
|
3089
|
-
message: decryptResult.failure.message
|
|
3090
|
-
}
|
|
3091
|
-
};
|
|
3092
|
-
}
|
|
3093
|
-
const decryptedSecrets = decryptResult.data;
|
|
3094
|
-
const secretsMap = {};
|
|
3095
|
-
for (const secret of decryptedSecrets) {
|
|
3096
|
-
if (secret.name && secret.value) {
|
|
3097
|
-
secretsMap[secret.name] = secret.value;
|
|
3098
|
-
}
|
|
3099
|
-
}
|
|
3100
|
-
return { data: secretsMap };
|
|
3101
|
-
}
|
|
3102
|
-
/**
|
|
3103
|
-
* List all secrets in the environment.
|
|
3104
|
-
* Only names and metadata are returned; values remain encrypted.
|
|
3105
|
-
*
|
|
3106
|
-
* API: GET /api/secrets/list?workspaceId=...&environment=...
|
|
3107
|
-
*
|
|
3108
|
-
* @returns A Result containing the list of secrets or an error
|
|
3109
|
-
*/
|
|
3110
|
-
async list() {
|
|
3111
|
-
logger.debug("Listing secrets.");
|
|
3112
|
-
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3113
|
-
const apiResult = await this.apiRequest(
|
|
3114
|
-
"GET",
|
|
3115
|
-
"/list",
|
|
3116
|
-
{
|
|
3117
|
-
params: {
|
|
3118
|
-
workspaceId,
|
|
3119
|
-
environment: this.config.environment
|
|
3120
|
-
}
|
|
3121
|
-
}
|
|
3122
|
-
);
|
|
3123
|
-
if (apiResult.failure) {
|
|
3124
|
-
return apiResult;
|
|
3125
|
-
}
|
|
3126
|
-
return { data: apiResult.data.secrets };
|
|
3127
|
-
}
|
|
3128
|
-
/**
|
|
3129
|
-
* Delete a secret from the vault.
|
|
3130
|
-
*
|
|
3131
|
-
* API: POST /api/secrets/delete
|
|
3132
|
-
*
|
|
3133
|
-
* @param name - The name of the secret to delete
|
|
3134
|
-
* @returns A Result containing the API response or an error
|
|
3135
|
-
*/
|
|
3136
|
-
async delete(name) {
|
|
3137
|
-
logger.debug("Deleting secret");
|
|
3138
|
-
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3139
|
-
return await this.apiRequest("POST", "/delete", {
|
|
3140
|
-
body: {
|
|
3141
|
-
workspaceId,
|
|
3142
|
-
environment: this.config.environment,
|
|
3143
|
-
name
|
|
3144
|
-
}
|
|
3145
|
-
});
|
|
3146
|
-
}
|
|
3147
|
-
};
|
|
3148
2790
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3149
2791
|
0 && (module.exports = {
|
|
3150
2792
|
Encryption,
|
|
3151
|
-
Secrets,
|
|
3152
2793
|
encryptedColumn,
|
|
3153
2794
|
encryptedField,
|
|
3154
2795
|
encryptedTable,
|