@docstack/client 0.0.1

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 (77) hide show
  1. package/README.md +214 -0
  2. package/lib/core/attribute.d.ts +174 -0
  3. package/lib/core/attribute.js +296 -0
  4. package/lib/core/attribute.js.map +1 -0
  5. package/lib/core/class.d.ts +340 -0
  6. package/lib/core/class.js +540 -0
  7. package/lib/core/class.js.map +1 -0
  8. package/lib/core/crypto-engine/index.d.ts +121 -0
  9. package/lib/core/crypto-engine/index.js +130 -0
  10. package/lib/core/crypto-engine/index.js.map +1 -0
  11. package/lib/core/crypto-engine/utils.d.ts +20 -0
  12. package/lib/core/crypto-engine/utils.js +76 -0
  13. package/lib/core/crypto-engine/utils.js.map +1 -0
  14. package/lib/core/datamodel/index.d.ts +3 -0
  15. package/lib/core/datamodel/index.js +1186 -0
  16. package/lib/core/datamodel/index.js.map +1 -0
  17. package/lib/core/domain.d.ts +200 -0
  18. package/lib/core/domain.js +285 -0
  19. package/lib/core/domain.js.map +1 -0
  20. package/lib/core/index.d.ts +176 -0
  21. package/lib/core/index.js +379 -0
  22. package/lib/core/index.js.map +1 -0
  23. package/lib/core/job-engine/index.d.ts +110 -0
  24. package/lib/core/job-engine/index.js +116 -0
  25. package/lib/core/job-engine/index.js.map +1 -0
  26. package/lib/core/policy-engine/index.d.ts +97 -0
  27. package/lib/core/policy-engine/index.js +150 -0
  28. package/lib/core/policy-engine/index.js.map +1 -0
  29. package/lib/core/query-engine/accumulators.d.ts +9 -0
  30. package/lib/core/query-engine/accumulators.js +258 -0
  31. package/lib/core/query-engine/accumulators.js.map +1 -0
  32. package/lib/core/query-engine/evaluator.d.ts +37 -0
  33. package/lib/core/query-engine/evaluator.js +179 -0
  34. package/lib/core/query-engine/evaluator.js.map +1 -0
  35. package/lib/core/query-engine/executor.d.ts +14 -0
  36. package/lib/core/query-engine/executor.js +405 -0
  37. package/lib/core/query-engine/executor.js.map +1 -0
  38. package/lib/core/query-engine/index.d.ts +4 -0
  39. package/lib/core/query-engine/index.js +4 -0
  40. package/lib/core/query-engine/index.js.map +1 -0
  41. package/lib/core/query-engine/parser.d.ts +10 -0
  42. package/lib/core/query-engine/parser.js +515 -0
  43. package/lib/core/query-engine/parser.js.map +1 -0
  44. package/lib/core/query-engine/planner.d.ts +27 -0
  45. package/lib/core/query-engine/planner.js +330 -0
  46. package/lib/core/query-engine/planner.js.map +1 -0
  47. package/lib/core/stack.d.ts +497 -0
  48. package/lib/core/stack.js +1507 -0
  49. package/lib/core/stack.js.map +1 -0
  50. package/lib/core/test-utils/docstack.d.ts +29 -0
  51. package/lib/core/test-utils/docstack.js +222 -0
  52. package/lib/core/test-utils/docstack.js.map +1 -0
  53. package/lib/core/trigger/index.d.ts +31 -0
  54. package/lib/core/trigger/index.js +81 -0
  55. package/lib/core/trigger/index.js.map +1 -0
  56. package/lib/index.d.ts +4 -0
  57. package/lib/index.js +8237 -0
  58. package/lib/index.js.map +1 -0
  59. package/lib/plugins/pouchdb.d.ts +9 -0
  60. package/lib/plugins/pouchdb.js +403 -0
  61. package/lib/plugins/pouchdb.js.map +1 -0
  62. package/lib/utils/crypto/index.d.ts +3 -0
  63. package/lib/utils/crypto/index.js +34 -0
  64. package/lib/utils/crypto/index.js.map +1 -0
  65. package/lib/utils/index.d.ts +4 -0
  66. package/lib/utils/index.js +58 -0
  67. package/lib/utils/index.js.map +1 -0
  68. package/lib/utils/logger/index.d.ts +4 -0
  69. package/lib/utils/logger/index.js +20 -0
  70. package/lib/utils/logger/index.js.map +1 -0
  71. package/lib/utils/logger/transport.d.ts +11 -0
  72. package/lib/utils/logger/transport.js +28 -0
  73. package/lib/utils/logger/transport.js.map +1 -0
  74. package/lib/workers/dataModel.d.ts +1 -0
  75. package/lib/workers/dataModel.js +48 -0
  76. package/lib/workers/dataModel.js.map +1 -0
  77. package/package.json +60 -0
