@growy/strapi-plugin-encrypted-field 1.9.0 → 2.0.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.
- package/README.md +2 -1
- package/package.json +1 -1
- package/server/bootstrap.js +4 -34
- package/server/middlewares/decrypt.js +1 -3
- package/server/register.js +0 -2
package/README.md
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
Plugin oficial de **Growy AI** para Strapi que proporciona un campo personalizado de texto cifrado con AES-256-GCM. Protege información sensible directamente en tu base de datos con cifrado transparente y validación robusta.
|
|
10
10
|
|
|
11
|
-
## Características
|
|
12
11
|
|
|
13
12
|
- ✅ **Campo personalizado** "Texto Cifrado" en el Content-Type Builder
|
|
14
13
|
- ✅ **Cifrado automático** AES-256-GCM al guardar
|
|
@@ -18,6 +17,7 @@ Plugin oficial de **Growy AI** para Strapi que proporciona un campo personalizad
|
|
|
18
17
|
- ✅ **Gestión de claves robusta** con validación y mensajes de error claros
|
|
19
18
|
- ✅ **Datos cifrados** en base de datos con IV único y Auth Tag
|
|
20
19
|
- ✅ **Reutilizable** en cualquier colección o componente
|
|
20
|
+
- ✅ **Soporte completo** para componentes anidados y estructuras complejas
|
|
21
21
|
|
|
22
22
|
## Instalación
|
|
23
23
|
|
|
@@ -137,6 +137,7 @@ El campo funciona como un campo de texto normal:
|
|
|
137
137
|
- **Al guardar**: Se cifra automáticamente
|
|
138
138
|
- **Al leer**: Se descifra automáticamente
|
|
139
139
|
- **En la BD**: Se guarda cifrado con formato `iv:authTag:encrypted`
|
|
140
|
+
- **En componentes**: Funciona igual en componentes anidados de cualquier profundidad
|
|
140
141
|
|
|
141
142
|
### 3. Uso por API
|
|
142
143
|
|
package/package.json
CHANGED
package/server/bootstrap.js
CHANGED
|
@@ -7,29 +7,16 @@ module.exports = ({ strapi }) => {
|
|
|
7
7
|
const components = Object.values(strapi.components);
|
|
8
8
|
const allModels = [...contentTypes, ...components];
|
|
9
9
|
|
|
10
|
-
strapi.log.info(`Total de content types: ${contentTypes.length}, componentes: ${components.length}`);
|
|
11
|
-
|
|
12
10
|
allModels.forEach((model) => {
|
|
13
11
|
const attributes = model.attributes || {};
|
|
14
12
|
|
|
15
|
-
// Debug: mostrar todos los campos del modelo
|
|
16
|
-
strapi.log.debug(`Modelo ${model.uid}: ${Object.keys(attributes).length} atributos`);
|
|
17
|
-
|
|
18
13
|
const encryptedFields = Object.entries(attributes)
|
|
19
|
-
.filter(([key, attr]) =>
|
|
20
|
-
const isEncrypted = isEncryptedField(attr);
|
|
21
|
-
if (attr.customField) {
|
|
22
|
-
strapi.log.debug(` - ${key}: customField = ${attr.customField}, isEncrypted = ${isEncrypted}`);
|
|
23
|
-
}
|
|
24
|
-
return isEncrypted;
|
|
25
|
-
})
|
|
14
|
+
.filter(([key, attr]) => isEncryptedField(attr))
|
|
26
15
|
.map(([key]) => key);
|
|
27
16
|
|
|
28
17
|
if (encryptedFields.length === 0) return;
|
|
29
18
|
|
|
30
19
|
const uid = model.uid;
|
|
31
|
-
|
|
32
|
-
strapi.log.info(`✓ Registrando lifecycles de cifrado para ${uid} - Campos: ${encryptedFields.join(', ')}`);
|
|
33
20
|
|
|
34
21
|
|
|
35
22
|
strapi.db.lifecycles.subscribe({
|
|
@@ -38,9 +25,6 @@ module.exports = ({ strapi }) => {
|
|
|
38
25
|
async beforeCreate(event) {
|
|
39
26
|
const { data } = event.params;
|
|
40
27
|
|
|
41
|
-
strapi.log.info(`[beforeCreate] Evento recibido para ${event.model?.uid}`);
|
|
42
|
-
strapi.log.info(`[beforeCreate] Data recibida: ${JSON.stringify(data)}`);
|
|
43
|
-
|
|
44
28
|
if (!event.model?.uid) return;
|
|
45
29
|
|
|
46
30
|
const currentModel = strapi.getModel(event.model.uid);
|
|
@@ -50,26 +34,17 @@ module.exports = ({ strapi }) => {
|
|
|
50
34
|
for (const [key, attribute] of Object.entries(currentModel.attributes)) {
|
|
51
35
|
if (!isEncryptedField(attribute)) continue;
|
|
52
36
|
|
|
53
|
-
strapi.log.info(`[beforeCreate] Campo cifrado detectado: ${key}`);
|
|
54
|
-
|
|
55
37
|
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
56
38
|
const value = data[key];
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (value === null || value === undefined || value === '') {
|
|
61
|
-
strapi.log.info(`[beforeCreate] Valor vacío, saltando cifrado`);
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
40
|
+
if (value === null || value === undefined || value === '') continue;
|
|
64
41
|
|
|
65
42
|
const validation = validateValue(value, attribute);
|
|
66
43
|
if (!validation.valid) {
|
|
67
44
|
throw new Error(`Validación fallida para el campo "${key}": ${validation.error}`);
|
|
68
45
|
}
|
|
69
46
|
|
|
70
|
-
strapi.log.info(`✓ Cifrando campo ${key} con valor: ${value}`);
|
|
71
47
|
data[key] = encrypt(value, strapi);
|
|
72
|
-
strapi.log.info(`✓ Campo ${key} cifrado exitosamente`);
|
|
73
48
|
}
|
|
74
49
|
}
|
|
75
50
|
},
|
|
@@ -93,7 +68,6 @@ module.exports = ({ strapi }) => {
|
|
|
93
68
|
throw new Error(`Validación fallida para el campo "${key}": ${validation.error}`);
|
|
94
69
|
}
|
|
95
70
|
|
|
96
|
-
strapi.log.info(`Cifrando campo ${key} en ${event.model.uid}`);
|
|
97
71
|
data[key] = encrypt(value, strapi);
|
|
98
72
|
}
|
|
99
73
|
}
|
|
@@ -113,9 +87,7 @@ module.exports = ({ strapi }) => {
|
|
|
113
87
|
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
114
88
|
const value = result[key];
|
|
115
89
|
if (typeof value === 'string' && value) {
|
|
116
|
-
|
|
117
|
-
strapi.log.info(`Descifrando campo ${key} en ${event.model.uid}: ${value.substring(0, 20)}... -> ${decrypted}`);
|
|
118
|
-
result[key] = decrypted;
|
|
90
|
+
result[key] = decrypt(value, strapi);
|
|
119
91
|
}
|
|
120
92
|
}
|
|
121
93
|
}
|
|
@@ -136,9 +108,7 @@ module.exports = ({ strapi }) => {
|
|
|
136
108
|
if (Object.prototype.hasOwnProperty.call(item, key)) {
|
|
137
109
|
const value = item[key];
|
|
138
110
|
if (typeof value === 'string' && value) {
|
|
139
|
-
|
|
140
|
-
strapi.log.info(`Descifrando campo ${key}: ${value.substring(0, 20)}... -> ${decrypted}`);
|
|
141
|
-
item[key] = decrypted;
|
|
111
|
+
item[key] = decrypt(value, strapi);
|
|
142
112
|
}
|
|
143
113
|
}
|
|
144
114
|
}
|
|
@@ -37,9 +37,7 @@ module.exports = (config, { strapi }) => {
|
|
|
37
37
|
for (const [key, attribute] of Object.entries(model.attributes)) {
|
|
38
38
|
if (isEncryptedField(attribute) && obj[key] && typeof obj[key] === 'string') {
|
|
39
39
|
try {
|
|
40
|
-
|
|
41
|
-
strapi.log.info(`[Middleware] Descifrando ${key} en ${currentModelUid}: ${obj[key].substring(0, 20)}... -> ${decrypted}`);
|
|
42
|
-
obj[key] = decrypted;
|
|
40
|
+
obj[key] = decrypt(obj[key], strapi);
|
|
43
41
|
} catch (error) {
|
|
44
42
|
strapi.log.error(`Error descifrando campo ${key}: ${error.message}`);
|
|
45
43
|
}
|
package/server/register.js
CHANGED