@growy/strapi-plugin-encrypted-field 1.9.0 → 2.0.1

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 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
 
@@ -28,7 +28,7 @@ const Input = (props) => {
28
28
  });
29
29
  };
30
30
 
31
- // Extraer solo el nombre del campo sin prefijos
31
+
32
32
  const fieldName = name.includes('.') ? name.split('.').pop() : name;
33
33
  const label = intlLabel?.id ? formatMessage(intlLabel) : (intlLabel || fieldName);
34
34
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growy/strapi-plugin-encrypted-field",
3
- "version": "1.9.0",
3
+ "version": "2.0.1",
4
4
  "description": "Campo personalizado de texto cifrado para Strapi",
5
5
  "strapi": {
6
6
  "name": "encrypted-field",
@@ -2,34 +2,21 @@ const { encrypt, decrypt, validateValue, isEncryptedField } = require('./utils/c
2
2
 
3
3
  module.exports = ({ strapi }) => {
4
4
 
5
- // Obtener tanto content types como componentes
5
+
6
6
  const contentTypes = Object.values(strapi.contentTypes);
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
- strapi.log.info(`[beforeCreate] Valor del campo ${key}: ${value}`);
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
- const decrypted = decrypt(value, strapi);
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
- const decrypted = decrypt(value, strapi);
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
  }
@@ -6,40 +6,38 @@ module.exports = (config, { strapi }) => {
6
6
 
7
7
  if (!ctx.body) return;
8
8
 
9
- // Función recursiva para descifrar campos en cualquier nivel de anidación
9
+
10
10
  const decryptRecursive = (obj, modelUid = null) => {
11
11
  if (!obj || typeof obj !== 'object') return;
12
12
 
13
- // Si es un array, procesar cada elemento
13
+
14
14
  if (Array.isArray(obj)) {
15
15
  obj.forEach(item => decryptRecursive(item, modelUid));
16
16
  return;
17
17
  }
18
18
 
19
- // Detectar si es un componente por el campo __component
19
+
20
20
  let currentModelUid = modelUid;
21
21
  if (obj.__component) {
22
22
  currentModelUid = obj.__component;
23
23
  }
24
24
 
25
- // Obtener el modelo si tenemos un UID
25
+
26
26
  let model = null;
27
27
  if (currentModelUid) {
28
28
  try {
29
29
  model = strapi.getModel(currentModelUid) || strapi.components[currentModelUid];
30
30
  } catch (e) {
31
- // Ignorar si no se encuentra el modelo
31
+
32
32
  }
33
33
  }
34
34
 
35
- // Descifrar campos del modelo actual
35
+
36
36
  if (model?.attributes) {
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
- const decrypted = decrypt(obj[key], strapi);
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
  }
@@ -47,7 +45,7 @@ module.exports = (config, { strapi }) => {
47
45
  }
48
46
  }
49
47
 
50
- // Procesar recursivamente todos los valores del objeto
48
+
51
49
  for (const value of Object.values(obj)) {
52
50
  if (value && typeof value === 'object') {
53
51
  decryptRecursive(value, currentModelUid);
@@ -55,11 +53,11 @@ module.exports = (config, { strapi }) => {
55
53
  }
56
54
  };
57
55
 
58
- // Procesar ctx.body.data si existe
56
+
59
57
  if (ctx.body.data) {
60
58
  decryptRecursive(ctx.body.data);
61
59
  } else {
62
- // Procesar ctx.body directamente
60
+
63
61
  decryptRecursive(ctx.body);
64
62
  }
65
63
  };
@@ -3,8 +3,6 @@ module.exports = ({ strapi }) => {
3
3
 
4
4
  strapi.server.use(decryptMiddleware({}, { strapi }));
5
5
 
6
- strapi.log.info('✓ Middleware de descifrado registrado');
7
-
8
6
  strapi.customFields.register({
9
7
  name: 'encrypted-text',
10
8
  plugin: 'encrypted-field',