@futdevpro/fsm-dynamo 1.10.31 → 1.10.33

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.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Error codes for crypto operations
3
+ */
4
+ export declare enum CryptoErrorCode {
5
+ INVALID_INPUT = "DyFM-CRY-EA0",
6
+ DECRYPTION_FAILED = "DyFM-CRY-DRY",
7
+ ENCRYPTION_FAILED = "DyFM-CRY-ENF",
8
+ INVALID_KEY = "DyFM-CRY-IKY",
9
+ INVALID_DATA = "DyFM-CRY-IDT"
10
+ }
11
+ /**
12
+ * Configuration options for encryption/decryption
13
+ */
14
+ export interface CryptoConfig {
15
+ ivLength?: number;
16
+ saltLength?: number;
17
+ keyIterations?: number;
18
+ keySize?: number;
19
+ }
20
+ /**
21
+ * A utility class for secure encryption and decryption of data
22
+ * Uses AES-256-CBC with PBKDF2 key derivation
23
+ */
24
+ export declare class DyFM_Crypto {
25
+ private static readonly DEFAULT_CONFIG;
26
+ /**
27
+ * Validates the input data and key
28
+ * @throws {DyFM_Error} if validation fails
29
+ */
30
+ private static validateInput;
31
+ /**
32
+ * Generates a secure random padding
33
+ * @param length Length of the padding in bytes
34
+ */
35
+ private static generatePadding;
36
+ /**
37
+ * Derives a key using PBKDF2
38
+ * @param key The input key
39
+ * @param salt The salt to use
40
+ * @param config Configuration options
41
+ */
42
+ private static deriveKey;
43
+ /**
44
+ * Safely serializes data to JSON
45
+ * @param data The data to serialize
46
+ * @returns Serialized data as string
47
+ */
48
+ private static safeSerialize;
49
+ /**
50
+ * Safely deserializes JSON data
51
+ * @param data The JSON string to deserialize
52
+ * @returns Deserialized data
53
+ */
54
+ private static safeDeserialize;
55
+ /**
56
+ * Encrypts data using AES-256-CBC
57
+ * @param data The data to encrypt
58
+ * @param key The encryption key
59
+ * @param config Optional configuration
60
+ * @returns URL-safe encrypted string
61
+ * @throws {DyFM_Error} if encryption fails
62
+ */
63
+ static encrypt<T>(data: T, key: string, config?: CryptoConfig): string;
64
+ /**
65
+ * Decrypts data that was encrypted using encrypt()
66
+ * @param encryptedData The encrypted data
67
+ * @param key The decryption key
68
+ * @param config Optional configuration
69
+ * @returns The decrypted data
70
+ * @throws {DyFM_Error} if decryption fails
71
+ */
72
+ static decrypt<T>(encryptedData: string, key: string, config?: CryptoConfig): T;
73
+ /**
74
+ * Generates a secure random key
75
+ * @param length Length of the key in bytes (default: 32)
76
+ * @returns A secure random key
77
+ */
78
+ static generateKey(length?: number): string;
79
+ /**
80
+ * Validates if a string is a valid encrypted data
81
+ * @param encryptedData The data to validate
82
+ * @returns true if the data appears to be valid encrypted data
83
+ */
84
+ static isValidEncryptedData(encryptedData: string): boolean;
85
+ }
86
+ //# sourceMappingURL=crypto.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/crypto/_collections/crypto.util.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,oBAAY,eAAe;IACzB,aAAa,iBAAiB;IAC9B,iBAAiB,iBAAiB;IAClC,iBAAiB,iBAAiB;IAClC,WAAW,iBAAiB;IAC5B,YAAY,iBAAiB;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAKpC;IAMF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAkB5B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAOxB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAY5B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAY9B;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM;IAyCtE;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,CAAC;IAoD/E;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM;IAI/C;;;;OAIG;IACH,MAAM,CAAC,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;CAM5D"}
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyFM_Crypto = exports.CryptoErrorCode = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const CryptoJS = tslib_1.__importStar(require("crypto-js"));
6
+ const error_control_model_1 = require("../../../_models/control-models/error.control-model");
7
+ /**
8
+ * Error codes for crypto operations
9
+ */
10
+ var CryptoErrorCode;
11
+ (function (CryptoErrorCode) {
12
+ CryptoErrorCode["INVALID_INPUT"] = "DyFM-CRY-EA0";
13
+ CryptoErrorCode["DECRYPTION_FAILED"] = "DyFM-CRY-DRY";
14
+ CryptoErrorCode["ENCRYPTION_FAILED"] = "DyFM-CRY-ENF";
15
+ CryptoErrorCode["INVALID_KEY"] = "DyFM-CRY-IKY";
16
+ CryptoErrorCode["INVALID_DATA"] = "DyFM-CRY-IDT";
17
+ })(CryptoErrorCode || (exports.CryptoErrorCode = CryptoErrorCode = {}));
18
+ /**
19
+ * A utility class for secure encryption and decryption of data
20
+ * Uses AES-256-CBC with PBKDF2 key derivation
21
+ */
22
+ class DyFM_Crypto {
23
+ static DEFAULT_CONFIG = {
24
+ ivLength: 16,
25
+ saltLength: 16,
26
+ keyIterations: 10000,
27
+ keySize: 256 / 32
28
+ };
29
+ // Tömör: kb. 60–80 karakteres token, nem 200+
30
+ // Nem szabványos: nehéz visszafejteni
31
+ // Használható cookie, header, URL-ben
32
+ /**
33
+ * Validates the input data and key
34
+ * @throws {DyFM_Error} if validation fails
35
+ */
36
+ static validateInput(data, key) {
37
+ if (data === undefined || data === null) {
38
+ throw new error_control_model_1.DyFM_Error({
39
+ message: 'Data is required',
40
+ error: new Error('Data is required'),
41
+ errorCode: CryptoErrorCode.INVALID_DATA
42
+ });
43
+ }
44
+ if (!key || typeof key !== 'string' || key.trim().length === 0) {
45
+ throw new error_control_model_1.DyFM_Error({
46
+ message: 'Valid key is required',
47
+ error: new Error('Key must be a non-empty string'),
48
+ errorCode: CryptoErrorCode.INVALID_KEY
49
+ });
50
+ }
51
+ }
52
+ /**
53
+ * Generates a secure random padding
54
+ * @param length Length of the padding in bytes
55
+ */
56
+ static generatePadding(length) {
57
+ return CryptoJS.lib.WordArray.random(length).toString();
58
+ }
59
+ /**
60
+ * Derives a key using PBKDF2
61
+ * @param key The input key
62
+ * @param salt The salt to use
63
+ * @param config Configuration options
64
+ */
65
+ static deriveKey(key, salt, config) {
66
+ return CryptoJS.PBKDF2(key, salt, {
67
+ keySize: config.keySize,
68
+ iterations: config.keyIterations
69
+ });
70
+ }
71
+ /**
72
+ * Safely serializes data to JSON
73
+ * @param data The data to serialize
74
+ * @returns Serialized data as string
75
+ */
76
+ static safeSerialize(data) {
77
+ try {
78
+ return JSON.stringify(data);
79
+ }
80
+ catch (error) {
81
+ throw new error_control_model_1.DyFM_Error({
82
+ message: 'Failed to serialize data',
83
+ error: error instanceof Error ? error : new Error(String(error)),
84
+ errorCode: CryptoErrorCode.INVALID_DATA
85
+ });
86
+ }
87
+ }
88
+ /**
89
+ * Safely deserializes JSON data
90
+ * @param data The JSON string to deserialize
91
+ * @returns Deserialized data
92
+ */
93
+ static safeDeserialize(data) {
94
+ try {
95
+ return JSON.parse(data);
96
+ }
97
+ catch (error) {
98
+ throw new error_control_model_1.DyFM_Error({
99
+ message: 'Failed to deserialize data',
100
+ error: error instanceof Error ? error : new Error(String(error)),
101
+ errorCode: CryptoErrorCode.DECRYPTION_FAILED
102
+ });
103
+ }
104
+ }
105
+ /**
106
+ * Encrypts data using AES-256-CBC
107
+ * @param data The data to encrypt
108
+ * @param key The encryption key
109
+ * @param config Optional configuration
110
+ * @returns URL-safe encrypted string
111
+ * @throws {DyFM_Error} if encryption fails
112
+ */
113
+ static encrypt(data, key, config) {
114
+ try {
115
+ this.validateInput(data, key);
116
+ const finalConfig = { ...this.DEFAULT_CONFIG, ...config };
117
+ // Generate random IV and salt
118
+ const iv = CryptoJS.lib.WordArray.random(finalConfig.ivLength);
119
+ const salt = CryptoJS.lib.WordArray.random(finalConfig.saltLength);
120
+ // Derive key using PBKDF2
121
+ const derivedKey = this.deriveKey(key, salt, finalConfig);
122
+ // Convert data to string and add random padding
123
+ const dataStr = this.safeSerialize(data);
124
+ const padding = this.generatePadding(16);
125
+ const paddedData = padding + dataStr;
126
+ // Encrypt the data
127
+ const encrypted = CryptoJS.AES.encrypt(paddedData, derivedKey, {
128
+ iv: iv,
129
+ mode: CryptoJS.mode.CBC,
130
+ padding: CryptoJS.pad.Pkcs7
131
+ });
132
+ // Combine IV + Salt + Ciphertext
133
+ const combined = iv.concat(salt).concat(encrypted.ciphertext);
134
+ // Convert to URL-safe base64
135
+ return CryptoJS.enc.Base64.stringify(combined)
136
+ .replace(/\+/g, '-')
137
+ .replace(/\//g, '_')
138
+ .replace(/=+$/, '');
139
+ }
140
+ catch (error) {
141
+ throw new error_control_model_1.DyFM_Error({
142
+ message: 'Error encrypting data',
143
+ error: error instanceof Error ? error : new Error(String(error)),
144
+ errorCode: CryptoErrorCode.ENCRYPTION_FAILED
145
+ });
146
+ }
147
+ }
148
+ /**
149
+ * Decrypts data that was encrypted using encrypt()
150
+ * @param encryptedData The encrypted data
151
+ * @param key The decryption key
152
+ * @param config Optional configuration
153
+ * @returns The decrypted data
154
+ * @throws {DyFM_Error} if decryption fails
155
+ */
156
+ static decrypt(encryptedData, key, config) {
157
+ try {
158
+ this.validateInput(encryptedData, key);
159
+ const finalConfig = { ...this.DEFAULT_CONFIG, ...config };
160
+ // Convert from URL-safe base64
161
+ const base64 = encryptedData
162
+ .replace(/-/g, '+')
163
+ .replace(/_/g, '/');
164
+ // Parse the combined data
165
+ const combined = CryptoJS.enc.Base64.parse(base64);
166
+ // Extract IV, salt, and ciphertext
167
+ const iv = CryptoJS.lib.WordArray.create(combined.words.slice(0, finalConfig.ivLength / 4));
168
+ const salt = CryptoJS.lib.WordArray.create(combined.words.slice(finalConfig.ivLength / 4, (finalConfig.ivLength + finalConfig.saltLength) / 4));
169
+ const ciphertext = CryptoJS.lib.WordArray.create(combined.words.slice((finalConfig.ivLength + finalConfig.saltLength) / 4));
170
+ // Derive key using PBKDF2
171
+ const derivedKey = this.deriveKey(key, salt, finalConfig);
172
+ // Decrypt the data
173
+ const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, derivedKey, {
174
+ iv: iv,
175
+ mode: CryptoJS.mode.CBC,
176
+ padding: CryptoJS.pad.Pkcs7
177
+ });
178
+ // Remove padding and parse JSON
179
+ const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
180
+ const jsonStr = decryptedStr.slice(32); // Remove 16-byte padding
181
+ return this.safeDeserialize(jsonStr);
182
+ }
183
+ catch (error) {
184
+ throw new error_control_model_1.DyFM_Error({
185
+ message: 'Error decrypting data',
186
+ error: error instanceof Error ? error : new Error(String(error)),
187
+ errorCode: CryptoErrorCode.DECRYPTION_FAILED
188
+ });
189
+ }
190
+ }
191
+ /**
192
+ * Generates a secure random key
193
+ * @param length Length of the key in bytes (default: 32)
194
+ * @returns A secure random key
195
+ */
196
+ static generateKey(length = 32) {
197
+ return CryptoJS.lib.WordArray.random(length).toString();
198
+ }
199
+ /**
200
+ * Validates if a string is a valid encrypted data
201
+ * @param encryptedData The data to validate
202
+ * @returns true if the data appears to be valid encrypted data
203
+ */
204
+ static isValidEncryptedData(encryptedData) {
205
+ if (!encryptedData || typeof encryptedData !== 'string') {
206
+ return false;
207
+ }
208
+ return /^[A-Za-z0-9\-_]+$/.test(encryptedData);
209
+ }
210
+ }
211
+ exports.DyFM_Crypto = DyFM_Crypto;
212
+ //# sourceMappingURL=crypto.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.util.js","sourceRoot":"","sources":["../../../../src/_modules/crypto/_collections/crypto.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=crypto.util.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.util.spec.d.ts","sourceRoot":"","sources":["../../../../src/_modules/crypto/_collections/crypto.util.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const crypto_util_1 = require("./crypto.util");
4
+ describe('DyFM_Crypto', () => {
5
+ const testKey = 'test-secret-key-123';
6
+ const testData = { id: 1, name: 'test' };
7
+ describe('encrypt', () => {
8
+ it('should successfully encrypt data', () => {
9
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
10
+ expect(encrypted).toBeDefined();
11
+ expect(typeof encrypted).toBe('string');
12
+ expect(encrypted).toMatch(/^[A-Za-z0-9\-_]+$/);
13
+ });
14
+ it('should encrypt different data with different results', () => {
15
+ const data1 = { id: 1 };
16
+ const data2 = { id: 2 };
17
+ const encrypted1 = crypto_util_1.DyFM_Crypto.encrypt(data1, testKey);
18
+ const encrypted2 = crypto_util_1.DyFM_Crypto.encrypt(data2, testKey);
19
+ expect(encrypted1).not.toEqual(encrypted2);
20
+ });
21
+ it('should throw DyFM_Error when encryption fails', () => {
22
+ // @ts-ignore - Testing invalid input
23
+ expect(() => crypto_util_1.DyFM_Crypto.encrypt(undefined, testKey)).toThrow();
24
+ });
25
+ it('should handle complex objects', () => {
26
+ const complexData = {
27
+ id: 1,
28
+ name: 'test',
29
+ nested: {
30
+ value: 'nested-value',
31
+ array: [1, 2, 3]
32
+ }
33
+ };
34
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(complexData, testKey);
35
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
36
+ expect(decrypted).toEqual(complexData);
37
+ });
38
+ it('should handle arrays', () => {
39
+ const arrayData = [1, 'test', { nested: true }];
40
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(arrayData, testKey);
41
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
42
+ expect(decrypted).toEqual(arrayData);
43
+ });
44
+ it('should handle primitive values', () => {
45
+ const stringData = 'test string';
46
+ const numberData = 42;
47
+ const booleanData = true;
48
+ const encryptedString = crypto_util_1.DyFM_Crypto.encrypt(stringData, testKey);
49
+ const encryptedNumber = crypto_util_1.DyFM_Crypto.encrypt(numberData, testKey);
50
+ const encryptedBoolean = crypto_util_1.DyFM_Crypto.encrypt(booleanData, testKey);
51
+ expect(crypto_util_1.DyFM_Crypto.decrypt(encryptedString, testKey)).toBe(stringData);
52
+ expect(crypto_util_1.DyFM_Crypto.decrypt(encryptedNumber, testKey)).toBe(numberData);
53
+ expect(crypto_util_1.DyFM_Crypto.decrypt(encryptedBoolean, testKey)).toBe(booleanData);
54
+ });
55
+ });
56
+ describe('decrypt', () => {
57
+ it('should successfully decrypt encrypted data', () => {
58
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
59
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
60
+ expect(decrypted).toEqual(testData);
61
+ });
62
+ it('should throw DyFM_Error when decryption fails', () => {
63
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt('invalid-encrypted-data', testKey)).toThrow();
64
+ });
65
+ it('should throw DyFM_Error when using wrong key', () => {
66
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
67
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt(encrypted, 'wrong-key')).toThrow();
68
+ });
69
+ it('should throw DyFM_Error when encrypted data is modified', () => {
70
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
71
+ const modified = encrypted.slice(0, -1) + 'A';
72
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt(modified, testKey)).toThrow();
73
+ });
74
+ });
75
+ describe('URL-safe encryption', () => {
76
+ it('should produce URL-safe strings', () => {
77
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
78
+ expect(encrypted).toMatch(/^[A-Za-z0-9\-_]+$/);
79
+ });
80
+ it('should work in HTTP headers', () => {
81
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
82
+ const header = `Bearer ${encrypted}`;
83
+ const extracted = header.split(' ')[1];
84
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(extracted, testKey);
85
+ expect(decrypted).toEqual(testData);
86
+ });
87
+ it('should work in URLs', () => {
88
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
89
+ const url = `https://example.com/api?token=${encrypted}`;
90
+ const params = new URLSearchParams(url.split('?')[1]);
91
+ const extracted = params.get('token');
92
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(extracted, testKey);
93
+ expect(decrypted).toEqual(testData);
94
+ });
95
+ });
96
+ describe('edge cases', () => {
97
+ describe('empty and null values', () => {
98
+ it('should handle empty objects', () => {
99
+ const emptyObj = {};
100
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(emptyObj, testKey);
101
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
102
+ expect(decrypted).toEqual(emptyObj);
103
+ });
104
+ it('should handle empty arrays', () => {
105
+ const emptyArr = [];
106
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(emptyArr, testKey);
107
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
108
+ expect(decrypted).toEqual(emptyArr);
109
+ });
110
+ it('should handle null values in objects', () => {
111
+ const dataWithNull = {
112
+ id: 1,
113
+ name: null,
114
+ nested: { value: null }
115
+ };
116
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(dataWithNull, testKey);
117
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
118
+ expect(decrypted).toEqual(dataWithNull);
119
+ });
120
+ it('should handle undefined values in objects', () => {
121
+ const dataWithUndefined = {
122
+ id: 1,
123
+ name: undefined,
124
+ nested: { value: undefined }
125
+ };
126
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(dataWithUndefined, testKey);
127
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, testKey);
128
+ expect(decrypted).toEqual({ id: 1, nested: {} });
129
+ });
130
+ });
131
+ describe('key edge cases', () => {
132
+ it('should handle very long keys', () => {
133
+ const longKey = 'a'.repeat(1000);
134
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, longKey);
135
+ const decrypted = crypto_util_1.DyFM_Crypto.decrypt(encrypted, longKey);
136
+ expect(decrypted).toEqual(testData);
137
+ });
138
+ it('should handle empty key', () => {
139
+ expect(() => crypto_util_1.DyFM_Crypto.encrypt(testData, '')).toThrow();
140
+ });
141
+ it('should handle whitespace-only keys', () => {
142
+ expect(() => crypto_util_1.DyFM_Crypto.encrypt(testData, ' ')).toThrow();
143
+ });
144
+ });
145
+ describe('encrypted data manipulation', () => {
146
+ it('should detect when encrypted data is truncated', () => {
147
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
148
+ const truncated = encrypted.slice(0, -10);
149
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt(truncated, testKey)).toThrow();
150
+ });
151
+ it('should detect when encrypted data is extended', () => {
152
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
153
+ const extended = encrypted + 'A'.repeat(10);
154
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt(extended, testKey)).toThrow();
155
+ });
156
+ it('should detect when encrypted data is modified in the middle', () => {
157
+ const encrypted = crypto_util_1.DyFM_Crypto.encrypt(testData, testKey);
158
+ const midPoint = Math.floor(encrypted.length / 2);
159
+ const modified = encrypted.slice(0, midPoint) + 'X' + encrypted.slice(midPoint + 1);
160
+ expect(() => crypto_util_1.DyFM_Crypto.decrypt(modified, testKey)).toThrow();
161
+ });
162
+ });
163
+ });
164
+ });
165
+ //# sourceMappingURL=crypto.util.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.util.spec.js","sourceRoot":"","sources":["../../../../src/_modules/crypto/_collections/crypto.util.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './_collections/crypto.util';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/crypto/index.ts"],"names":[],"mappings":"AAEA,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./_collections/crypto.util"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/crypto/index.ts"],"names":[],"mappings":";;;AAEA,qEAA2C"}
package/nodemon.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "exec": "title Test Build of Dynamo-FSM && npm run build-tgz",
2
+ "exec": "title Test Build of Dynamo-FSM && npm run nodemon-run",
3
3
  "restartable": "rs",
