@cipherstash/stack 0.3.0 → 0.5.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 +19 -0
- package/README.md +10 -37
- package/dist/bin/stash.js +261 -320
- package/dist/bin/stash.js.map +1 -1
- package/dist/{chunk-SUYMGQBY.js → chunk-4RNBI3UH.js} +1 -7
- package/dist/chunk-4RNBI3UH.js.map +1 -0
- package/dist/{chunk-OAPLZLR5.js → chunk-GXGEW6T4.js} +2 -76
- package/dist/chunk-GXGEW6T4.js.map +1 -0
- package/dist/{chunk-JLI27P46.js → chunk-HCL75LXQ.js} +1 -1
- package/dist/chunk-HCL75LXQ.js.map +1 -0
- package/dist/chunk-LBMC4D6D.js +19 -0
- package/dist/chunk-LBMC4D6D.js.map +1 -0
- package/dist/chunk-Q5FTQLYG.js +68 -0
- package/dist/chunk-Q5FTQLYG.js.map +1 -0
- package/dist/{chunk-MW6D52V2.js → chunk-TGUELLJS.js} +58 -150
- package/dist/chunk-TGUELLJS.js.map +1 -0
- package/dist/{chunk-TBAIVO6T.js → chunk-Y35W4WFN.js} +6 -6
- package/dist/chunk-Y35W4WFN.js.map +1 -0
- package/dist/chunk-YLISU7FD.js +357 -0
- package/dist/chunk-YLISU7FD.js.map +1 -0
- package/dist/{client-Bf0Xw2xo.d.cts → client-BFrHTgC6.d.ts} +50 -18
- package/dist/{client-Kfp8OsPB.d.ts → client-BVQvgvdY.d.cts} +50 -18
- package/dist/client.cjs +5 -5
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/client.js +1 -1
- package/dist/drizzle/index.cjs +5 -5
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +14 -6
- package/dist/drizzle/index.d.ts +14 -6
- package/dist/drizzle/index.js +4 -4
- package/dist/drizzle/index.js.map +1 -1
- package/dist/dynamodb/index.cjs +68 -0
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +4 -4
- package/dist/dynamodb/index.d.ts +4 -4
- package/dist/dynamodb/index.js +9 -0
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/encryption/index.cjs +2572 -0
- package/dist/encryption/index.cjs.map +1 -0
- package/dist/encryption/index.d.cts +7 -0
- package/dist/encryption/index.d.ts +7 -0
- package/dist/encryption/index.js +17 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/errors/index.cjs +44 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.cts +94 -0
- package/dist/errors/index.d.ts +94 -0
- package/dist/errors/index.js +9 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/identity/index.cjs +21 -13
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +78 -2
- package/dist/identity/index.d.ts +78 -2
- package/dist/identity/index.js +7 -3
- package/dist/identity/index.js.map +1 -1
- package/dist/index.cjs +425 -182
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -19
- package/dist/index.d.ts +21 -19
- package/dist/index.js +15 -9
- package/dist/schema/index.cjs +5 -5
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +1 -2
- package/dist/schema/index.d.ts +1 -2
- package/dist/schema/index.js +1 -1
- package/dist/secrets/index.cjs +116 -180
- package/dist/secrets/index.cjs.map +1 -1
- package/dist/secrets/index.d.cts +4 -6
- package/dist/secrets/index.d.ts +4 -6
- package/dist/secrets/index.js +9 -318
- package/dist/secrets/index.js.map +1 -1
- package/dist/supabase/index.cjs +86 -3
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.d.cts +4 -4
- package/dist/supabase/index.d.ts +4 -4
- package/dist/supabase/index.js +26 -3
- package/dist/supabase/index.js.map +1 -1
- package/dist/{types-public-0CzBV45X.d.cts → types-public-dKxDzTIL.d.cts} +47 -34
- package/dist/{types-public-0CzBV45X.d.ts → types-public-dKxDzTIL.d.ts} +47 -34
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +1 -2
- package/dist/types-public.d.ts +1 -2
- package/dist/types-public.js +1 -1
- package/package.json +30 -2
- package/dist/chunk-JLI27P46.js.map +0 -1
- package/dist/chunk-MW6D52V2.js.map +0 -1
- package/dist/chunk-OAPLZLR5.js.map +0 -1
- package/dist/chunk-SUYMGQBY.js.map +0 -1
- package/dist/chunk-TBAIVO6T.js.map +0 -1
- package/dist/index-9-Ya3fDK.d.cts +0 -169
- package/dist/index-9-Ya3fDK.d.ts +0 -169
package/dist/index.cjs
CHANGED
|
@@ -31,31 +31,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Encryption: () => Encryption,
|
|
34
|
-
|
|
34
|
+
Secrets: () => Secrets,
|
|
35
35
|
encryptedColumn: () => encryptedColumn,
|
|
36
36
|
encryptedField: () => encryptedField,
|
|
37
37
|
encryptedTable: () => encryptedTable,
|
|
38
|
-
|
|
38
|
+
encryptedToPgComposite: () => encryptedToPgComposite,
|
|
39
|
+
isEncryptedPayload: () => isEncryptedPayload
|
|
39
40
|
});
|
|
40
41
|
module.exports = __toCommonJS(index_exports);
|
|
41
42
|
|
|
42
|
-
// src/errors/index.ts
|
|
43
|
-
var EncryptionErrorTypes = {
|
|
44
|
-
ClientInitError: "ClientInitError",
|
|
45
|
-
EncryptionError: "EncryptionError",
|
|
46
|
-
DecryptionError: "DecryptionError",
|
|
47
|
-
LockContextError: "LockContextError",
|
|
48
|
-
CtsTokenError: "CtsTokenError"
|
|
49
|
-
};
|
|
50
|
-
function getErrorMessage(error) {
|
|
51
|
-
if (error instanceof Error) return error.message;
|
|
52
|
-
if (typeof error === "string") return error;
|
|
53
|
-
return String(error);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
43
|
// src/schema/index.ts
|
|
57
44
|
var import_zod = require("zod");
|
|
58
|
-
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json"]).default("
|
|
45
|
+
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
59
46
|
var tokenFilterSchema = import_zod.z.object({
|
|
60
47
|
kind: import_zod.z.literal("downcase")
|
|
61
48
|
});
|
|
@@ -103,7 +90,7 @@ var EncryptedField = class {
|
|
|
103
90
|
castAsValue;
|
|
104
91
|
constructor(valueName) {
|
|
105
92
|
this.valueName = valueName;
|
|
106
|
-
this.castAsValue = "
|
|
93
|
+
this.castAsValue = "text";
|
|
107
94
|
}
|
|
108
95
|
/**
|
|
109
96
|
* Set or override the plaintext data type for this field.
|
|
@@ -112,7 +99,7 @@ var EncryptedField = class {
|
|
|
112
99
|
* a different type so the encryption layer knows how to encode the plaintext
|
|
113
100
|
* before encrypting.
|
|
114
101
|
*
|
|
115
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
102
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
|
|
116
103
|
* @returns This `EncryptedField` instance for method chaining.
|
|
117
104
|
*
|
|
118
105
|
* @example
|
|
@@ -128,7 +115,7 @@ var EncryptedField = class {
|
|
|
128
115
|
}
|
|
129
116
|
build() {
|
|
130
117
|
return {
|
|
131
|
-
cast_as: this.castAsValue,
|
|
118
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
132
119
|
indexes: {}
|
|
133
120
|
};
|
|
134
121
|
}
|
|
@@ -282,7 +269,7 @@ var EncryptedColumn = class {
|
|
|
282
269
|
}
|
|
283
270
|
build() {
|
|
284
271
|
return {
|
|
285
|
-
cast_as: this.castAsValue,
|
|
272
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
286
273
|
indexes: this.indexesValue
|
|
287
274
|
};
|
|
288
275
|
}
|
|
@@ -380,6 +367,15 @@ function buildEncryptConfig(...protectTables) {
|
|
|
380
367
|
return config;
|
|
381
368
|
}
|
|
382
369
|
|
|
370
|
+
// src/errors/index.ts
|
|
371
|
+
var EncryptionErrorTypes = {
|
|
372
|
+
ClientInitError: "ClientInitError",
|
|
373
|
+
EncryptionError: "EncryptionError",
|
|
374
|
+
DecryptionError: "DecryptionError",
|
|
375
|
+
LockContextError: "LockContextError",
|
|
376
|
+
CtsTokenError: "CtsTokenError"
|
|
377
|
+
};
|
|
378
|
+
|
|
383
379
|
// src/utils/config/index.ts
|
|
384
380
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
385
381
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -445,25 +441,33 @@ function loadWorkSpaceId(suppliedCrn) {
|
|
|
445
441
|
|
|
446
442
|
// src/utils/logger/index.ts
|
|
447
443
|
var import_evlog = require("evlog");
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
444
|
+
var validLevels = ["debug", "info", "error"];
|
|
445
|
+
function levelFromEnv() {
|
|
446
|
+
const env = process.env.STASH_STACK_LOG;
|
|
447
|
+
if (env && validLevels.includes(env)) return env;
|
|
448
|
+
return "error";
|
|
449
|
+
}
|
|
450
|
+
function samplingRatesForLevel(level) {
|
|
451
|
+
switch (level) {
|
|
452
|
+
case "debug":
|
|
453
|
+
return { debug: 100, info: 100, warn: 100, error: 100 };
|
|
454
|
+
case "info":
|
|
455
|
+
return { debug: 0, info: 100, warn: 100, error: 100 };
|
|
456
|
+
case "error":
|
|
457
|
+
default:
|
|
458
|
+
return { debug: 0, info: 0, warn: 0, error: 100 };
|
|
459
|
+
}
|
|
455
460
|
}
|
|
456
461
|
var initialized = false;
|
|
457
|
-
function initStackLogger(
|
|
462
|
+
function initStackLogger() {
|
|
458
463
|
if (initialized) return;
|
|
459
464
|
initialized = true;
|
|
460
|
-
const
|
|
465
|
+
const level = levelFromEnv();
|
|
466
|
+
const rates = samplingRatesForLevel(level);
|
|
461
467
|
(0, import_evlog.initLogger)({
|
|
462
468
|
env: { service: "@cipherstash/stack" },
|
|
463
|
-
enabled:
|
|
464
|
-
|
|
465
|
-
...rates && { sampling: { rates } },
|
|
466
|
-
...config?.drain && { drain: config.drain }
|
|
469
|
+
enabled: true,
|
|
470
|
+
sampling: { rates }
|
|
467
471
|
});
|
|
468
472
|
}
|
|
469
473
|
initStackLogger();
|
|
@@ -501,18 +505,18 @@ var logger = {
|
|
|
501
505
|
// src/encryption/index.ts
|
|
502
506
|
var import_result11 = require("@byteslice/result");
|
|
503
507
|
var import_protect_ffi9 = require("@cipherstash/protect-ffi");
|
|
508
|
+
var import_uuid = require("uuid");
|
|
504
509
|
|
|
505
510
|
// src/encryption/helpers/index.ts
|
|
511
|
+
function encryptedToPgComposite(obj) {
|
|
512
|
+
return {
|
|
513
|
+
data: obj
|
|
514
|
+
};
|
|
515
|
+
}
|
|
506
516
|
function encryptedToCompositeLiteral(obj) {
|
|
507
|
-
if (obj === null) {
|
|
508
|
-
throw new Error("encryptedToCompositeLiteral: obj cannot be null");
|
|
509
|
-
}
|
|
510
517
|
return `(${JSON.stringify(JSON.stringify(obj))})`;
|
|
511
518
|
}
|
|
512
519
|
function encryptedToEscapedCompositeLiteral(obj) {
|
|
513
|
-
if (obj === null) {
|
|
514
|
-
throw new Error("encryptedToEscapedCompositeLiteral: obj cannot be null");
|
|
515
|
-
}
|
|
516
520
|
return JSON.stringify(encryptedToCompositeLiteral(obj));
|
|
517
521
|
}
|
|
518
522
|
function formatEncryptedResult(encrypted, returnType) {
|
|
@@ -695,18 +699,6 @@ var EncryptionOperation = class {
|
|
|
695
699
|
};
|
|
696
700
|
|
|
697
701
|
// src/encryption/operations/batch-encrypt-query.ts
|
|
698
|
-
function filterNullTerms(terms) {
|
|
699
|
-
const nullIndices = /* @__PURE__ */ new Set();
|
|
700
|
-
const nonNullTerms = [];
|
|
701
|
-
terms.forEach((term, index) => {
|
|
702
|
-
if (term.value === null || term.value === void 0) {
|
|
703
|
-
nullIndices.add(index);
|
|
704
|
-
} else {
|
|
705
|
-
nonNullTerms.push({ term, originalIndex: index });
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
return { nullIndices, nonNullTerms };
|
|
709
|
-
}
|
|
710
702
|
function buildQueryPayload(term, lockContext) {
|
|
711
703
|
assertValidNumericValue(term.value);
|
|
712
704
|
const { indexType, queryOp } = resolveIndexType(
|
|
@@ -727,13 +719,10 @@ function buildQueryPayload(term, lockContext) {
|
|
|
727
719
|
}
|
|
728
720
|
return payload;
|
|
729
721
|
}
|
|
730
|
-
function assembleResults(
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
results[originalIndex] = formatEncryptedResult(encrypted, term.returnType);
|
|
735
|
-
});
|
|
736
|
-
return results;
|
|
722
|
+
function assembleResults(terms, encryptedValues) {
|
|
723
|
+
return terms.map(
|
|
724
|
+
(term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
|
|
725
|
+
);
|
|
737
726
|
}
|
|
738
727
|
var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
739
728
|
constructor(client, terms) {
|
|
@@ -760,23 +749,18 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
|
760
749
|
log.emit();
|
|
761
750
|
return { data: [] };
|
|
762
751
|
}
|
|
763
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
764
|
-
if (nonNullTerms.length === 0) {
|
|
765
|
-
log.emit();
|
|
766
|
-
return { data: this.terms.map(() => null) };
|
|
767
|
-
}
|
|
768
752
|
const result = await (0, import_result.withResult)(
|
|
769
753
|
async () => {
|
|
770
754
|
if (!this.client) throw noClientError();
|
|
771
755
|
const { metadata } = this.getAuditData();
|
|
772
|
-
const queries =
|
|
773
|
-
(
|
|
756
|
+
const queries = this.terms.map(
|
|
757
|
+
(term) => buildQueryPayload(term)
|
|
774
758
|
);
|
|
775
759
|
const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
|
|
776
760
|
queries,
|
|
777
761
|
unverifiedContext: metadata
|
|
778
762
|
});
|
|
779
|
-
return assembleResults(this.terms
|
|
763
|
+
return assembleResults(this.terms, encrypted);
|
|
780
764
|
},
|
|
781
765
|
(error) => {
|
|
782
766
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -810,11 +794,6 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
810
794
|
log.emit();
|
|
811
795
|
return { data: [] };
|
|
812
796
|
}
|
|
813
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
814
|
-
if (nonNullTerms.length === 0) {
|
|
815
|
-
log.emit();
|
|
816
|
-
return { data: this.terms.map(() => null) };
|
|
817
|
-
}
|
|
818
797
|
const lockContextResult = await this.lockContext.getLockContext();
|
|
819
798
|
if (lockContextResult.failure) {
|
|
820
799
|
log.emit();
|
|
@@ -825,15 +804,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
825
804
|
async () => {
|
|
826
805
|
if (!this.client) throw noClientError();
|
|
827
806
|
const { metadata } = this.getAuditData();
|
|
828
|
-
const queries =
|
|
829
|
-
(
|
|
807
|
+
const queries = this.terms.map(
|
|
808
|
+
(term) => buildQueryPayload(term, context)
|
|
830
809
|
);
|
|
831
810
|
const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
|
|
832
811
|
queries,
|
|
833
812
|
serviceToken: ctsToken,
|
|
834
813
|
unverifiedContext: metadata
|
|
835
814
|
});
|
|
836
|
-
return assembleResults(this.terms
|
|
815
|
+
return assembleResults(this.terms, encrypted);
|
|
837
816
|
},
|
|
838
817
|
(error) => {
|
|
839
818
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -853,42 +832,25 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
853
832
|
var import_result2 = require("@byteslice/result");
|
|
854
833
|
var import_protect_ffi3 = require("@cipherstash/protect-ffi");
|
|
855
834
|
var createDecryptPayloads = (encryptedPayloads, lockContext) => {
|
|
856
|
-
return encryptedPayloads.map((
|
|
835
|
+
return encryptedPayloads.map(({ id, data }) => ({
|
|
857
836
|
id,
|
|
858
837
|
ciphertext: data,
|
|
859
|
-
originalIndex,
|
|
860
838
|
...lockContext && { lockContext }
|
|
861
839
|
}));
|
|
862
840
|
};
|
|
863
|
-
var createNullResult = (encryptedPayloads) => {
|
|
864
|
-
return encryptedPayloads.map(({ id }) => ({
|
|
865
|
-
id,
|
|
866
|
-
data: null
|
|
867
|
-
}));
|
|
868
|
-
};
|
|
869
841
|
var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const decryptResult = decryptedData[decryptedIndex];
|
|
877
|
-
if ("error" in decryptResult) {
|
|
878
|
-
result[i] = {
|
|
879
|
-
id: encryptedPayloads[i].id,
|
|
880
|
-
error: decryptResult.error
|
|
881
|
-
};
|
|
882
|
-
} else {
|
|
883
|
-
result[i] = {
|
|
884
|
-
id: encryptedPayloads[i].id,
|
|
885
|
-
data: decryptResult.data
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
decryptedIndex++;
|
|
842
|
+
return decryptedData.map((decryptResult, i) => {
|
|
843
|
+
if ("error" in decryptResult) {
|
|
844
|
+
return {
|
|
845
|
+
id: encryptedPayloads[i].id,
|
|
846
|
+
error: decryptResult.error
|
|
847
|
+
};
|
|
889
848
|
}
|
|
890
|
-
|
|
891
|
-
|
|
849
|
+
return {
|
|
850
|
+
id: encryptedPayloads[i].id,
|
|
851
|
+
data: decryptResult.data
|
|
852
|
+
};
|
|
853
|
+
});
|
|
892
854
|
};
|
|
893
855
|
var BulkDecryptOperation = class extends EncryptionOperation {
|
|
894
856
|
client;
|
|
@@ -913,13 +875,10 @@ var BulkDecryptOperation = class extends EncryptionOperation {
|
|
|
913
875
|
if (!this.client) throw noClientError();
|
|
914
876
|
if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
|
|
915
877
|
return [];
|
|
916
|
-
const
|
|
917
|
-
if (nonNullPayloads.length === 0) {
|
|
918
|
-
return createNullResult(this.encryptedPayloads);
|
|
919
|
-
}
|
|
878
|
+
const payloads = createDecryptPayloads(this.encryptedPayloads);
|
|
920
879
|
const { metadata } = this.getAuditData();
|
|
921
880
|
const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(this.client, {
|
|
922
|
-
ciphertexts:
|
|
881
|
+
ciphertexts: payloads,
|
|
923
882
|
unverifiedContext: metadata
|
|
924
883
|
});
|
|
925
884
|
return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
|
|
@@ -971,16 +930,13 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
971
930
|
if (context.failure) {
|
|
972
931
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
973
932
|
}
|
|
974
|
-
const
|
|
933
|
+
const payloads = createDecryptPayloads(
|
|
975
934
|
encryptedPayloads,
|
|
976
935
|
context.data.context
|
|
977
936
|
);
|
|
978
|
-
if (nonNullPayloads.length === 0) {
|
|
979
|
-
return createNullResult(encryptedPayloads);
|
|
980
|
-
}
|
|
981
937
|
const { metadata } = this.getAuditData();
|
|
982
938
|
const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(client, {
|
|
983
|
-
ciphertexts:
|
|
939
|
+
ciphertexts: payloads,
|
|
984
940
|
serviceToken: context.data.ctsToken,
|
|
985
941
|
unverifiedContext: metadata
|
|
986
942
|
});
|
|
@@ -1619,34 +1575,14 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
|
|
|
1619
1575
|
var import_result4 = require("@byteslice/result");
|
|
1620
1576
|
var import_protect_ffi5 = require("@cipherstash/protect-ffi");
|
|
1621
1577
|
var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
|
|
1622
|
-
return plaintexts.map((
|
|
1578
|
+
return plaintexts.map(({ id, plaintext }) => ({
|
|
1623
1579
|
id,
|
|
1624
1580
|
plaintext,
|
|
1625
1581
|
column: column.getName(),
|
|
1626
1582
|
table: table.tableName,
|
|
1627
|
-
originalIndex,
|
|
1628
1583
|
...lockContext && { lockContext }
|
|
1629
1584
|
}));
|
|
1630
1585
|
};
|
|
1631
|
-
var createNullResult2 = (plaintexts) => {
|
|
1632
|
-
return plaintexts.map(({ id }) => ({ id, data: null }));
|
|
1633
|
-
};
|
|
1634
|
-
var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
|
|
1635
|
-
const result = new Array(plaintexts.length);
|
|
1636
|
-
let encryptedIndex = 0;
|
|
1637
|
-
for (let i = 0; i < plaintexts.length; i++) {
|
|
1638
|
-
if (plaintexts[i].plaintext === null) {
|
|
1639
|
-
result[i] = { id: plaintexts[i].id, data: null };
|
|
1640
|
-
} else {
|
|
1641
|
-
result[i] = {
|
|
1642
|
-
id: plaintexts[i].id,
|
|
1643
|
-
data: encryptedData[encryptedIndex]
|
|
1644
|
-
};
|
|
1645
|
-
encryptedIndex++;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
return result;
|
|
1649
|
-
};
|
|
1650
1586
|
var BulkEncryptOperation = class extends EncryptionOperation {
|
|
1651
1587
|
client;
|
|
1652
1588
|
plaintexts;
|
|
@@ -1679,20 +1615,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
|
|
|
1679
1615
|
if (!this.plaintexts || this.plaintexts.length === 0) {
|
|
1680
1616
|
return [];
|
|
1681
1617
|
}
|
|
1682
|
-
const
|
|
1618
|
+
const payloads = createEncryptPayloads(
|
|
1683
1619
|
this.plaintexts,
|
|
1684
1620
|
this.column,
|
|
1685
1621
|
this.table
|
|
1686
1622
|
);
|
|
1687
|
-
if (nonNullPayloads.length === 0) {
|
|
1688
|
-
return createNullResult2(this.plaintexts);
|
|
1689
|
-
}
|
|
1690
1623
|
const { metadata } = this.getAuditData();
|
|
1691
1624
|
const encryptedData = await (0, import_protect_ffi5.encryptBulk)(this.client, {
|
|
1692
|
-
plaintexts:
|
|
1625
|
+
plaintexts: payloads,
|
|
1693
1626
|
unverifiedContext: metadata
|
|
1694
1627
|
});
|
|
1695
|
-
return
|
|
1628
|
+
return encryptedData.map((data, i) => ({
|
|
1629
|
+
id: this.plaintexts[i].id,
|
|
1630
|
+
data
|
|
1631
|
+
}));
|
|
1696
1632
|
},
|
|
1697
1633
|
(error) => {
|
|
1698
1634
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -1749,22 +1685,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
1749
1685
|
if (context.failure) {
|
|
1750
1686
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
1751
1687
|
}
|
|
1752
|
-
const
|
|
1688
|
+
const payloads = createEncryptPayloads(
|
|
1753
1689
|
plaintexts,
|
|
1754
1690
|
column,
|
|
1755
1691
|
table,
|
|
1756
1692
|
context.data.context
|
|
1757
1693
|
);
|
|
1758
|
-
if (nonNullPayloads.length === 0) {
|
|
1759
|
-
return createNullResult2(plaintexts);
|
|
1760
|
-
}
|
|
1761
1694
|
const { metadata } = this.getAuditData();
|
|
1762
1695
|
const encryptedData = await (0, import_protect_ffi5.encryptBulk)(client, {
|
|
1763
|
-
plaintexts:
|
|
1696
|
+
plaintexts: payloads,
|
|
1764
1697
|
serviceToken: context.data.ctsToken,
|
|
1765
1698
|
unverifiedContext: metadata
|
|
1766
1699
|
});
|
|
1767
|
-
return
|
|
1700
|
+
return encryptedData.map((data, i) => ({
|
|
1701
|
+
id: plaintexts[i].id,
|
|
1702
|
+
data
|
|
1703
|
+
}));
|
|
1768
1704
|
},
|
|
1769
1705
|
(error) => {
|
|
1770
1706
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -1914,9 +1850,6 @@ var DecryptOperation = class extends EncryptionOperation {
|
|
|
1914
1850
|
if (!this.client) {
|
|
1915
1851
|
throw noClientError();
|
|
1916
1852
|
}
|
|
1917
|
-
if (this.encryptedData === null) {
|
|
1918
|
-
return null;
|
|
1919
|
-
}
|
|
1920
1853
|
const { metadata } = this.getAuditData();
|
|
1921
1854
|
return await (0, import_protect_ffi6.decrypt)(this.client, {
|
|
1922
1855
|
ciphertext: this.encryptedData,
|
|
@@ -1967,9 +1900,6 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
1967
1900
|
if (!client) {
|
|
1968
1901
|
throw noClientError();
|
|
1969
1902
|
}
|
|
1970
|
-
if (encryptedData === null) {
|
|
1971
|
-
return null;
|
|
1972
|
-
}
|
|
1973
1903
|
const { metadata } = this.getAuditData();
|
|
1974
1904
|
const context = await this.lockContext.getLockContext();
|
|
1975
1905
|
if (context.failure) {
|
|
@@ -2123,9 +2053,6 @@ var EncryptOperation = class extends EncryptionOperation {
|
|
|
2123
2053
|
if (!this.client) {
|
|
2124
2054
|
throw noClientError();
|
|
2125
2055
|
}
|
|
2126
|
-
if (this.plaintext === null) {
|
|
2127
|
-
return null;
|
|
2128
|
-
}
|
|
2129
2056
|
if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
|
|
2130
2057
|
throw new Error("[encryption]: Cannot encrypt NaN value");
|
|
2131
2058
|
}
|
|
@@ -2187,9 +2114,6 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2187
2114
|
if (!client) {
|
|
2188
2115
|
throw noClientError();
|
|
2189
2116
|
}
|
|
2190
|
-
if (plaintext === null) {
|
|
2191
|
-
return null;
|
|
2192
|
-
}
|
|
2193
2117
|
const { metadata } = this.getAuditData();
|
|
2194
2118
|
const context = await this.lockContext.getLockContext();
|
|
2195
2119
|
if (context.failure) {
|
|
@@ -2353,10 +2277,6 @@ var EncryptQueryOperation = class extends EncryptionOperation {
|
|
|
2353
2277
|
queryType: this.opts.queryType,
|
|
2354
2278
|
lockContext: false
|
|
2355
2279
|
});
|
|
2356
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
2357
|
-
log.emit();
|
|
2358
|
-
return { data: null };
|
|
2359
|
-
}
|
|
2360
2280
|
const validationError = validateNumericValue(this.plaintext);
|
|
2361
2281
|
if (validationError?.failure) {
|
|
2362
2282
|
log.emit();
|
|
@@ -2420,10 +2340,6 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2420
2340
|
queryType: this.opts.queryType,
|
|
2421
2341
|
lockContext: true
|
|
2422
2342
|
});
|
|
2423
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
2424
|
-
log.emit();
|
|
2425
|
-
return { data: null };
|
|
2426
|
-
}
|
|
2427
2343
|
const validationError = validateNumericValue(this.plaintext);
|
|
2428
2344
|
if (validationError?.failure) {
|
|
2429
2345
|
log.emit();
|
|
@@ -2528,7 +2444,7 @@ var EncryptionClient = class {
|
|
|
2528
2444
|
/**
|
|
2529
2445
|
* Encrypt a value - returns a promise which resolves to an encrypted value.
|
|
2530
2446
|
*
|
|
2531
|
-
* @param plaintext - The plaintext value to be encrypted.
|
|
2447
|
+
* @param plaintext - The plaintext value to be encrypted.
|
|
2532
2448
|
* @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
|
|
2533
2449
|
* @returns An EncryptOperation that can be awaited or chained with additional methods.
|
|
2534
2450
|
*
|
|
@@ -2829,7 +2745,7 @@ var EncryptionClient = class {
|
|
|
2829
2745
|
*
|
|
2830
2746
|
* Each value is encrypted with its own unique key via a single call to ZeroKMS.
|
|
2831
2747
|
* Values can include optional `id` fields for correlating results back to
|
|
2832
|
-
* your application data.
|
|
2748
|
+
* your application data.
|
|
2833
2749
|
*
|
|
2834
2750
|
* @param plaintexts - An array of objects with `plaintext` (and optional `id`) fields.
|
|
2835
2751
|
* @param opts - Options specifying the target column (or nested {@link encryptedField}) and table. See {@link EncryptOptions}.
|
|
@@ -2850,7 +2766,6 @@ var EncryptionClient = class {
|
|
|
2850
2766
|
* [
|
|
2851
2767
|
* { id: "u1", plaintext: "alice@example.com" },
|
|
2852
2768
|
* { id: "u2", plaintext: "bob@example.com" },
|
|
2853
|
-
* { id: "u3", plaintext: null },
|
|
2854
2769
|
* ],
|
|
2855
2770
|
* { column: users.email, table: users },
|
|
2856
2771
|
* )
|
|
@@ -2904,23 +2819,14 @@ var EncryptionClient = class {
|
|
|
2904
2819
|
};
|
|
2905
2820
|
}
|
|
2906
2821
|
};
|
|
2907
|
-
|
|
2908
|
-
// src/index.ts
|
|
2909
|
-
function isValidUuid(uuid) {
|
|
2910
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2911
|
-
return uuidRegex.test(uuid);
|
|
2912
|
-
}
|
|
2913
2822
|
var Encryption = async (config) => {
|
|
2914
|
-
if (config.logging) {
|
|
2915
|
-
initStackLogger(config.logging);
|
|
2916
|
-
}
|
|
2917
2823
|
const { schemas, config: clientConfig } = config;
|
|
2918
2824
|
if (!schemas.length) {
|
|
2919
2825
|
throw new Error(
|
|
2920
2826
|
"[encryption]: At least one encryptedTable must be provided to initialize the encryption client"
|
|
2921
2827
|
);
|
|
2922
2828
|
}
|
|
2923
|
-
if (clientConfig?.keyset && "id" in clientConfig.keyset && !
|
|
2829
|
+
if (clientConfig?.keyset && "id" in clientConfig.keyset && !(0, import_uuid.validate)(clientConfig.keyset.id)) {
|
|
2924
2830
|
throw new Error(
|
|
2925
2831
|
"[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
|
|
2926
2832
|
);
|
|
@@ -2936,13 +2842,350 @@ var Encryption = async (config) => {
|
|
|
2936
2842
|
}
|
|
2937
2843
|
return result.data;
|
|
2938
2844
|
};
|
|
2845
|
+
|
|
2846
|
+
// src/secrets/index.ts
|
|
2847
|
+
var Secrets = class {
|
|
2848
|
+
encryptionClient = null;
|
|
2849
|
+
config;
|
|
2850
|
+
apiBaseUrl = process.env.STASH_API_URL || "https://dashboard.cipherstash.com/api/secrets";
|
|
2851
|
+
secretsSchema = encryptedTable("secrets", {
|
|
2852
|
+
value: encryptedColumn("value")
|
|
2853
|
+
});
|
|
2854
|
+
constructor(config) {
|
|
2855
|
+
const workspaceCRN = config.workspaceCRN ?? process.env.CS_WORKSPACE_CRN;
|
|
2856
|
+
const clientId = config.clientId ?? process.env.CS_CLIENT_ID;
|
|
2857
|
+
const clientKey = config.clientKey ?? process.env.CS_CLIENT_KEY;
|
|
2858
|
+
const accessKey = config.accessKey ?? process.env.CS_CLIENT_ACCESS_KEY;
|
|
2859
|
+
if (!workspaceCRN || !clientId || !clientKey || !accessKey) {
|
|
2860
|
+
throw new Error(
|
|
2861
|
+
"Missing required configuration or environment variables."
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
this.config = {
|
|
2865
|
+
environment: config.environment,
|
|
2866
|
+
workspaceCRN,
|
|
2867
|
+
clientId,
|
|
2868
|
+
clientKey,
|
|
2869
|
+
accessKey
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2872
|
+
initPromise = null;
|
|
2873
|
+
/**
|
|
2874
|
+
* Initialize the Secrets client and underlying Encryption client
|
|
2875
|
+
*/
|
|
2876
|
+
async ensureInitialized() {
|
|
2877
|
+
if (!this.initPromise) {
|
|
2878
|
+
this.initPromise = this._doInit();
|
|
2879
|
+
}
|
|
2880
|
+
return this.initPromise;
|
|
2881
|
+
}
|
|
2882
|
+
async _doInit() {
|
|
2883
|
+
logger.debug("Initializing the Secrets client.");
|
|
2884
|
+
this.encryptionClient = await Encryption({
|
|
2885
|
+
schemas: [this.secretsSchema],
|
|
2886
|
+
config: {
|
|
2887
|
+
workspaceCrn: this.config.workspaceCRN,
|
|
2888
|
+
clientId: this.config.clientId,
|
|
2889
|
+
clientKey: this.config.clientKey,
|
|
2890
|
+
accessKey: this.config.accessKey,
|
|
2891
|
+
keyset: { name: this.config.environment }
|
|
2892
|
+
}
|
|
2893
|
+
});
|
|
2894
|
+
logger.debug("Successfully initialized the Secrets client.");
|
|
2895
|
+
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Get the authorization header for API requests
|
|
2898
|
+
*/
|
|
2899
|
+
getAuthHeader() {
|
|
2900
|
+
return `Bearer ${this.config.accessKey}`;
|
|
2901
|
+
}
|
|
2902
|
+
/**
|
|
2903
|
+
* Make an API request with error handling.
|
|
2904
|
+
*
|
|
2905
|
+
* For GET requests, `params` are appended as URL query parameters.
|
|
2906
|
+
* For POST requests, `body` is sent as JSON in the request body.
|
|
2907
|
+
*/
|
|
2908
|
+
async apiRequest(method, path2, options) {
|
|
2909
|
+
try {
|
|
2910
|
+
let url = `${this.apiBaseUrl}${path2}`;
|
|
2911
|
+
if (options?.params) {
|
|
2912
|
+
const searchParams = new URLSearchParams(options.params);
|
|
2913
|
+
url = `${url}?${searchParams.toString()}`;
|
|
2914
|
+
}
|
|
2915
|
+
logger.debug(`Secrets API request: ${method} ${path2}`);
|
|
2916
|
+
const headers = {
|
|
2917
|
+
"Content-Type": "application/json",
|
|
2918
|
+
Authorization: this.getAuthHeader()
|
|
2919
|
+
};
|
|
2920
|
+
const response = await fetch(url, {
|
|
2921
|
+
method,
|
|
2922
|
+
headers,
|
|
2923
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
2924
|
+
});
|
|
2925
|
+
if (!response.ok) {
|
|
2926
|
+
const errorText = await response.text();
|
|
2927
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
2928
|
+
try {
|
|
2929
|
+
const errorJson = JSON.parse(errorText);
|
|
2930
|
+
errorMessage = errorJson.message || errorJson.error || errorMessage;
|
|
2931
|
+
} catch {
|
|
2932
|
+
errorMessage = errorText || errorMessage;
|
|
2933
|
+
}
|
|
2934
|
+
logger.error(`Secrets API error on ${method} ${path2}: ${errorMessage}`);
|
|
2935
|
+
return {
|
|
2936
|
+
failure: {
|
|
2937
|
+
type: "ApiError",
|
|
2938
|
+
message: errorMessage
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
logger.debug(`Secrets API request successful: ${method} ${path2}`);
|
|
2943
|
+
const data = await response.json();
|
|
2944
|
+
return { data };
|
|
2945
|
+
} catch (error) {
|
|
2946
|
+
const message = error instanceof Error ? error.message : "Unknown network error occurred";
|
|
2947
|
+
logger.error(`Secrets network error on ${method} ${path2}: ${message}`);
|
|
2948
|
+
return {
|
|
2949
|
+
failure: {
|
|
2950
|
+
type: "NetworkError",
|
|
2951
|
+
message
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Store an encrypted secret in the vault.
|
|
2958
|
+
* The value is encrypted locally before being sent to the API.
|
|
2959
|
+
*
|
|
2960
|
+
* API: POST /api/secrets/set
|
|
2961
|
+
*
|
|
2962
|
+
* @param name - The name of the secret
|
|
2963
|
+
* @param value - The plaintext value to encrypt and store
|
|
2964
|
+
* @returns A Result containing the API response or an error
|
|
2965
|
+
*/
|
|
2966
|
+
async set(name, value) {
|
|
2967
|
+
logger.debug("Setting secret");
|
|
2968
|
+
await this.ensureInitialized();
|
|
2969
|
+
if (!this.encryptionClient) {
|
|
2970
|
+
return {
|
|
2971
|
+
failure: {
|
|
2972
|
+
type: "ClientError",
|
|
2973
|
+
message: "Failed to initialize Encryption client"
|
|
2974
|
+
}
|
|
2975
|
+
};
|
|
2976
|
+
}
|
|
2977
|
+
const encryptResult = await this.encryptionClient.encrypt(value, {
|
|
2978
|
+
column: this.secretsSchema.value,
|
|
2979
|
+
table: this.secretsSchema
|
|
2980
|
+
});
|
|
2981
|
+
if (encryptResult.failure) {
|
|
2982
|
+
logger.error("Failed to encrypt secret");
|
|
2983
|
+
return {
|
|
2984
|
+
failure: {
|
|
2985
|
+
type: "EncryptionError",
|
|
2986
|
+
message: encryptResult.failure.message
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
2991
|
+
return await this.apiRequest("POST", "/set", {
|
|
2992
|
+
body: {
|
|
2993
|
+
workspaceId,
|
|
2994
|
+
environment: this.config.environment,
|
|
2995
|
+
name,
|
|
2996
|
+
encryptedValue: encryptedToPgComposite(encryptResult.data)
|
|
2997
|
+
}
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
/**
|
|
3001
|
+
* Retrieve and decrypt a secret from the vault.
|
|
3002
|
+
* The secret is decrypted locally after retrieval.
|
|
3003
|
+
*
|
|
3004
|
+
* API: GET /api/secrets/get?workspaceId=...&environment=...&name=...
|
|
3005
|
+
*
|
|
3006
|
+
* @param name - The name of the secret to retrieve
|
|
3007
|
+
* @returns A Result containing the decrypted value or an error
|
|
3008
|
+
*/
|
|
3009
|
+
async get(name) {
|
|
3010
|
+
logger.debug("Getting secret");
|
|
3011
|
+
await this.ensureInitialized();
|
|
3012
|
+
if (!this.encryptionClient) {
|
|
3013
|
+
return {
|
|
3014
|
+
failure: {
|
|
3015
|
+
type: "ClientError",
|
|
3016
|
+
message: "Failed to initialize Encryption client"
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3021
|
+
const apiResult = await this.apiRequest("GET", "/get", {
|
|
3022
|
+
params: {
|
|
3023
|
+
workspaceId,
|
|
3024
|
+
environment: this.config.environment,
|
|
3025
|
+
name
|
|
3026
|
+
}
|
|
3027
|
+
});
|
|
3028
|
+
if (apiResult.failure) {
|
|
3029
|
+
return apiResult;
|
|
3030
|
+
}
|
|
3031
|
+
const decryptResult = await this.encryptionClient.decrypt(
|
|
3032
|
+
apiResult.data.encryptedValue.data
|
|
3033
|
+
);
|
|
3034
|
+
if (decryptResult.failure) {
|
|
3035
|
+
logger.error("Failed to decrypt secret");
|
|
3036
|
+
return {
|
|
3037
|
+
failure: {
|
|
3038
|
+
type: "DecryptionError",
|
|
3039
|
+
message: decryptResult.failure.message
|
|
3040
|
+
}
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
if (typeof decryptResult.data !== "string") {
|
|
3044
|
+
logger.error("Decrypted secret value is not a string");
|
|
3045
|
+
return {
|
|
3046
|
+
failure: {
|
|
3047
|
+
type: "DecryptionError",
|
|
3048
|
+
message: "Decrypted value is not a string"
|
|
3049
|
+
}
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
return { data: decryptResult.data };
|
|
3053
|
+
}
|
|
3054
|
+
/**
|
|
3055
|
+
* Retrieve and decrypt many secrets from the vault.
|
|
3056
|
+
* The secrets are decrypted locally after retrieval.
|
|
3057
|
+
* This method only triggers a single network request to the ZeroKMS.
|
|
3058
|
+
*
|
|
3059
|
+
* API: GET /api/secrets/get-many?workspaceId=...&environment=...&names=name1,name2,...
|
|
3060
|
+
*
|
|
3061
|
+
* Constraints:
|
|
3062
|
+
* - Minimum 2 secret names required
|
|
3063
|
+
* - Maximum 100 secret names per request
|
|
3064
|
+
*
|
|
3065
|
+
* @param names - The names of the secrets to retrieve (min 2, max 100)
|
|
3066
|
+
* @returns A Result containing an object mapping secret names to their decrypted values
|
|
3067
|
+
*/
|
|
3068
|
+
async getMany(names) {
|
|
3069
|
+
logger.debug(`Getting ${names.length} secrets.`);
|
|
3070
|
+
await this.ensureInitialized();
|
|
3071
|
+
if (!this.encryptionClient) {
|
|
3072
|
+
return {
|
|
3073
|
+
failure: {
|
|
3074
|
+
type: "ClientError",
|
|
3075
|
+
message: "Failed to initialize Encryption client"
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
if (names.length < 2) {
|
|
3080
|
+
return {
|
|
3081
|
+
failure: {
|
|
3082
|
+
type: "ClientError",
|
|
3083
|
+
message: "At least 2 secret names are required for getMany"
|
|
3084
|
+
}
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
if (names.length > 100) {
|
|
3088
|
+
return {
|
|
3089
|
+
failure: {
|
|
3090
|
+
type: "ClientError",
|
|
3091
|
+
message: "Maximum 100 secret names per request"
|
|
3092
|
+
}
|
|
3093
|
+
};
|
|
3094
|
+
}
|
|
3095
|
+
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3096
|
+
const apiResult = await this.apiRequest(
|
|
3097
|
+
"GET",
|
|
3098
|
+
"/get-many",
|
|
3099
|
+
{
|
|
3100
|
+
params: {
|
|
3101
|
+
workspaceId,
|
|
3102
|
+
environment: this.config.environment,
|
|
3103
|
+
names: names.join(",")
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
);
|
|
3107
|
+
if (apiResult.failure) {
|
|
3108
|
+
return apiResult;
|
|
3109
|
+
}
|
|
3110
|
+
const dataToDecrypt = apiResult.data.map((item) => ({
|
|
3111
|
+
name: item.name,
|
|
3112
|
+
value: item.encryptedValue.data
|
|
3113
|
+
}));
|
|
3114
|
+
const decryptResult = await this.encryptionClient.bulkDecryptModels(dataToDecrypt);
|
|
3115
|
+
if (decryptResult.failure) {
|
|
3116
|
+
logger.error(
|
|
3117
|
+
`Failed to decrypt secrets: ${decryptResult.failure.message}`
|
|
3118
|
+
);
|
|
3119
|
+
return {
|
|
3120
|
+
failure: {
|
|
3121
|
+
type: "DecryptionError",
|
|
3122
|
+
message: decryptResult.failure.message
|
|
3123
|
+
}
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
const decryptedSecrets = decryptResult.data;
|
|
3127
|
+
const secretsMap = {};
|
|
3128
|
+
for (const secret of decryptedSecrets) {
|
|
3129
|
+
if (secret.name && secret.value) {
|
|
3130
|
+
secretsMap[secret.name] = secret.value;
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
return { data: secretsMap };
|
|
3134
|
+
}
|
|
3135
|
+
/**
|
|
3136
|
+
* List all secrets in the environment.
|
|
3137
|
+
* Only names and metadata are returned; values remain encrypted.
|
|
3138
|
+
*
|
|
3139
|
+
* API: GET /api/secrets/list?workspaceId=...&environment=...
|
|
3140
|
+
*
|
|
3141
|
+
* @returns A Result containing the list of secrets or an error
|
|
3142
|
+
*/
|
|
3143
|
+
async list() {
|
|
3144
|
+
logger.debug("Listing secrets.");
|
|
3145
|
+
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3146
|
+
const apiResult = await this.apiRequest(
|
|
3147
|
+
"GET",
|
|
3148
|
+
"/list",
|
|
3149
|
+
{
|
|
3150
|
+
params: {
|
|
3151
|
+
workspaceId,
|
|
3152
|
+
environment: this.config.environment
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
);
|
|
3156
|
+
if (apiResult.failure) {
|
|
3157
|
+
return apiResult;
|
|
3158
|
+
}
|
|
3159
|
+
return { data: apiResult.data.secrets };
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Delete a secret from the vault.
|
|
3163
|
+
*
|
|
3164
|
+
* API: POST /api/secrets/delete
|
|
3165
|
+
*
|
|
3166
|
+
* @param name - The name of the secret to delete
|
|
3167
|
+
* @returns A Result containing the API response or an error
|
|
3168
|
+
*/
|
|
3169
|
+
async delete(name) {
|
|
3170
|
+
logger.debug("Deleting secret");
|
|
3171
|
+
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
3172
|
+
return await this.apiRequest("POST", "/delete", {
|
|
3173
|
+
body: {
|
|
3174
|
+
workspaceId,
|
|
3175
|
+
environment: this.config.environment,
|
|
3176
|
+
name
|
|
3177
|
+
}
|
|
3178
|
+
});
|
|
3179
|
+
}
|
|
3180
|
+
};
|
|
2939
3181
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2940
3182
|
0 && (module.exports = {
|
|
2941
3183
|
Encryption,
|
|
2942
|
-
|
|
3184
|
+
Secrets,
|
|
2943
3185
|
encryptedColumn,
|
|
2944
3186
|
encryptedField,
|
|
2945
3187
|
encryptedTable,
|
|
2946
|
-
|
|
3188
|
+
encryptedToPgComposite,
|
|
3189
|
+
isEncryptedPayload
|
|
2947
3190
|
});
|
|
2948
3191
|
//# sourceMappingURL=index.cjs.map
|