test-entity-library-asm 3.9.6 → 3.9.8

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.
@@ -4,53 +4,105 @@ exports.JsonEncryptionTransformer = void 0;
4
4
  const crypto = require("crypto");
5
5
  const ENCRYPTION_KEY = process.env.SECRET_ENCRYPTION_KEY || "clave-32-bytes-segura";
6
6
  const ALGORITHM = "aes-256-cbc";
7
- // Crear KeyObject con exactamente 32 bytes para AES-256
8
- const keyObject = crypto.createSecretKey(new Uint8Array(crypto.createHash("sha256").update(ENCRYPTION_KEY).digest()));
9
- function decryptValue(encrypted) {
10
- if (!encrypted.includes(":"))
11
- return encrypted;
12
- const [ivHex, content] = encrypted.split(":");
7
+ // KeyObject de 32 bytes
8
+ const KEY = crypto.createSecretKey(crypto.createHash("sha256").update(String(ENCRYPTION_KEY)).digest());
9
+ function looksLikeCBC(encoded) {
10
+ // formato: iv:cipherHex
11
+ return /^[0-9a-fA-F]+:[0-9a-fA-F]+$/.test(encoded);
12
+ }
13
+ function decryptValue(value) {
14
+ if (typeof value !== "string" || !looksLikeCBC(value))
15
+ return value;
16
+ const [ivHex, contentHex] = value.split(":");
13
17
  const iv = Buffer.from(ivHex, "hex");
14
- // Pasar IV como Uint8Array para que TypeScript no dé error
15
- const decipher = crypto.createDecipheriv(ALGORITHM, keyObject, new Uint8Array(iv));
16
- let decrypted = decipher.update(content, "hex", "utf8");
17
- decrypted += decipher.final("utf8");
18
- return decrypted;
18
+ const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv);
19
+ const dec = Buffer.concat([
20
+ decipher.update(Buffer.from(contentHex, "hex")),
21
+ decipher.final(),
22
+ ]);
23
+ return dec.toString("utf8");
19
24
  }
20
25
  function encryptValue(plain) {
26
+ if (plain === null || plain === undefined)
27
+ return null;
28
+ const text = String(plain);
21
29
  const iv = crypto.randomBytes(16);
22
- // Igual aquí: IV como Uint8Array
23
- const cipher = crypto.createCipheriv(ALGORITHM, keyObject, new Uint8Array(iv));
24
- let encrypted = cipher.update(plain, "utf8", "hex");
25
- encrypted += cipher.final("hex");
26
- return iv.toString("hex") + ":" + encrypted;
30
+ const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
31
+ const enc = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
32
+ return iv.toString("hex") + ":" + enc.toString("hex");
27
33
  }
