@futdevpro/fsm-dynamo 1.10.30 → 1.10.32
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/build/_enums/environment-flag.enum.d.ts +1 -0
- package/build/_enums/environment-flag.enum.d.ts.map +1 -1
- package/build/_enums/environment-flag.enum.js +2 -1
- package/build/_enums/environment-flag.enum.js.map +1 -1
- package/build/_models/control-models/data-property-params.control-model.d.ts.map +1 -1
- package/build/_models/control-models/data-property-params.control-model.js +18 -6
- package/build/_models/control-models/data-property-params.control-model.js.map +1 -1
- package/build/_models/control-models/data-property-params.control-model.spec.js +7 -4
- package/build/_models/control-models/data-property-params.control-model.spec.js.map +1 -1
- package/build/_models/control-models/service-endpoint-settings-base.control-model.js +3 -3
- package/build/_modules/crypto/_collections/crypto.util.d.ts +86 -0
- package/build/_modules/crypto/_collections/crypto.util.d.ts.map +1 -0
- package/build/_modules/crypto/_collections/crypto.util.js +212 -0
- package/build/_modules/crypto/_collections/crypto.util.js.map +1 -0
- package/build/_modules/crypto/_collections/crypto.util.spec.d.ts +2 -0
- package/build/_modules/crypto/_collections/crypto.util.spec.d.ts.map +1 -0
- package/build/_modules/crypto/_collections/crypto.util.spec.js +165 -0
- package/build/_modules/crypto/_collections/crypto.util.spec.js.map +1 -0
- package/build/_modules/crypto/index.d.ts +2 -0
- package/build/_modules/crypto/index.d.ts.map +1 -0
- package/build/_modules/crypto/index.js +5 -0
- package/build/_modules/crypto/index.js.map +1 -0
- package/futdevpro-fsm-dynamo-01.10.32.tgz +0 -0
- package/nodemon.json +7 -2
- package/package.json +20 -6
- package/src/_enums/environment-flag.enum.ts +2 -0
- package/src/_models/control-models/data-property-params.control-model.spec.ts +7 -4
- package/src/_models/control-models/data-property-params.control-model.ts +18 -6
- package/src/_models/control-models/service-endpoint-settings-base.control-model.ts +3 -3
- package/src/_modules/crypto/_collections/crypto.util.spec.ts +195 -0
- package/src/_modules/crypto/_collections/crypto.util.ts +248 -0
- package/src/_modules/crypto/index.ts +3 -0
- package/futdevpro-fsm-dynamo-01.10.30.tgz +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import * as CryptoJS from 'crypto-js';
|
|
2
|
+
|
|
3
|
+
import { DyFM_Error } from '../../../_models/control-models/error.control-model';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Error codes for crypto operations
|
|
7
|
+
*/
|
|
8
|
+
export enum CryptoErrorCode {
|
|
9
|
+
INVALID_INPUT = 'DyFM-CRY-EA0',
|
|
10
|
+
DECRYPTION_FAILED = 'DyFM-CRY-DRY',
|
|
11
|
+
ENCRYPTION_FAILED = 'DyFM-CRY-ENF',
|
|
12
|
+
INVALID_KEY = 'DyFM-CRY-IKY',
|
|
13
|
+
INVALID_DATA = 'DyFM-CRY-IDT'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configuration options for encryption/decryption
|
|
18
|
+
*/
|
|
19
|
+
export interface CryptoConfig {
|
|
20
|
+
ivLength?: number;
|
|
21
|
+
saltLength?: number;
|
|
22
|
+
keyIterations?: number;
|
|
23
|
+
keySize?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A utility class for secure encryption and decryption of data
|
|
28
|
+
* Uses AES-256-CBC with PBKDF2 key derivation
|
|
29
|
+
*/
|
|
30
|
+
export class DyFM_Crypto {
|
|
31
|
+
private static readonly DEFAULT_CONFIG: Required<CryptoConfig> = {
|
|
32
|
+
ivLength: 16,
|
|
33
|
+
saltLength: 16,
|
|
34
|
+
keyIterations: 10000,
|
|
35
|
+
keySize: 256 / 32
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Tömör: kb. 60–80 karakteres token, nem 200+
|
|
39
|
+
// Nem szabványos: nehéz visszafejteni
|
|
40
|
+
// Használható cookie, header, URL-ben
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validates the input data and key
|
|
44
|
+
* @throws {DyFM_Error} if validation fails
|
|
45
|
+
*/
|
|
46
|
+
private static validateInput<T>(data: T, key: string): void {
|
|
47
|
+
if (data === undefined || data === null) {
|
|
48
|
+
throw new DyFM_Error({
|
|
49
|
+
message: 'Data is required',
|
|
50
|
+
error: new Error('Data is required'),
|
|
51
|
+
errorCode: CryptoErrorCode.INVALID_DATA
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!key || typeof key !== 'string' || key.trim().length === 0) {
|
|
56
|
+
throw new DyFM_Error({
|
|
57
|
+
message: 'Valid key is required',
|
|
58
|
+
error: new Error('Key must be a non-empty string'),
|
|
59
|
+
errorCode: CryptoErrorCode.INVALID_KEY
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Generates a secure random padding
|
|
66
|
+
* @param length Length of the padding in bytes
|
|
67
|
+
*/
|
|
68
|
+
private static generatePadding(length: number): string {
|
|
69
|
+
return CryptoJS.lib.WordArray.random(length).toString();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Derives a key using PBKDF2
|
|
74
|
+
* @param key The input key
|
|
75
|
+
* @param salt The salt to use
|
|
76
|
+
* @param config Configuration options
|
|
77
|
+
*/
|
|
78
|
+
private static deriveKey(key: string, salt: CryptoJS.lib.WordArray, config: Required<CryptoConfig>): CryptoJS.lib.WordArray {
|
|
79
|
+
return CryptoJS.PBKDF2(key, salt, {
|
|
80
|
+
keySize: config.keySize,
|
|
81
|
+
iterations: config.keyIterations
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Safely serializes data to JSON
|
|
87
|
+
* @param data The data to serialize
|
|
88
|
+
* @returns Serialized data as string
|
|
89
|
+
*/
|
|
90
|
+
private static safeSerialize<T>(data: T): string {
|
|
91
|
+
try {
|
|
92
|
+
return JSON.stringify(data);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw new DyFM_Error({
|
|
95
|
+
message: 'Failed to serialize data',
|
|
96
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
97
|
+
errorCode: CryptoErrorCode.INVALID_DATA
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Safely deserializes JSON data
|
|
104
|
+
* @param data The JSON string to deserialize
|
|
105
|
+
* @returns Deserialized data
|
|
106
|
+
*/
|
|
107
|
+
private static safeDeserialize<T>(data: string): T {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(data);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new DyFM_Error({
|
|
112
|
+
message: 'Failed to deserialize data',
|
|
113
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
114
|
+
errorCode: CryptoErrorCode.DECRYPTION_FAILED
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Encrypts data using AES-256-CBC
|
|
121
|
+
* @param data The data to encrypt
|
|
122
|
+
* @param key The encryption key
|
|
123
|
+
* @param config Optional configuration
|
|
124
|
+
* @returns URL-safe encrypted string
|
|
125
|
+
* @throws {DyFM_Error} if encryption fails
|
|
126
|
+
*/
|
|
127
|
+
static encrypt<T>(data: T, key: string, config?: CryptoConfig): string {
|
|
128
|
+
try {
|
|
129
|
+
this.validateInput(data, key);
|
|
130
|
+
const finalConfig = { ...this.DEFAULT_CONFIG, ...config };
|
|
131
|
+
|
|
132
|
+
// Generate random IV and salt
|
|
133
|
+
const iv = CryptoJS.lib.WordArray.random(finalConfig.ivLength);
|
|
134
|
+
const salt = CryptoJS.lib.WordArray.random(finalConfig.saltLength);
|
|
135
|
+
|
|
136
|
+
// Derive key using PBKDF2
|
|
137
|
+
const derivedKey = this.deriveKey(key, salt, finalConfig);
|
|
138
|
+
|
|
139
|
+
// Convert data to string and add random padding
|
|
140
|
+
const dataStr = this.safeSerialize(data);
|
|
141
|
+
const padding = this.generatePadding(16);
|
|
142
|
+
const paddedData = padding + dataStr;
|
|
143
|
+
|
|
144
|
+
// Encrypt the data
|
|
145
|
+
const encrypted = CryptoJS.AES.encrypt(paddedData, derivedKey, {
|
|
146
|
+
iv: iv,
|
|
147
|
+
mode: CryptoJS.mode.CBC,
|
|
148
|
+
padding: CryptoJS.pad.Pkcs7
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Combine IV + Salt + Ciphertext
|
|
152
|
+
const combined = iv.concat(salt).concat(encrypted.ciphertext);
|
|
153
|
+
|
|
154
|
+
// Convert to URL-safe base64
|
|
155
|
+
return CryptoJS.enc.Base64.stringify(combined)
|
|
156
|
+
.replace(/\+/g, '-')
|
|
157
|
+
.replace(/\//g, '_')
|
|
158
|
+
.replace(/=+$/, '');
|
|
159
|
+
} catch (error) {
|
|
160
|
+
throw new DyFM_Error({
|
|
161
|
+
message: 'Error encrypting data',
|
|
162
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
163
|
+
errorCode: CryptoErrorCode.ENCRYPTION_FAILED
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Decrypts data that was encrypted using encrypt()
|
|
170
|
+
* @param encryptedData The encrypted data
|
|
171
|
+
* @param key The decryption key
|
|
172
|
+
* @param config Optional configuration
|
|
173
|
+
* @returns The decrypted data
|
|
174
|
+
* @throws {DyFM_Error} if decryption fails
|
|
175
|
+
*/
|
|
176
|
+
static decrypt<T>(encryptedData: string, key: string, config?: CryptoConfig): T {
|
|
177
|
+
try {
|
|
178
|
+
this.validateInput(encryptedData, key);
|
|
179
|
+
const finalConfig = { ...this.DEFAULT_CONFIG, ...config };
|
|
180
|
+
|
|
181
|
+
// Convert from URL-safe base64
|
|
182
|
+
const base64 = encryptedData
|
|
183
|
+
.replace(/-/g, '+')
|
|
184
|
+
.replace(/_/g, '/');
|
|
185
|
+
|
|
186
|
+
// Parse the combined data
|
|
187
|
+
const combined = CryptoJS.enc.Base64.parse(base64);
|
|
188
|
+
|
|
189
|
+
// Extract IV, salt, and ciphertext
|
|
190
|
+
const iv = CryptoJS.lib.WordArray.create(combined.words.slice(0, finalConfig.ivLength / 4));
|
|
191
|
+
const salt = CryptoJS.lib.WordArray.create(
|
|
192
|
+
combined.words.slice(
|
|
193
|
+
finalConfig.ivLength / 4,
|
|
194
|
+
(finalConfig.ivLength + finalConfig.saltLength) / 4
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
const ciphertext = CryptoJS.lib.WordArray.create(
|
|
198
|
+
combined.words.slice((finalConfig.ivLength + finalConfig.saltLength) / 4)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Derive key using PBKDF2
|
|
202
|
+
const derivedKey = this.deriveKey(key, salt, finalConfig);
|
|
203
|
+
|
|
204
|
+
// Decrypt the data
|
|
205
|
+
const decrypted = CryptoJS.AES.decrypt(
|
|
206
|
+
{ ciphertext: ciphertext },
|
|
207
|
+
derivedKey,
|
|
208
|
+
{
|
|
209
|
+
iv: iv,
|
|
210
|
+
mode: CryptoJS.mode.CBC,
|
|
211
|
+
padding: CryptoJS.pad.Pkcs7
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Remove padding and parse JSON
|
|
216
|
+
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
|
|
217
|
+
const jsonStr = decryptedStr.slice(32); // Remove 16-byte padding
|
|
218
|
+
return this.safeDeserialize<T>(jsonStr);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
throw new DyFM_Error({
|
|
221
|
+
message: 'Error decrypting data',
|
|
222
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
223
|
+
errorCode: CryptoErrorCode.DECRYPTION_FAILED
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Generates a secure random key
|
|
230
|
+
* @param length Length of the key in bytes (default: 32)
|
|
231
|
+
* @returns A secure random key
|
|
232
|
+
*/
|
|
233
|
+
static generateKey(length: number = 32): string {
|
|
234
|
+
return CryptoJS.lib.WordArray.random(length).toString();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Validates if a string is a valid encrypted data
|
|
239
|
+
* @param encryptedData The data to validate
|
|
240
|
+
* @returns true if the data appears to be valid encrypted data
|
|
241
|
+
*/
|
|
242
|
+
static isValidEncryptedData(encryptedData: string): boolean {
|
|
243
|
+
if (!encryptedData || typeof encryptedData !== 'string') {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
return /^[A-Za-z0-9\-_]+$/.test(encryptedData);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
Binary file
|