@memberjunction/encryption 0.0.1 → 2.129.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.
Files changed (46) hide show
  1. package/README.md +391 -28
  2. package/dist/EncryptionEngine.d.ts +351 -0
  3. package/dist/EncryptionEngine.d.ts.map +1 -0
  4. package/dist/EncryptionEngine.js +683 -0
  5. package/dist/EncryptionEngine.js.map +1 -0
  6. package/dist/EncryptionKeySourceBase.d.ts +203 -0
  7. package/dist/EncryptionKeySourceBase.d.ts.map +1 -0
  8. package/dist/EncryptionKeySourceBase.js +133 -0
  9. package/dist/EncryptionKeySourceBase.js.map +1 -0
  10. package/dist/actions/EnableFieldEncryptionAction.d.ts +87 -0
  11. package/dist/actions/EnableFieldEncryptionAction.d.ts.map +1 -0
  12. package/dist/actions/EnableFieldEncryptionAction.js +308 -0
  13. package/dist/actions/EnableFieldEncryptionAction.js.map +1 -0
  14. package/dist/actions/RotateEncryptionKeyAction.d.ts +79 -0
  15. package/dist/actions/RotateEncryptionKeyAction.d.ts.map +1 -0
  16. package/dist/actions/RotateEncryptionKeyAction.js +343 -0
  17. package/dist/actions/RotateEncryptionKeyAction.js.map +1 -0
  18. package/dist/actions/index.d.ts +12 -0
  19. package/dist/actions/index.d.ts.map +1 -0
  20. package/dist/actions/index.js +17 -0
  21. package/dist/actions/index.js.map +1 -0
  22. package/dist/index.d.ts +66 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +81 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/interfaces.d.ts +216 -0
  27. package/dist/interfaces.d.ts.map +1 -0
  28. package/dist/interfaces.js +15 -0
  29. package/dist/interfaces.js.map +1 -0
  30. package/dist/providers/AWSKMSKeySource.d.ts +110 -0
  31. package/dist/providers/AWSKMSKeySource.d.ts.map +1 -0
  32. package/dist/providers/AWSKMSKeySource.js +245 -0
  33. package/dist/providers/AWSKMSKeySource.js.map +1 -0
  34. package/dist/providers/AzureKeyVaultKeySource.d.ts +109 -0
  35. package/dist/providers/AzureKeyVaultKeySource.d.ts.map +1 -0
  36. package/dist/providers/AzureKeyVaultKeySource.js +268 -0
  37. package/dist/providers/AzureKeyVaultKeySource.js.map +1 -0
  38. package/dist/providers/ConfigFileKeySource.d.ts +173 -0
  39. package/dist/providers/ConfigFileKeySource.d.ts.map +1 -0
  40. package/dist/providers/ConfigFileKeySource.js +310 -0
  41. package/dist/providers/ConfigFileKeySource.js.map +1 -0
  42. package/dist/providers/EnvVarKeySource.d.ts +152 -0
  43. package/dist/providers/EnvVarKeySource.d.ts.map +1 -0
  44. package/dist/providers/EnvVarKeySource.js +251 -0
  45. package/dist/providers/EnvVarKeySource.js.map +1 -0
  46. package/package.json +65 -6
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Environment variable key source provider.
4
+ *
5
+ * This provider retrieves encryption keys from environment variables.
6
+ * It's the simplest and most commonly used key source for development
7
+ * and containerized deployments.
8
+ *
9
+ * ## Usage
10
+ *
11
+ * 1. Generate a key: `openssl rand -base64 32`
12
+ * 2. Set environment variable: `export MJ_ENCRYPTION_KEY_PII="<base64-key>"`
13
+ * 3. Configure in database with KeyLookupValue = 'MJ_ENCRYPTION_KEY_PII'
14
+ *
15
+ * ## Key Format
16
+ *
17
+ * Keys must be base64-encoded. For AES-256, generate with:
18
+ * ```bash
19
+ * openssl rand -base64 32
20
+ * ```
21
+ *
22
+ * For AES-128:
23
+ * ```bash
24
+ * openssl rand -base64 16
25
+ * ```
26
+ *
27
+ * ## Key Rotation
28
+ *
29
+ * During rotation, store the new key in a separate variable:
30
+ * ```bash
31
+ * export MJ_ENCRYPTION_KEY_PII="<current-key>"
32
+ * export MJ_ENCRYPTION_KEY_PII_NEW="<new-key>"
33
+ * ```
34
+ *
35
+ * After rotation completes, remove the old key and optionally
36
+ * rename the new key to the original variable name.
37
+ *
38
+ * ## Security Considerations
39
+ *
40
+ * - Environment variables may be logged or visible to child processes
41
+ * - Consider using secrets managers for production deployments
42
+ * - Ensure proper access controls on the runtime environment
43
+ * - Never commit keys to source control
44
+ *
45
+ * @module @memberjunction/encryption
46
+ */
47
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
48
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
49
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
50
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
51
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.EnvVarKeySource = void 0;
55
+ const global_1 = require("@memberjunction/global");
56
+ const EncryptionKeySourceBase_1 = require("../EncryptionKeySourceBase");
57
+ /**
58
+ * Encryption key source that retrieves keys from environment variables.
59
+ *
60
+ * This is the default and recommended key source for:
61
+ * - Development environments
62
+ * - Docker/Kubernetes deployments with secret injection
63
+ * - Serverless functions with environment configuration
64
+ *
65
+ * Keys are expected to be base64-encoded strings in the environment.
66
+ * The provider decodes them to raw bytes for crypto operations.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * // The provider is automatically instantiated by ClassFactory
71
+ * // based on database configuration. For manual usage:
72
+ *
73
+ * import { EnvVarKeySource } from '@memberjunction/encryption';
74
+ *
75
+ * const source = new EnvVarKeySource();
76
+ *
77
+ * // Check if key exists
78
+ * if (await source.KeyExists('MJ_ENCRYPTION_KEY_PII')) {
79
+ * const keyBytes = await source.GetKey('MJ_ENCRYPTION_KEY_PII');
80
+ * console.log(`Key length: ${keyBytes.length} bytes`);
81
+ * }
82
+ * ```
83
+ */
84
+ let EnvVarKeySource = class EnvVarKeySource extends EncryptionKeySourceBase_1.EncryptionKeySourceBase {
85
+ /**
86
+ * Human-readable name for this source.
87
+ */
88
+ get SourceName() {
89
+ return 'Environment Variable';
90
+ }
91
+ /**
92
+ * Validates the source configuration.
93
+ *
94
+ * For environment variables, configuration is always valid as
95
+ * keys are validated at lookup time. This allows the source
96
+ * to be used dynamically for any environment variable.
97
+ *
98
+ * @returns Always returns `true`
99
+ */
100
+ ValidateConfiguration() {
101
+ // Environment variable source is always valid
102
+ // Keys are validated at lookup time, not configuration time
103
+ return true;
104
+ }
105
+ /**
106
+ * Checks if an environment variable containing a key exists.
107
+ *
108
+ * @param lookupValue - The environment variable name to check
109
+ * @returns Promise resolving to `true` if the variable is defined
110
+ */
111
+ async KeyExists(lookupValue) {
112
+ if (!lookupValue || typeof lookupValue !== 'string') {
113
+ return false;
114
+ }
115
+ // Validate the lookup value format (env var name)
116
+ if (!this.isValidEnvVarName(lookupValue)) {
117
+ return false;
118
+ }
119
+ return process.env[lookupValue] !== undefined;
120
+ }
121
+ /**
122
+ * Retrieves key material from an environment variable.
123
+ *
124
+ * The environment variable should contain a base64-encoded key.
125
+ * For versioned keys, the version is appended with an underscore:
126
+ * - `KEY_NAME` for version 1 (default)
127
+ * - `KEY_NAME_V2` for version 2
128
+ * - etc.
129
+ *
130
+ * @param lookupValue - The environment variable name
131
+ * @param keyVersion - Optional version number (defaults to '1')
132
+ * @returns Promise resolving to the decoded key bytes
133
+ *
134
+ * @throws Error if the environment variable is not set
135
+ * @throws Error if the value is not valid base64
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // Get current key
140
+ * const key = await source.GetKey('MJ_ENCRYPTION_KEY_PII');
141
+ *
142
+ * // Get specific version during rotation
143
+ * const oldKey = await source.GetKey('MJ_ENCRYPTION_KEY_PII', '1');
144
+ * const newKey = await source.GetKey('MJ_ENCRYPTION_KEY_PII', '2');
145
+ * // The above looks for MJ_ENCRYPTION_KEY_PII_V2
146
+ * ```
147
+ */
148
+ async GetKey(lookupValue, keyVersion) {
149
+ // Validate lookup value
150
+ if (!lookupValue || typeof lookupValue !== 'string') {
151
+ throw new Error('Invalid lookup value: environment variable name is required. ' +
152
+ 'Provide the name of the environment variable containing the base64-encoded key.');
153
+ }
154
+ // Validate env var name format to prevent injection
155
+ if (!this.isValidEnvVarName(lookupValue)) {
156
+ throw new Error(`Invalid environment variable name: "${lookupValue}". ` +
157
+ 'Names must start with a letter or underscore and contain only ' +
158
+ 'letters, numbers, and underscores.');
159
+ }
160
+ // Build the full environment variable name
161
+ // For versions other than '1', append _V{version}
162
+ const envVarName = this.buildEnvVarName(lookupValue, keyVersion);
163
+ // Retrieve the value
164
+ const keyValue = process.env[envVarName];
165
+ if (keyValue === undefined || keyValue === null) {
166
+ throw new Error(`Encryption key not found in environment variable: "${envVarName}". ` +
167
+ 'Ensure the environment variable is set with a base64-encoded key value. ' +
168
+ 'Generate a key with: openssl rand -base64 32');
169
+ }
170
+ if (keyValue.trim() === '') {
171
+ throw new Error(`Encryption key in environment variable "${envVarName}" is empty. ` +
172
+ 'The variable must contain a non-empty base64-encoded key value.');
173
+ }
174
+ // Decode from base64
175
+ try {
176
+ const keyBytes = Buffer.from(keyValue, 'base64');
177
+ // Verify we got actual bytes (empty buffer check)
178
+ if (keyBytes.length === 0) {
179
+ throw new Error('Decoded key is empty');
180
+ }
181
+ // Validate it was actually valid base64
182
+ // by checking the round-trip
183
+ const roundTrip = keyBytes.toString('base64');
184
+ const normalized = keyValue.replace(/\s+/g, '');
185
+ if (roundTrip !== normalized && roundTrip + '=' !== normalized && roundTrip + '==' !== normalized) {
186
+ // If they don't match, the input wasn't valid base64
187
+ // (We allow for padding differences)
188
+ throw new Error('Input does not appear to be valid base64 encoding');
189
+ }
190
+ return keyBytes;
191
+ }
192
+ catch (err) {
193
+ const message = err instanceof Error ? err.message : String(err);
194
+ throw new Error(`Invalid base64 encoding for encryption key in "${envVarName}". ` +
195
+ `The value must be a valid base64-encoded string. Error: ${message}. ` +
196
+ 'Generate a valid key with: openssl rand -base64 32');
197
+ }
198
+ }
199
+ /**
200
+ * Builds the full environment variable name with optional version suffix.
201
+ *
202
+ * @param baseName - The base environment variable name
203
+ * @param keyVersion - Optional version number
204
+ * @returns The full environment variable name
205
+ *
206
+ * @private
207
+ */
208
+ buildEnvVarName(baseName, keyVersion) {
209
+ // No version or version '1' = use base name
210
+ if (!keyVersion || keyVersion === '1') {
211
+ return baseName;
212
+ }
213
+ // For other versions, append _V{version}
214
+ return `${baseName}_V${keyVersion}`;
215
+ }
216
+ /**
217
+ * Validates that a string is a valid environment variable name.
218
+ *
219
+ * Valid names:
220
+ * - Start with a letter (A-Z, a-z) or underscore (_)
221
+ * - Contain only letters, numbers, and underscores
222
+ *
223
+ * This prevents injection attacks where malicious lookupValues
224
+ * could be crafted to access unintended variables.
225
+ *
226
+ * @param name - The name to validate
227
+ * @returns `true` if the name is valid
228
+ *
229
+ * @private
230
+ */
231
+ isValidEnvVarName(name) {
232
+ // Must be non-empty
233
+ if (!name || name.length === 0) {
234
+ return false;
235
+ }
236
+ // Maximum reasonable length to prevent DoS
237
+ if (name.length > 256) {
238
+ return false;
239
+ }
240
+ // Standard environment variable naming rules
241
+ // Must start with letter or underscore
242
+ // Can contain letters, numbers, underscores
243
+ const envVarPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
244
+ return envVarPattern.test(name);
245
+ }
246
+ };
247
+ exports.EnvVarKeySource = EnvVarKeySource;
248
+ exports.EnvVarKeySource = EnvVarKeySource = __decorate([
249
+ (0, global_1.RegisterClass)(EncryptionKeySourceBase_1.EncryptionKeySourceBase, 'EnvVarKeySource')
250
+ ], EnvVarKeySource);
251
+ //# sourceMappingURL=EnvVarKeySource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvVarKeySource.js","sourceRoot":"","sources":["../../src/providers/EnvVarKeySource.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,69 @@
1
1
  {
2
2
  "name": "@memberjunction/encryption",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @memberjunction/encryption",
3
+ "version": "2.129.0",
4
+ "description": "MemberJunction: Field-level encryption engine with pluggable key sources. Server-side only - provides AES-256-GCM/CBC encryption with environment variable, config file, AWS KMS, and Azure Key Vault key sources.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "/dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "jest",
13
+ "test:watch": "jest --watch",
14
+ "test:coverage": "jest --coverage"
15
+ },
16
+ "author": "MemberJunction.com",
17
+ "license": "ISC",
18
+ "devDependencies": {
19
+ "@types/jest": "^29.5.12",
20
+ "@types/node": "^20.11.0",
21
+ "jest": "^29.7.0",
22
+ "ts-jest": "^29.1.2",
23
+ "typescript": "^5.4.5"
24
+ },
25
+ "dependencies": {
26
+ "@memberjunction/global": "2.129.0",
27
+ "@memberjunction/core": "2.129.0",
28
+ "@memberjunction/core-entities": "2.129.0",
29
+ "@memberjunction/actions-base": "2.129.0",
30
+ "cosmiconfig": "^9.0.0"
31
+ },
32
+ "optionalDependencies": {
33
+ "@aws-sdk/client-kms": "^3.700.0",
34
+ "@azure/keyvault-secrets": "^4.9.0",
35
+ "@azure/identity": "^4.5.0"
36
+ },
37
+ "peerDependencies": {
38
+ "@aws-sdk/client-kms": "^3.0.0",
39
+ "@azure/keyvault-secrets": "^4.0.0",
40
+ "@azure/identity": "^4.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "@aws-sdk/client-kms": {
44
+ "optional": true
45
+ },
46
+ "@azure/keyvault-secrets": {
47
+ "optional": true
48
+ },
49
+ "@azure/identity": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/MemberJunction/MJ"
56
+ },
5
57
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
58
+ "memberjunction",
59
+ "encryption",
60
+ "field-level-encryption",
61
+ "aes-256-gcm",
62
+ "security",
63
+ "aws-kms",
64
+ "azure-keyvault"
65
+ ],
66
+ "engines": {
67
+ "node": ">=18.0.0"
68
+ }
10
69
  }