28
- exports.JsonEncryptionTransformer = {
29
- to(value) {
30
- if (typeof value !== "object" || value === null)
31
- return JSON.stringify({});
32
- const encryptedJson = {};
33
- for (const key in value) {
34
- if (key.startsWith("encrypted_")) {
35
- encryptedJson[key] = encryptValue(value[key]);
34
+ /** Recorre profundo y encripta solo claves `encrypted_*` */
35
+ function deepEncrypt(input) {
36
+ if (input === null || input === undefined)
37
+ return input;
38
+ if (Array.isArray(input)) {
39
+ const arr = [];
40
+ for (let i = 0; i < input.length; i++) {
41
+ arr[i] = deepEncrypt(input[i]);
42
+ }
43
+ return arr;
44
+ }
45
+ if (typeof input === "object") {
46
+ const out = {};
47
+ for (const k in input) {
48
+ const v = input[k];
49
+ if (k.length >= 10 && k.substr(0, 10) === "encrypted_") {
50
+ out[k] = encryptValue(v);
36
51
  }
37
52
  else {
38
- encryptedJson[key] = value[key];
53
+ out[k] = deepEncrypt(v);
39
54
  }
40
55
  }
41
- return JSON.stringify(encryptedJson);
56
+ return out;
57
+ }
58
+ // primitivos
59
+ return input;
60
+ }
61
+ /** Recorre profundo y desencripta solo claves `encrypted_*` */
62
+ function deepDecrypt(input) {
63
+ if (input === null || input === undefined)
64
+ return input;
65
+ if (Array.isArray(input)) {
66
+ const arr = [];
67
+ for (let i = 0; i < input.length; i++) {
68
+ arr[i] = deepDecrypt(input[i]);
69
+ }
70
+ return arr;
71
+ }
72
+ if (typeof input === "object") {
73
+ const out = {};
74
+ for (const k in input) {
75
+ const v = input[k];
76
+ if (k.length >= 10 && k.substr(0, 10) === "encrypted_") {
77
+ try {
78
+ out[k] = decryptValue(v);
79
+ }
80
+ catch {
81
+ out[k] = v; // si está corrupto, lo dejamos como está
82
+ }
83
+ }
84
+ else {
85
+ out[k] = deepDecrypt(v);
86
+ }
87
+ }
88
+ return out;
89
+ }
90
+ // primitivos
91
+ return input;
92
+ }
93
+ exports.JsonEncryptionTransformer = {
94
+ to(value) {
95
+ if (typeof value !== "object" || value === null)
96
+ return JSON.stringify({});
97
+ return JSON.stringify(deepEncrypt(value));
42
98
  },
43
99
  from(dbValue) {
44
100
  try {
45
101
  const parsed = JSON.parse(dbValue);
46
- for (const key in parsed) {
47
- if (key.startsWith("encrypted_")) {
48
- parsed[key] = decryptValue(parsed[key]);
49
- }
50
- }
51
- return parsed;
102
+ return deepDecrypt(parsed);
52
103
  }
53
104
  catch {
105
+ // si no es JSON válido, no tumbar todo
54
106
  return {};
55
107
  }
56
108
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "test-entity-library-asm",
3
- "version": "3.9.6",
3
+ "version": "3.9.8",
4
4
  "description": "Entidades de ejemplo para una base de datos",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/express": "^4.17.21",
23
- "@types/node": "^20.12.7",
23
+ "@types/node": "^20.19.10",
24
24
  "rimraf": "^6.0.1",
25
25
  "typescript": "^5.4.5"
26
26
  },
@@ -5,70 +5,111 @@ const ENCRYPTION_KEY =
5
5
  process.env.SECRET_ENCRYPTION_KEY || "clave-32-bytes-segura";
6
6
  const ALGORITHM = "aes-256-cbc";
7
7
 
8
- // Crear KeyObject con exactamente 32 bytes para AES-256
9
- const keyObject = crypto.createSecretKey(
10
- new Uint8Array(crypto.createHash("sha256").update(ENCRYPTION_KEY).digest())
8
+ // KeyObject de 32 bytes
9
+ const KEY = crypto.createSecretKey(
10
+ crypto.createHash("sha256").update(String(ENCRYPTION_KEY)).digest()
11
11
  );
12
12
 
13
- function decryptValue(encrypted: string): string {
14
- if (!encrypted.includes(":")) return encrypted;
13
+ function looksLikeCBC(encoded: string) {
14
+ // formato: iv:cipherHex
15
+ return /^[0-9a-fA-F]+:[0-9a-fA-F]+$/.test(encoded);
16
+ }
15
17
 
16
- const [ivHex, content] = encrypted.split(":");
18
+ function decryptValue(value: any): any {
19
+ if (typeof value !== "string" || !looksLikeCBC(value)) return value;
20
+ const [ivHex, contentHex] = value.split(":");
17
21
  const iv = Buffer.from(ivHex, "hex");
18
-
19
- // Pasar IV como Uint8Array para que TypeScript no dé error
20
- const decipher = crypto.createDecipheriv(
21
- ALGORITHM,
22
- keyObject,
23
- new Uint8Array(iv)
24
- );
25
- let decrypted = decipher.update(content, "hex", "utf8");
26
- decrypted += decipher.final("utf8");
27
- return decrypted;
22
+ const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv);
23
+ const dec = Buffer.concat([
24
+ decipher.update(Buffer.from(contentHex, "hex")),
25
+ decipher.final(),
26
+ ]);
27
+ return dec.toString("utf8");
28
28
  }
29
29
 
30
- function encryptValue(plain: string): string {
30
+ function encryptValue(plain: any): string | null {
31
+ if (plain === null || plain === undefined) return null;
32
+ const text = String(plain);
31
33
  const iv = crypto.randomBytes(16);
34
+ const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
35
+ const enc = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
36
+ return iv.toString("hex") + ":" + enc.toString("hex");
37
+ }
32
38
 
33
- // Igual aquí: IV como Uint8Array
34
- const cipher = crypto.createCipheriv(
35
- ALGORITHM,
36
- keyObject,
37
- new Uint8Array(iv)
38
- );
39
- let encrypted = cipher.update(plain, "utf8", "hex");
40
- encrypted += cipher.final("hex");
39
+ /** Recorre profundo y encripta solo claves `encrypted_*` */
40
+ function deepEncrypt(input: any): any {
41
+ if (input === null || input === undefined) return input;
41
42
 
42
- return iv.toString("hex") + ":" + encrypted;
43
+ if (Array.isArray(input)) {
44
+ const arr: any[] = [];
45
+ for (let i = 0; i < input.length; i++) {
46
+ arr[i] = deepEncrypt(input[i]);
47
+ }
48
+ return arr;
49
+ }
50
+
51
+ if (typeof input === "object") {
52
+ const out: { [k: string]: any } = {};
53
+ for (const k in input) {
54
+ const v = input[k];
55
+ if (k.length >= 10 && k.substr(0, 10) === "encrypted_") {
56
+ out[k] = encryptValue(v);
57
+ } else {
58
+ out[k] = deepEncrypt(v);
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+
64
+ // primitivos
65
+ return input;
43
66
  }
44
67
 
45
- export const JsonEncryptionTransformer: ValueTransformer = {
46
- to(value: any): string {
47
- if (typeof value !== "object" || value === null) return JSON.stringify({});
68
+ /** Recorre profundo y desencripta solo claves `encrypted_*` */
69
+ function deepDecrypt(input: any): any {
70
+ if (input === null || input === undefined) return input;
48
71
 
49
- const encryptedJson: Record<string, any> = {};
72
+ if (Array.isArray(input)) {
73
+ const arr: any[] = [];
74
+ for (let i = 0; i < input.length; i++) {
75
+ arr[i] = deepDecrypt(input[i]);
76
+ }
77
+ return arr;
78
+ }
50
79
 
51
- for (const key in value) {
52
- if (key.startsWith("encrypted_")) {
53
- encryptedJson[key] = encryptValue(value[key]);
80
+ if (typeof input === "object") {
81
+ const out: { [k: string]: any } = {};
82
+ for (const k in input) {
83
+ const v = input[k];
84
+ if (k.length >= 10 && k.substr(0, 10) === "encrypted_") {
85
+ try {
86
+ out[k] = decryptValue(v);
87
+ } catch {
88
+ out[k] = v; // si está corrupto, lo dejamos como está
89
+ }
54
90
  } else {
55
- encryptedJson[key] = value[key];
91
+ out[k] = deepDecrypt(v);
56
92
  }
57
93
  }
94
+ return out;
95
+ }
96
+
97
+ // primitivos
98
+ return input;
99
+ }
58
100
 
59
- return JSON.stringify(encryptedJson);
101
+ export const JsonEncryptionTransformer: ValueTransformer = {
102
+ to(value: any): string {
103
+ if (typeof value !== "object" || value === null) return JSON.stringify({});
104
+ return JSON.stringify(deepEncrypt(value));
60
105
  },
61
106
 
62
107
  from(dbValue: string): any {
63
108
  try {
64
109
  const parsed = JSON.parse(dbValue);
65
- for (const key in parsed) {
66
- if (key.startsWith("encrypted_")) {
67
- parsed[key] = decryptValue(parsed[key]);
68
- }
69
- }
70
- return parsed;
110
+ return deepDecrypt(parsed);
71
111
  } catch {
112
+ // si no es JSON válido, no tumbar todo
72
113
  return {};
73
114
  }
74
115
  },