@@ -0,0 +1,121 @@
1
+ import { Document } from "@docstack/shared";
2
+ import Class from "../class.js";
3
+ import type ClientStack from "../stack.js";
4
+ import { EncryptedPayload } from "./utils.js";
5
+ /**
6
+ * Engine for handling document-level encryption and decryption.
7
+ *
8
+ * CryptoEngine manages AES-GCM encryption for sensitive document fields.
9
+ * It uses a document key (derived from user credentials) to encrypt/decrypt
10
+ * fields marked with `encrypted: true` in their attribute configuration.
11
+ *
12
+ * The engine can be disabled via stack options for scenarios where
13
+ * encryption is not required.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Encryption is handled automatically during document operations
18
+ * // when attributes are configured with `encrypted: true`
19
+ * await Attribute.create(userClass, 'ssn', 'string', 'Social Security Number', {
20
+ * encrypted: true
21
+ * });
22
+ *
23
+ * // After authentication, the document key is available
24
+ * await stack.authenticate({ username: 'user', password: 'pass' });
25
+ * // Now encrypted fields will be automatically encrypted/decrypted
26
+ * ```
27
+ */
28
+ export declare class CryptoEngine {
29
+ /** The hex-encoded document encryption key. */
30
+ private documentKey?;
31
+ /** The imported CryptoKey for Web Crypto API operations. */
32
+ private cryptoKey?;
33
+ private readonly logger;
34
+ /** Reference to the parent stack. */
35
+ private readonly stack;
36
+ /** Whether the crypto engine is enabled. */
37
+ private readonly enabled;
38
+ /**
39
+ * Creates a new CryptoEngine instance.
40
+ * @param stack - The parent ClientStack instance
41
+ */
42
+ constructor(stack: ClientStack);
43
+ /**
44
+ * Sets the document encryption key.
45
+ * Called automatically during authentication to provide the key
46
+ * derived from user credentials.
47
+ *
48
+ * @param documentKey - The hex-encoded document key, or null to clear
49
+ */
50
+ setDocumentKey(documentKey?: string | null): Promise<void>;
51
+ /**
52
+ * Returns the current document key.
53
+ * @returns The hex-encoded document key, or undefined if not set
54
+ */
55
+ getDocumentKey(): string;
56
+ /**
57
+ * Generates a cryptographically secure random string.
58
+ * Useful for generating salts or nonces.
59
+ *
60
+ * @param length - The length of the string to generate (default: 16)
61
+ * @returns A random hex string
62
+ */
63
+ generateRandomString(length?: number): string;
64
+ encryptValueForMarker(value: unknown): Promise<EncryptedPayload>;
65
+ /**
66
+ * Checks if the crypto engine is enabled.
67
+ * @returns `true` if encryption is enabled
68
+ */
69
+ isEnabled(): boolean;
70
+ /**
71
+ * Wraps a document key using the user's derived key.
72
+ * Used during user registration to store the encrypted document key.
73
+ *
74
+ * @param documentKey - The document key to wrap
75
+ * @param derivedKeyHex - The user's derived key (from password)
76
+ * @returns The wrapped (encrypted) document key
77
+ */
78
+ wrapDocumentKey(documentKey: string, derivedKeyHex: string): Promise<string>;
79
+ /**
80
+ * Unwraps and stores the document key using the user's derived key.
81
+ * Called during authentication to recover the document key.
82
+ *
83
+ * @param wrappedDocumentKey - The wrapped document key from the user record
84
+ * @param derivedKey - The user's derived key (from password)
85
+ * @returns The unwrapped document key
86
+ * @throws Error if the crypto engine is disabled or keys are missing
87
+ */
88
+ unwrapAndStoreDocumentKey(wrappedDocumentKey?: string | null, derivedKey?: string | null): Promise<string>;
89
+ private getCryptoKey;
90
+ private encryptValue;
91
+ private decryptValue;
92
+ /**
93
+ * Identifies which document keys contain encrypted data.
94
+ * Combines schema-defined encrypted attributes with runtime detection.
95
+ *
96
+ * @param document - The document to analyze
97
+ * @param classObj - Optional class for schema-based detection
98
+ * @returns Array of field names that are/should be encrypted
99
+ */
100
+ identifyEncryptedKeys(document: Document, classObj?: Class): string[];
101
+ /**
102
+ * Encrypts sensitive fields in a document before storage.
103
+ * Only encrypts fields marked with `encrypted: true` in the schema.
104
+ * Modifies the document in place.
105
+ *
106
+ * @param document - The document to encrypt
107
+ * @param classObj - The class defining which fields to encrypt
108
+ */
109
+ encryptDocument(document: Document, classObj: Class): Promise<void>;
110
+ /**
111
+ * Decrypts encrypted fields in a document after retrieval.
112
+ * Modifies the document in place.
113
+ *
114
+ * @param document - The document to decrypt
115
+ * @param classObj - Optional class for schema-based detection
116
+ * @param encryptedKeys - Optional pre-computed list of encrypted field names
117
+ */
118
+ decryptDocument(document: Document, classObj?: Class, encryptedKeys?: string[]): Promise<void>;
119
+ }
120
+ export type { EncryptedPayload } from "./utils.js";
121
+ export { wrapDocumentKey, unwrapDocumentKey } from "./utils.js";
@@ -0,0 +1,130 @@
1
+ import createLogger from "../../utils/logger/index.js";
2
+ import { decryptWithAesGcm, encryptWithAesGcm, importAesKeyFromHex, isEncryptedPayload, unwrapDocumentKey, } from "./utils.js";
3
+ export class CryptoEngine {
4
+ constructor(stack) {
5
+ this.logger = createLogger().child({ module: "crypto-engine" });
6
+ this.stack = stack;
7
+ this.enabled = !stack.isCryptoEngineDisabled();
8
+ }
9
+ async setDocumentKey(documentKey) {
10
+ if (!this.enabled)
11
+ return;
12
+ this.documentKey = documentKey || undefined;
13
+ this.cryptoKey = undefined;
14
+ }
15
+ getDocumentKey() {
16
+ return this.enabled ? this.documentKey : undefined;
17
+ }
18
+ async encryptValueForMarker(value) {
19
+ if (!this.enabled)
20
+ return null;
21
+ const key = await this.getCryptoKey();
22
+ if (!key)
23
+ return null;
24
+ return await this.encryptValue(value, key);
25
+ }
26
+ isEnabled() {
27
+ return this.enabled;
28
+ }
29
+ async unwrapAndStoreDocumentKey(wrappedDocumentKey, derivedKey) {
30
+ if (!this.enabled)
31
+ return null;
32
+ if (!wrappedDocumentKey || !derivedKey)
33
+ return null;
34
+ const key = await unwrapDocumentKey(wrappedDocumentKey, derivedKey);
35
+ await this.setDocumentKey(key);
36
+ return key;
37
+ }
38
+ async getCryptoKey() {
39
+ if (!this.enabled)
40
+ return null;
41
+ if (!this.documentKey)
42
+ return null;
43
+ if (this.cryptoKey)
44
+ return this.cryptoKey;
45
+ this.cryptoKey = await importAesKeyFromHex(this.documentKey, ["encrypt", "decrypt"]);
46
+ return this.cryptoKey;
47
+ }
48
+ async encryptValue(value, key) {
49
+ if (!this.enabled)
50
+ return value;
51
+ if (!key)
52
+ return value;
53
+ if (value === undefined || value === null)
54
+ return value;
55
+ if (isEncryptedPayload(value))
56
+ return value;
57
+ const serialized = JSON.stringify(value);
58
+ return encryptWithAesGcm(serialized, key);
59
+ }
60
+ async decryptValue(value, key) {
61
+ if (!this.enabled)
62
+ return value;
63
+ if (!key)
64
+ return value;
65
+ if (!isEncryptedPayload(value))
66
+ return value;
67
+ try {
68
+ const decrypted = await decryptWithAesGcm(value, key);
69
+ return JSON.parse(decrypted);
70
+ }
71
+ catch (error) {
72
+ this.logger.error("Failed to decrypt value", { error: (error === null || error === void 0 ? void 0 : error.message) || error });
73
+ return value;
74
+ }
75
+ }
76
+ identifyEncryptedKeys(document, classObj) {
77
+ var _a;
78
+ if (!this.enabled)
79
+ return [];
80
+ const encryptedFromSchema = (_a = classObj === null || classObj === void 0 ? void 0 : classObj.getEncryptedAttributes().map((attribute) => attribute.getName())) !== null && _a !== void 0 ? _a : [];
81
+ const encryptedFromPayload = Object.keys(document).filter((key) => isEncryptedPayload(document[key]));
82
+ if (!encryptedFromSchema.length) {
83
+ return encryptedFromPayload;
84
+ }
85
+ const merged = new Set(encryptedFromSchema);
86
+ for (const key of encryptedFromPayload) {
87
+ merged.add(key);
88
+ }
89
+ return Array.from(merged);
90
+ }
91
+ async encryptDocument(document, classObj) {
92
+ var _a, _b, _c;
93
+ if (!this.enabled)
94
+ return;
95
+ const encryptableAttributes = classObj.getEncryptedAttributes();
96
+ if (!encryptableAttributes.length)
97
+ return;
98
+ const key = await this.getCryptoKey();
99
+ if (!key) {
100
+ this.logger.warn("Document key is not available; skipping encryption", { className: (_b = (_a = classObj.getName) === null || _a === void 0 ? void 0 : _a.call(classObj)) !== null && _b !== void 0 ? _b : (_c = classObj.model) === null || _c === void 0 ? void 0 : _c.name });
101
+ return;
102
+ }
103
+ for (const attribute of encryptableAttributes) {
104
+ const name = attribute.getName();
105
+ if (!(name in document))
106
+ continue;
107
+ const encrypted = await this.encryptValue(document[name], key);
108
+ document[name] = encrypted;
109
+ }
110
+ }
111
+ async decryptDocument(document, classObj, encryptedKeys) {
112
+ var _a, _b, _c;
113
+ if (!this.enabled)
114
+ return;
115
+ const encryptedAttributes = encryptedKeys !== null && encryptedKeys !== void 0 ? encryptedKeys : this.identifyEncryptedKeys(document, classObj);
116
+ if (!encryptedAttributes.length)
117
+ return;
118
+ const key = await this.getCryptoKey();
119
+ if (!key) {
120
+ this.logger.warn("Document key is not available; returning encrypted payload", { className: (_b = (_a = classObj === null || classObj === void 0 ? void 0 : classObj.getName) === null || _a === void 0 ? void 0 : _a.call(classObj)) !== null && _b !== void 0 ? _b : (_c = classObj === null || classObj === void 0 ? void 0 : classObj.model) === null || _c === void 0 ? void 0 : _c.name });
121
+ return;
122
+ }
123
+ for (const name of encryptedAttributes) {
124
+ const decrypted = await this.decryptValue(document[name], key);
125
+ document[name] = decrypted;
126
+ }
127
+ }
128
+ }
129
+ export { wrapDocumentKey, unwrapDocumentKey } from "./utils.js";
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/crypto-engine/index.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,6BAA6B,CAAC;AAGvD,OAAO,EAEH,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,OAAO,YAAY;IAOrB,YAAY,KAAkB;QAJb,WAAM,GAAG,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;QAKxE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC;IACnD,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,WAA2B;QACnD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,SAAS,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;IAEM,cAAc;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IACvD,CAAC;IAEM,KAAK,CAAC,qBAAqB,CAAC,KAAc;QAC7C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAqB,CAAC;IACnE,CAAC;IAEM,SAAS;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAEM,KAAK,CAAC,yBAAyB,CAAC,kBAAkC,EAAE,UAA0B;QACjG,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,CAAC,kBAAkB,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAEpD,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;QACpE,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,YAAY;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC;QAE1C,IAAI,CAAC,SAAS,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAc,EAAE,GAAqB;QAC5D,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACxD,IAAI,kBAAkB,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,iBAAiB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAc,EAAE,GAAqB;QAC5D,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC7C,IAAI,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,OAAO,KAAI,KAAK,EAAE,CAAC,CAAC;YACjF,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAEM,qBAAqB,CAAC,QAAkB,EAAE,QAAgB;;QAC7D,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAC7B,MAAM,mBAAmB,GAAG,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,sBAAsB,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,mCAAI,EAAE,CAAC;QAC7G,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,CAAE,QAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAE/G,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC;YAC9B,OAAO,oBAAoB,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,mBAAmB,CAAC,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,oBAAoB,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,QAAkB,EAAE,QAAe;;QAC5D,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,qBAAqB,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;QAChE,IAAI,CAAC,qBAAqB,CAAC,MAAM;YAAE,OAAO;QAE1C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE,EAAE,SAAS,EAAE,MAAA,MAAA,QAAQ,CAAC,OAAO,wDAAI,mCAAI,MAAA,QAAQ,CAAC,KAAK,0CAAE,IAAI,EAAE,CAAC,CAAC;YACpI,OAAO;QACX,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,qBAAqB,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC;gBAAE,SAAS;YAClC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAE,QAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;YACvE,QAAgB,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;QACxC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,QAAkB,EAAE,QAAgB,EAAE,aAAwB;;QACvF,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,mBAAmB,GAAG,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC5F,IAAI,CAAC,mBAAmB,CAAC,MAAM;YAAE,OAAO;QAExC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4DAA4D,EAAE,EAAE,SAAS,EAAE,MAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,wDAAI,mCAAI,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,KAAK,0CAAE,IAAI,EAAE,CAAC,CAAC;YAC9I,OAAO;QACX,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAE,QAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;YACvE,QAAgB,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;QACxC,CAAC;IACL,CAAC;CACJ;AAGD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type EncryptedPayload = {
2
+ __enc: true;
3
+ iv: string;
4
+ data: string;
5
+ alg: "AES-GCM";
6
+ };
7
+ export declare const hexToBytes: (hex: string) => Uint8Array;
8
+ export declare const toBase64: (data: ArrayBuffer | Uint8Array) => string;
9
+ export declare const fromBase64: (value: string) => Uint8Array;
10
+ export declare const importAesKeyFromHex: (hexKey: string, usages?: KeyUsage[]) => Promise<CryptoKey>;
11
+ export declare const isEncryptedPayload: (value: unknown) => value is EncryptedPayload;
12
+ export declare const encryptWithAesGcm: (plaintext: string, key: CryptoKey) => Promise<EncryptedPayload>;
13
+ export declare const decryptWithAesGcm: (payload: EncryptedPayload, key: CryptoKey) => Promise<string>;
14
+ export declare const wrapDocumentKey: (documentKey: string, derivedKeyHex: string) => Promise<string>;
15
+ export declare const unwrapDocumentKey: (wrappedDocumentKey: string, cryptoKey: CryptoKey, derivedKeyHex: string) => Promise<string>;
16
+ /**
17
+ * Generate random string of given length in bytes, returned as hex string
18
+ *
19
+ **/
20
+ export declare const generateRandomString: (length?: number) => string;
@@ -0,0 +1,76 @@
1
+ const encoder = new TextEncoder();
2
+ const decoder = new TextDecoder();
3
+ const getCrypto = () => globalThis.crypto;
4
+ export const hexToBytes = (hex) => {
5
+ if (hex.length % 2 !== 0) {
6
+ throw new Error("Hex value must have an even length");
7
+ }
8
+ const bytes = new Uint8Array(hex.length / 2);
9
+ for (let i = 0; i < hex.length; i += 2) {
10
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
11
+ }
12
+ return bytes;
13
+ };
14
+ const toUint8Array = (data) => data instanceof ArrayBuffer ? new Uint8Array(data) : data;
15
+ export const toBase64 = (data) => {
16
+ const bytes = toUint8Array(data);
17
+ let binary = "";
18
+ bytes.forEach((byte) => {
19
+ binary += String.fromCharCode(byte);
20
+ });
21
+ return btoa(binary);
22
+ };
23
+ export const fromBase64 = (value) => {
24
+ const binary = atob(value);
25
+ const bytes = new Uint8Array(binary.length);
26
+ for (let i = 0; i < binary.length; i++) {
27
+ bytes[i] = binary.charCodeAt(i);
28
+ }
29
+ return bytes;
30
+ };
31
+ export const importAesKeyFromHex = async (hexKey, usages = ["encrypt", "decrypt"]) => {
32
+ const cryptoObj = getCrypto();
33
+ return cryptoObj.subtle.importKey("raw", hexToBytes(hexKey), { name: "AES-GCM" }, false, usages);
34
+ };
35
+ export const isEncryptedPayload = (value) => {
36
+ if (!value || typeof value !== "object")
37
+ return false;
38
+ const candidate = value;
39
+ return candidate.__enc === true && typeof candidate.iv === "string" && typeof candidate.data === "string";
40
+ };
41
+ export const encryptWithAesGcm = async (plaintext, key) => {
42
+ const cryptoObj = getCrypto();
43
+ const iv = new Uint8Array(12);
44
+ cryptoObj.getRandomValues(iv);
45
+ const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
46
+ const ciphertext = await cryptoObj.subtle.encrypt({ name: "AES-GCM", iv: ivBuffer }, key, encoder.encode(plaintext));
47
+ return {
48
+ __enc: true,
49
+ iv: toBase64(iv),
50
+ data: toBase64(ciphertext),
51
+ alg: "AES-GCM",
52
+ };
53
+ };
54
+ export const decryptWithAesGcm = async (payload, key) => {
55
+ const cryptoObj = getCrypto();
56
+ const ivBytes = fromBase64(payload.iv);
57
+ const dataBytes = fromBase64(payload.data);
58
+ const ivBuffer = ivBytes.buffer.slice(ivBytes.byteOffset, ivBytes.byteOffset + ivBytes.byteLength);
59
+ const dataBuffer = dataBytes.buffer.slice(dataBytes.byteOffset, dataBytes.byteOffset + dataBytes.byteLength);
60
+ const decrypted = await cryptoObj.subtle.decrypt({ name: "AES-GCM", iv: ivBuffer }, key, dataBuffer);
61
+ return decoder.decode(decrypted);
62
+ };
63
+ export const wrapDocumentKey = async (documentKey, derivedKeyHex) => {
64
+ const key = await importAesKeyFromHex(derivedKeyHex);
65
+ const payload = await encryptWithAesGcm(documentKey, key);
66
+ return JSON.stringify(payload);
67
+ };
68
+ export const unwrapDocumentKey = async (wrappedDocumentKey, derivedKeyHex) => {
69
+ const parsed = JSON.parse(wrappedDocumentKey);
70
+ if (!isEncryptedPayload(parsed)) {
71
+ throw new Error("Wrapped document key payload is malformed");
72
+ }
73
+ const key = await importAesKeyFromHex(derivedKeyHex, ["decrypt"]);
74
+ return decryptWithAesGcm(parsed, key);
75
+ };
76
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/crypto-engine/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Patch } from "@docstack/shared";
2
+ export declare function getSystemPatches(currentVersion: string): Promise<Patch[]>;
3
+ export declare function getAllSystemPatches(): Promise<Patch[]>;