@growy/strapi-plugin-encrypted-field 2.3.2 → 2.3.3
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 +170 -114
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,28 +6,22 @@
|
|
|
6
6
|
<img src="https://img.shields.io/badge/Strapi-v5-blueviolet" alt="Strapi v5" />
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- ✅ **
|
|
22
|
-
- ✅ **
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- ✅ **Native Strapi v5 UI** with visibility controls, redimensionable inputs and copy to clipboard.
|
|
26
|
-
- ✅ **Multi-language support (i18n)**: English and Spanish.
|
|
27
|
-
- ✅ **Encrypted Data** in database with unique IV and Auth Tag.
|
|
28
|
-
- ✅ **Nested Components support** at any depth.
|
|
29
|
-
|
|
30
|
-
### Installation
|
|
9
|
+
Official **Growy AI** plugin for Strapi that provides a custom encrypted text field using AES-256-GCM. Protect sensitive information directly in your database with transparent encryption and robust validation.
|
|
10
|
+
|
|
11
|
+
- ✅ **Custom field** "Encrypted Text" in the Content-Type Builder
|
|
12
|
+
- ✅ **Automatic encryption** AES-256-GCM on save
|
|
13
|
+
- ✅ **Transparent decryption** on read (admin panel and API)
|
|
14
|
+
- ✅ **Backend validation** with regex and length constraint support
|
|
15
|
+
- ✅ **Native Strapi v5 UI** with visibility controls, resizable inputs and copy to clipboard
|
|
16
|
+
- ✅ **Values hidden** by default with show/hide toggle
|
|
17
|
+
- ✅ **Copy notifications** confirmation when copying values
|
|
18
|
+
- ✅ **Multi-language support (i18n)**: English and Spanish
|
|
19
|
+
- ✅ **Robust key management** with validation and clear error messages
|
|
20
|
+
- ✅ **Encrypted data** in database with unique IV and Auth Tag per operation
|
|
21
|
+
- ✅ **Reusable** in any collection or component
|
|
22
|
+
- ✅ **Full support** for nested components and complex structures
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
31
25
|
|
|
32
26
|
```bash
|
|
33
27
|
npm install @growy/strapi-plugin-encrypted-field
|
|
@@ -35,10 +29,12 @@ npm install @growy/strapi-plugin-encrypted-field
|
|
|
35
29
|
yarn add @growy/strapi-plugin-encrypted-field
|
|
36
30
|
```
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
### 1. Enable the plugin
|
|
35
|
+
|
|
36
|
+
Create or edit `config/plugins.js` or `config/plugins.ts`:
|
|
39
37
|
|
|
40
|
-
#### 1. Enable the plugin
|
|
41
|
-
Edit `config/plugins.js` or `config/plugins.ts`:
|
|
42
38
|
```javascript
|
|
43
39
|
module.exports = {
|
|
44
40
|
'encrypted-field': {
|
|
@@ -47,140 +43,200 @@ module.exports = {
|
|
|
47
43
|
};
|
|
48
44
|
```
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
### 2. Configure the encryption key (REQUIRED)
|
|
47
|
+
|
|
48
|
+
#### Option A: Environment variable (recommended)
|
|
49
|
+
|
|
51
50
|
Add to your `.env`:
|
|
51
|
+
|
|
52
52
|
```bash
|
|
53
53
|
ENCRYPTION_KEY=your_64_character_hex_key_here
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
#### Option B: Configuration file
|
|
57
|
+
|
|
58
|
+
Edit `config/plugins.js`:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
module.exports = ({ env }) => ({
|
|
62
|
+
'encrypted-field': {
|
|
63
|
+
enabled: true,
|
|
64
|
+
config: {
|
|
65
|
+
encryptionKey: env('ENCRYPTION_KEY'),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Generate a secure key
|
|
72
|
+
|
|
57
73
|
```bash
|
|
58
74
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
59
75
|
```
|
|
60
76
|
|
|
77
|
+
This will generate a 64-character hexadecimal key (32 bytes).
|
|
78
|
+
|
|
61
79
|
⚠️ **CRITICAL - Key Management**:
|
|
62
|
-
- **Store the key
|
|
63
|
-
- **Never** include it in version control
|
|
64
|
-
- **If you lose the key**, you will
|
|
65
|
-
- **Use the same key** across all environments sharing the same database
|
|
80
|
+
- **Store the key securely** (secrets manager, encrypted environment variables)
|
|
81
|
+
- **Never** include it in version control
|
|
82
|
+
- **If you lose the key**, you will not be able to decrypt existing data
|
|
83
|
+
- **Use the same key** across all environments sharing the same database
|
|
84
|
+
- **For production**, consider services like AWS Secrets Manager, HashiCorp Vault or similar
|
|
85
|
+
|
|
86
|
+
### 3. Rebuild the admin
|
|
66
87
|
|
|
67
|
-
|
|
88
|
+
```bash
|
|
89
|
+
npm run build
|
|
90
|
+
npm run develop
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Requirements
|
|
94
|
+
|
|
95
|
+
- **Strapi**: v5.0.0 or higher
|
|
96
|
+
- **Node.js**: 18.x - 22.x
|
|
97
|
+
- **npm**: 6.0.0 or higher
|
|
98
|
+
|
|
99
|
+
## Data Validation
|
|
68
100
|
|
|
69
|
-
#### Data Validation
|
|
70
101
|
The plugin supports validation before encryption:
|
|
71
|
-
1. In Content-Type Builder, select the encrypted field.
|
|
72
|
-
2. Go to **"Advanced Settings"**.
|
|
73
|
-
3. In **"RegEx pattern"**, enter your regular expression.
|
|
74
|
-
**Example**: To validate an API key format: `^sk-[a-zA-Z0-9]{32}$`.
|
|
75
102
|
|
|
76
|
-
|
|
77
|
-
The API returns decrypted values automatically for authorized requests.
|
|
78
|
-
```bash
|
|
79
|
-
# Create an entry
|
|
80
|
-
curl -X POST http://localhost:1337/api/users \
|
|
81
|
-
-H "Content-Type: application/json" \
|
|
82
|
-
-d '{"data": {"apiKey": "my-secret-token"}}'
|
|
103
|
+
### Configure regex validation
|
|
83
104
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
1. In Content-Type Builder, select the encrypted field
|
|
106
|
+
2. Go to the **"Advanced Settings"** tab
|
|
107
|
+
3. In **"RegEx pattern"**, enter your regular expression
|
|
108
|
+
4. Save the changes
|
|
109
|
+
|
|
110
|
+
**Example**: To validate API key format:
|
|
111
|
+
```regex
|
|
112
|
+
^sk-[a-zA-Z0-9]{32}$
|
|
87
113
|
```
|
|
88
114
|
|
|
89
|
-
|
|
115
|
+
If the value does not match the pattern, an error will be thrown before encryption.
|
|
116
|
+
|
|
117
|
+
## Usage
|
|
90
118
|
|
|
91
|
-
|
|
119
|
+
### 1. Add an encrypted field to a collection
|
|
92
120
|
|
|
93
|
-
|
|
121
|
+
1. Go to **Content-Type Builder**
|
|
122
|
+
2. Select a collection or create a new one
|
|
123
|
+
3. Click **"Add another field"**
|
|
124
|
+
4. Search for **"Encrypted Text"** (with 🔒 icon)
|
|
125
|
+
5. Set the field name
|
|
126
|
+
6. Save and restart Strapi
|
|
94
127
|
|
|
95
|
-
###
|
|
128
|
+
### 2. Using the field
|
|
96
129
|
|
|
97
|
-
|
|
98
|
-
- ✅ **Cifrado automático** AES-256-GCM al guardar.
|
|
99
|
-
- ✅ **Descifrado transparente** al leer (panel y API).
|
|
100
|
-
- ✅ **Validación backend** con soporte para regex y restricciones.
|
|
101
|
-
- ✅ **UI Nativa Strapi v5** con controles de visibilidad, inputs redimensionables y copiar al portapapeles.
|
|
102
|
-
- ✅ **Soporte multi-idioma (i18n)**: Inglés y Español.
|
|
103
|
-
- ✅ **Datos cifrados** en base de datos con IV único y Auth Tag.
|
|
104
|
-
- ✅ **Soporte para componentes anidados** a cualquier profundidad.
|
|
130
|
+
The field works like a regular text field with additional security features:
|
|
105
131
|
|
|
106
|
-
|
|
132
|
+
- **In the panel**: Type text normally
|
|
133
|
+
- **Hidden values**: Values are shown as `***` by default
|
|
134
|
+
- **Eye button**: Toggles between show/hide the value
|
|
135
|
+
- **Copy button**: Copies the value to clipboard with a confirmation notification
|
|
136
|
+
- **On save**: Automatically encrypted
|
|
137
|
+
- **On read**: Automatically decrypted
|
|
138
|
+
- **In the DB**: Stored encrypted with format `iv:authTag:encrypted`
|
|
139
|
+
- **In components**: Works the same in nested components at any depth
|
|
140
|
+
|
|
141
|
+
### 3. API Usage
|
|
107
142
|
|
|
108
143
|
```bash
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
144
|
+
# Create with an encrypted field
|
|
145
|
+
curl -X POST http://localhost:1337/api/users \
|
|
146
|
+
-H "Content-Type: application/json" \
|
|
147
|
+
-d '{
|
|
148
|
+
"data": {
|
|
149
|
+
"name": "John",
|
|
150
|
+
"apiKey": "my-secret-key-123"
|
|
151
|
+
}
|
|
152
|
+
}'
|
|
153
|
+
|
|
154
|
+
# Read (returns decrypted)
|
|
155
|
+
curl -X GET http://localhost:1337/api/users/1
|
|
156
|
+
# Response: { "name": "John", "apiKey": "my-secret-key-123" }
|
|
112
157
|
```
|
|
113
158
|
|
|
114
|
-
|
|
159
|
+
## Usage Example
|
|
115
160
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
161
|
+
### "User" collection with an encrypted API Key
|
|
162
|
+
|
|
163
|
+
**Schema:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"name": "string",
|
|
167
|
+
"email": "email",
|
|
168
|
+
"apiKey": "plugin::encrypted-field.encrypted-text"
|
|
169
|
+
}
|
|
124
170
|
```
|
|
125
171
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
ENCRYPTION_KEY=tu_clave_de_64_caracteres_hexadecimales_aqui
|
|
172
|
+
**In the DB:**
|
|
173
|
+
```
|
|
174
|
+
apiKey: "a1b2c3d4e5f6....:f9e8d7c6b5a4....:9f8e7d6c5b4a3..."
|
|
130
175
|
```
|
|
131
176
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
-
|
|
135
|
-
|
|
177
|
+
**In the panel and API:**
|
|
178
|
+
```
|
|
179
|
+
apiKey: "sk-1234567890abcdef"
|
|
180
|
+
```
|
|
136
181
|
|
|
137
|
-
|
|
182
|
+
## Security & Architecture
|
|
138
183
|
|
|
139
|
-
|
|
140
|
-
El plugin soporta validación antes del cifrado:
|
|
141
|
-
1. En el Content-Type Builder, selecciona el campo cifrado.
|
|
142
|
-
2. Ve a la pestaña **"Advanced Settings"**.
|
|
143
|
-
3. En **"RegEx pattern"**, ingresa tu expresión regular.
|
|
144
|
-
**Ejemplo**: Para validar formato de API key: `^sk-[a-zA-Z0-9]{32}$`.
|
|
184
|
+
### Technical Specifications
|
|
145
185
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
-d '{"data": {"apiKey": "mi-clave-secreta-123"}}'
|
|
186
|
+
- **Algorithm**: AES-256-GCM (NIST standard, military grade)
|
|
187
|
+
- **Key size**: 256 bits (32 bytes, 64 hex characters)
|
|
188
|
+
- **IV (Initialization Vector)**: 96 bits (12 bytes) randomly generated per operation
|
|
189
|
+
- **Auth Tag**: 128 bits (16 bytes) for integrity verification
|
|
190
|
+
- **Stored format**: `iv:authTag:encryptedData` (all in hexadecimal)
|
|
191
|
+
- **Key caching**: Encryption key is parsed and cached in memory for optimal performance
|
|
153
192
|
|
|
154
|
-
|
|
155
|
-
curl -X GET http://localhost:1337/api/usuarios/1
|
|
156
|
-
# Response: { "apiKey": "mi-clave-secreta-123" }
|
|
157
|
-
```
|
|
193
|
+
### Security Features
|
|
158
194
|
|
|
159
|
-
|
|
195
|
+
- ✅ **Authenticated encryption**: GCM provides both confidentiality and integrity
|
|
196
|
+
- ✅ **Unique IV**: Every encryption operation generates a random IV
|
|
197
|
+
- ✅ **Tamper resistance**: Auth Tag detects any modification
|
|
198
|
+
- ✅ **Input validation**: Regex and custom constraints supported
|
|
199
|
+
- ✅ **Safe error handling**: Controlled logs without exposing sensitive data
|
|
200
|
+
- ✅ **Double-layer decryption**: Lifecycle hooks (internal) + middleware (API responses)
|
|
160
201
|
|
|
161
|
-
|
|
162
|
-
- **IV (Initialization Vector)**: 96 bits generado aleatoriamente por operación.
|
|
163
|
-
- **Integridad**: Auth Tag de 128 bits para detectar manipulaciones.
|
|
164
|
-
- **Formato almacenado**: `iv:authTag:encryptedData`.
|
|
202
|
+
### Best Practices
|
|
165
203
|
|
|
166
|
-
|
|
204
|
+
1. **Key rotation**: Plan a periodic rotation process
|
|
205
|
+
2. **Environment separation**: Use different keys per dev/staging/prod
|
|
206
|
+
3. **Auditing**: Monitor encryption/decryption error logs
|
|
207
|
+
4. **Key backup**: Keep secure copies of keys in multiple locations
|
|
208
|
+
5. **Private fields**: Mark sensitive fields as "private" to exclude them from the public API
|
|
167
209
|
|
|
168
|
-
|
|
169
|
-
- ❌ **Ordenamiento**: No se puede ordenar por campos cifrados.
|
|
170
|
-
- ❌ **Filtros**: No se pueden aplicar filtros directos en la consulta a la BD.
|
|
210
|
+
## Use Cases
|
|
171
211
|
|
|
172
|
-
|
|
212
|
+
- 🔑 Third-party API Keys
|
|
213
|
+
- 🔐 Access tokens
|
|
214
|
+
- 🔒 Webhook secrets
|
|
215
|
+
- 💳 Sensitive information
|
|
216
|
+
- 📧 SMTP credentials
|
|
217
|
+
- 🔑 Application passwords
|
|
218
|
+
|
|
219
|
+
## Known Limitations
|
|
220
|
+
|
|
221
|
+
- ❌ **Search**: Cannot search by encrypted fields (data is encrypted in DB)
|
|
222
|
+
- ❌ **Sorting**: Cannot sort by encrypted fields
|
|
223
|
+
- ❌ **Filters**: Cannot apply direct filters on encrypted fields
|
|
224
|
+
- ⚠️ **Performance**: Encryption/decryption adds minimal overhead (~1-2ms per operation)
|
|
225
|
+
- ⚠️ **Key synchronization**: All environments sharing the same DB must use the same key
|
|
226
|
+
|
|
227
|
+
## License
|
|
173
228
|
|
|
174
|
-
## License / Licencia
|
|
175
229
|
MIT © 2025 Growy AI
|
|
176
230
|
|
|
177
|
-
##
|
|
178
|
-
|
|
179
|
-
**
|
|
231
|
+
## Developed by
|
|
232
|
+
|
|
233
|
+
**Growy AI** - AI and business automation solutions
|
|
234
|
+
|
|
235
|
+
**Main author**: Zahir El isaac
|
|
180
236
|
|
|
181
237
|
---
|
|
182
238
|
|
|
183
239
|
<div align="center">
|
|
184
|
-
<p>If this plugin is useful to you, consider giving it a ⭐ on GitHub
|
|
185
|
-
<p>Made with ❤️ by Growy AI
|
|
240
|
+
<p>If this plugin is useful to you, consider giving it a ⭐ on GitHub</p>
|
|
241
|
+
<p>Made with ❤️ by the Growy AI team</p>
|
|
186
242
|
</div>
|