4
4
  "delay": "3000",
5
5
  "ext": ".ts,json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/fsm-dynamo",
3
- "version": "01.10.31",
3
+ "version": "01.10.33",
4
4
  "description": "Full Stack Model Collection for Dynamic (NodeJS-Typescript) Framework called Dynamo, by Future Development Ltd.",
5
5
  "scripts": {
6
6
  "prep": "npm i pnpm -g && npm i rimraf nodemon -g",
@@ -15,6 +15,9 @@
15
15
  "build-base": "pnpm i && rimraf ./build && npx tsc",
16
16
  "build-clean": "pnpm run clean && pnpm run build-base",
17
17
  "build-simple": "pnpm i && npx tsc && jasmine",
18
+ "build-n-test": "npm run build-tgz",
19
+
20
+ "nodemon-run": "npm run build-tgz",
18
21
 
19
22
  "clean": "pnpm run prep && rimraf ./build && rimraf package-lock.json && rimraf pnpm-lock.yaml && rimraf ./node_modules",
20
23
  "test": "pnpm run build-base && jasmine",
@@ -72,6 +75,12 @@
72
75
  "module": "./build/_modules/usage/index.js",
73
76
  "types": "./build/_modules/usage/index.d.ts",
74
77
  "typings": "./build/_modules/usage/index.d.ts"
78
+ },
79
+ "./crypto": {
80
+ "default": "./build/_modules/crypto/index.js",
81
+ "module": "./build/_modules/crypto/index.js",
82
+ "types": "./build/_modules/crypto/index.d.ts",
83
+ "typings": "./build/_modules/crypto/index.d.ts"
75
84
  }
76
85
  },
77
86
  "typesVersions": {
@@ -82,7 +91,8 @@
82
91
  "pipe": [ "build/_modules/pipe/index.d.ts" ],
83
92
  "socket": [ "build/_modules/socket/index.d.ts" ],
84
93
  "test": [ "build/_modules/test/index.d.ts" ],
85
- "usage": [ "build/_modules/usage/index.d.ts" ]
94
+ "usage": [ "build/_modules/usage/index.d.ts" ],
95
+ "crypto": [ "build/_modules/crypto/index.d.ts" ]
86
96
  }
87
97
  },
88
98
  "keywords": [],
@@ -110,6 +120,7 @@
110
120
  "eslint-plugin-unused-imports": "^4.1.4",
111
121
  "jasmine": "~5.1.0",
112
122
  "jasmine-spec-reporter": "^7.0.0",
123
+ "crypto-js": "~4.2.0",
113
124
  "openai": "^4.93.0"
114
125
  }
115
126
  }
@@ -0,0 +1,195 @@
1
+ import { DyFM_Crypto } from './crypto.util';
2
+
3
+ describe('DyFM_Crypto', () => {
4
+ const testKey = 'test-secret-key-123';
5
+ const testData = { id: 1, name: 'test' };
6
+
7
+ describe('encrypt', () => {
8
+ it('should successfully encrypt data', () => {
9
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
10
+
11
+ expect(encrypted).toBeDefined();
12
+ expect(typeof encrypted).toBe('string');
13
+ expect(encrypted).toMatch(/^[A-Za-z0-9\-_]+$/);
14
+ });
15
+
16
+ it('should encrypt different data with different results', () => {
17
+ const data1 = { id: 1 };
18
+ const data2 = { id: 2 };
19
+
20
+ const encrypted1 = DyFM_Crypto.encrypt(data1, testKey);
21
+ const encrypted2 = DyFM_Crypto.encrypt(data2, testKey);
22
+
23
+ expect(encrypted1).not.toEqual(encrypted2);
24
+ });
25
+
26
+ it('should throw DyFM_Error when encryption fails', () => {
27
+ // @ts-ignore - Testing invalid input
28
+ expect(() => DyFM_Crypto.encrypt(undefined, testKey)).toThrow();
29
+ });
30
+
31
+ it('should handle complex objects', () => {
32
+ const complexData = {
33
+ id: 1,
34
+ name: 'test',
35
+ nested: {
36
+ value: 'nested-value',
37
+ array: [1, 2, 3]
38
+ }
39
+ };
40
+
41
+ const encrypted = DyFM_Crypto.encrypt(complexData, testKey);
42
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
43
+
44
+ expect(decrypted).toEqual(complexData);
45
+ });
46
+
47
+ it('should handle arrays', () => {
48
+ const arrayData = [1, 'test', { nested: true }];
49
+ const encrypted = DyFM_Crypto.encrypt(arrayData, testKey);
50
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
51
+
52
+ expect(decrypted).toEqual(arrayData);
53
+ });
54
+
55
+ it('should handle primitive values', () => {
56
+ const stringData = 'test string';
57
+ const numberData = 42;
58
+ const booleanData = true;
59
+
60
+ const encryptedString = DyFM_Crypto.encrypt(stringData, testKey);
61
+ const encryptedNumber = DyFM_Crypto.encrypt(numberData, testKey);
62
+ const encryptedBoolean = DyFM_Crypto.encrypt(booleanData, testKey);
63
+
64
+ expect(DyFM_Crypto.decrypt(encryptedString, testKey)).toBe(stringData);
65
+ expect(DyFM_Crypto.decrypt(encryptedNumber, testKey)).toBe(numberData);
66
+ expect(DyFM_Crypto.decrypt(encryptedBoolean, testKey)).toBe(booleanData);
67
+ });
68
+ });
69
+
70
+ describe('decrypt', () => {
71
+ it('should successfully decrypt encrypted data', () => {
72
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
73
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
74
+
75
+ expect(decrypted).toEqual(testData);
76
+ });
77
+
78
+ it('should throw DyFM_Error when decryption fails', () => {
79
+ expect(() => DyFM_Crypto.decrypt('invalid-encrypted-data', testKey)).toThrow();
80
+ });
81
+
82
+ it('should throw DyFM_Error when using wrong key', () => {
83
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
84
+ expect(() => DyFM_Crypto.decrypt(encrypted, 'wrong-key')).toThrow();
85
+ });
86
+
87
+ it('should throw DyFM_Error when encrypted data is modified', () => {
88
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
89
+ const modified = encrypted.slice(0, -1) + 'A';
90
+ expect(() => DyFM_Crypto.decrypt(modified, testKey)).toThrow();
91
+ });
92
+ });
93
+
94
+ describe('URL-safe encryption', () => {
95
+ it('should produce URL-safe strings', () => {
96
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
97
+ expect(encrypted).toMatch(/^[A-Za-z0-9\-_]+$/);
98
+ });
99
+
100
+ it('should work in HTTP headers', () => {
101
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
102
+ const header = `Bearer ${encrypted}`;
103
+ const extracted = header.split(' ')[1];
104
+ const decrypted = DyFM_Crypto.decrypt(extracted, testKey);
105
+ expect(decrypted).toEqual(testData);
106
+ });
107
+
108
+ it('should work in URLs', () => {
109
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
110
+ const url = `https://example.com/api?token=${encrypted}`;
111
+ const params = new URLSearchParams(url.split('?')[1]);
112
+ const extracted = params.get('token');
113
+ const decrypted = DyFM_Crypto.decrypt(extracted!, testKey);
114
+ expect(decrypted).toEqual(testData);
115
+ });
116
+ });
117
+
118
+ describe('edge cases', () => {
119
+ describe('empty and null values', () => {
120
+ it('should handle empty objects', () => {
121
+ const emptyObj = {};
122
+ const encrypted = DyFM_Crypto.encrypt(emptyObj, testKey);
123
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
124
+ expect(decrypted).toEqual(emptyObj);
125
+ });
126
+
127
+ it('should handle empty arrays', () => {
128
+ const emptyArr: any[] = [];
129
+ const encrypted = DyFM_Crypto.encrypt(emptyArr, testKey);
130
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
131
+ expect(decrypted).toEqual(emptyArr);
132
+ });
133
+
134
+ it('should handle null values in objects', () => {
135
+ const dataWithNull = {
136
+ id: 1,
137
+ name: null,
138
+ nested: { value: null }
139
+ };
140
+ const encrypted = DyFM_Crypto.encrypt(dataWithNull, testKey);
141
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
142
+ expect(decrypted).toEqual(dataWithNull);
143
+ });
144
+
145
+ it('should handle undefined values in objects', () => {
146
+ const dataWithUndefined = {
147
+ id: 1,
148
+ name: undefined,
149
+ nested: { value: undefined }
150
+ };
151
+ const encrypted = DyFM_Crypto.encrypt(dataWithUndefined, testKey);
152
+ const decrypted = DyFM_Crypto.decrypt(encrypted, testKey);
153
+ expect(decrypted).toEqual({ id: 1, nested: {} });
154
+ });
155
+ });
156
+
157
+ describe('key edge cases', () => {
158
+ it('should handle very long keys', () => {
159
+ const longKey = 'a'.repeat(1000);
160
+ const encrypted = DyFM_Crypto.encrypt(testData, longKey);
161
+ const decrypted = DyFM_Crypto.decrypt(encrypted, longKey);
162
+ expect(decrypted).toEqual(testData);
163
+ });
164
+
165
+ it('should handle empty key', () => {
166
+ expect(() => DyFM_Crypto.encrypt(testData, '')).toThrow();
167
+ });
168
+
169
+ it('should handle whitespace-only keys', () => {
170
+ expect(() => DyFM_Crypto.encrypt(testData, ' ')).toThrow();
171
+ });
172
+ });
173
+
174
+ describe('encrypted data manipulation', () => {
175
+ it('should detect when encrypted data is truncated', () => {
176
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
177
+ const truncated = encrypted.slice(0, -10);
178
+ expect(() => DyFM_Crypto.decrypt(truncated, testKey)).toThrow();
179
+ });
180
+
181
+ it('should detect when encrypted data is extended', () => {
182
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
183
+ const extended = encrypted + 'A'.repeat(10);
184
+ expect(() => DyFM_Crypto.decrypt(extended, testKey)).toThrow();
185
+ });
186
+
187
+ it('should detect when encrypted data is modified in the middle', () => {
188
+ const encrypted = DyFM_Crypto.encrypt(testData, testKey);
189
+ const midPoint = Math.floor(encrypted.length / 2);
190
+ const modified = encrypted.slice(0, midPoint) + 'X' + encrypted.slice(midPoint + 1);
191
+ expect(() => DyFM_Crypto.decrypt(modified, testKey)).toThrow();
192
+ });
193
+ });
194
+ });
195
+ });
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+
2
+
3
+ export * from './_collections/crypto.util';
Binary file