@angular-helpers/security 21.0.3 → 21.0.4
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.es.md +52 -0
- package/README.md +52 -0
- package/fesm2022/angular-helpers-security.mjs +80 -2
- package/package.json +1 -1
- package/types/angular-helpers-security.d.ts +28 -2
package/README.es.md
CHANGED
|
@@ -15,6 +15,13 @@ Paquete de seguridad para aplicaciones Angular que previene ataques comunes como
|
|
|
15
15
|
- **Análisis de Complejidad**: Detecta patrones peligrosos antes de la ejecución.
|
|
16
16
|
- **Modo Seguro**: Solo permite patrones verificados como seguros.
|
|
17
17
|
|
|
18
|
+
### **Web Crypto API**
|
|
19
|
+
|
|
20
|
+
- **Cifrado/Descifrado**: Soporte AES-GCM para manejo seguro de datos
|
|
21
|
+
- **Hashing**: SHA-256 y otros algoritmos
|
|
22
|
+
- **Gestión de Claves**: Generar, importar y exportar claves criptográficas
|
|
23
|
+
- **Aleatorio Seguro**: Valores aleatorios criptográficamente seguros
|
|
24
|
+
|
|
18
25
|
### **Patrón Builder**
|
|
19
26
|
|
|
20
27
|
- **API Fluida**: Construye expresiones regulares de forma intuitiva.
|
|
@@ -93,6 +100,51 @@ const result = await RegexSecurityService.builder()
|
|
|
93
100
|
.execute('12345', this.securityService);
|
|
94
101
|
```
|
|
95
102
|
|
|
103
|
+
### **WebCryptoService**
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { WebCryptoService } from '@angular-helpers/security';
|
|
107
|
+
|
|
108
|
+
export class SecureStorageComponent {
|
|
109
|
+
private cryptoService = inject(WebCryptoService);
|
|
110
|
+
|
|
111
|
+
async hashPassword(password: string): Promise<string> {
|
|
112
|
+
return await this.cryptoService.hash(password, 'SHA-256');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async encryptData(
|
|
116
|
+
data: string,
|
|
117
|
+
): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array; key: CryptoKey }> {
|
|
118
|
+
const key = await this.cryptoService.generateAesKey(256);
|
|
119
|
+
const { ciphertext, iv } = await this.cryptoService.encryptAes(key, data);
|
|
120
|
+
return { ciphertext, iv, key };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async decryptData(ciphertext: ArrayBuffer, iv: Uint8Array, key: CryptoKey): Promise<string> {
|
|
124
|
+
return await this.cryptoService.decryptAes(key, ciphertext, iv);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async exportKeyForStorage(key: CryptoKey): Promise<JsonWebKey> {
|
|
128
|
+
return await this.cryptoService.exportKey(key);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async importKeyFromStorage(jwk: JsonWebKey): Promise<CryptoKey> {
|
|
132
|
+
return await this.cryptoService.importAesKey(jwk);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
generateSecureToken(length: number = 32): string {
|
|
136
|
+
const bytes = this.cryptoService.generateRandomBytes(length);
|
|
137
|
+
return Array.from(bytes)
|
|
138
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
139
|
+
.join('');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
generateUUID(): string {
|
|
143
|
+
return this.cryptoService.randomUUID();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
96
148
|
## 📊 Niveles de Riesgo
|
|
97
149
|
|
|
98
150
|
| Nivel | Descripción | Acción |
|
package/README.md
CHANGED
|
@@ -15,6 +15,13 @@ Security package for Angular applications that prevents common attacks like ReDo
|
|
|
15
15
|
- **Complexity Analysis**: Detects dangerous patterns before execution.
|
|
16
16
|
- **Safe Mode**: Only allows patterns verified as safe.
|
|
17
17
|
|
|
18
|
+
### **Web Crypto API**
|
|
19
|
+
|
|
20
|
+
- **Encryption/Decryption**: AES-GCM support for secure data handling
|
|
21
|
+
- **Hashing**: SHA-256 and other algorithms
|
|
22
|
+
- **Key Management**: Generate, import, and export cryptographic keys
|
|
23
|
+
- **Secure Random**: Cryptographically secure random values
|
|
24
|
+
|
|
18
25
|
### **Builder Pattern**
|
|
19
26
|
|
|
20
27
|
- **Fluent API**: Intuitively build regular expressions.
|
|
@@ -163,6 +170,51 @@ export class FormValidationComponent {
|
|
|
163
170
|
}
|
|
164
171
|
```
|
|
165
172
|
|
|
173
|
+
### **WebCryptoService**
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { WebCryptoService } from '@angular-helpers/security';
|
|
177
|
+
|
|
178
|
+
export class SecureStorageComponent {
|
|
179
|
+
private cryptoService = inject(WebCryptoService);
|
|
180
|
+
|
|
181
|
+
async hashPassword(password: string): Promise<string> {
|
|
182
|
+
return await this.cryptoService.hash(password, 'SHA-256');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async encryptData(
|
|
186
|
+
data: string,
|
|
187
|
+
): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array; key: CryptoKey }> {
|
|
188
|
+
const key = await this.cryptoService.generateAesKey(256);
|
|
189
|
+
const { ciphertext, iv } = await this.cryptoService.encryptAes(key, data);
|
|
190
|
+
return { ciphertext, iv, key };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async decryptData(ciphertext: ArrayBuffer, iv: Uint8Array, key: CryptoKey): Promise<string> {
|
|
194
|
+
return await this.cryptoService.decryptAes(key, ciphertext, iv);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async exportKeyForStorage(key: CryptoKey): Promise<JsonWebKey> {
|
|
198
|
+
return await this.cryptoService.exportKey(key);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async importKeyFromStorage(jwk: JsonWebKey): Promise<CryptoKey> {
|
|
202
|
+
return await this.cryptoService.importAesKey(jwk);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
generateSecureToken(length: number = 32): string {
|
|
206
|
+
const bytes = this.cryptoService.generateRandomBytes(length);
|
|
207
|
+
return Array.from(bytes)
|
|
208
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
209
|
+
.join('');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
generateUUID(): string {
|
|
213
|
+
return this.cryptoService.randomUUID();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
166
218
|
## 🔧 Advanced Configuration
|
|
167
219
|
|
|
168
220
|
### **Security Options**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DestroyRef, Injectable, makeEnvironmentProviders } from '@angular/core';
|
|
2
|
+
import { inject, DestroyRef, Injectable, PLATFORM_ID, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Security service for regular expressions that prevents ReDoS
|
|
@@ -411,8 +412,79 @@ class RegexSecurityBuilder {
|
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
|
|
415
|
+
class WebCryptoService {
|
|
416
|
+
platformId = inject(PLATFORM_ID);
|
|
417
|
+
isSupported() {
|
|
418
|
+
return isPlatformBrowser(this.platformId) && 'crypto' in window && 'subtle' in crypto;
|
|
419
|
+
}
|
|
420
|
+
get subtle() {
|
|
421
|
+
if (!this.isSupported()) {
|
|
422
|
+
throw new Error('Web Crypto API not supported in this environment');
|
|
423
|
+
}
|
|
424
|
+
return crypto.subtle;
|
|
425
|
+
}
|
|
426
|
+
ensureSecureContext() {
|
|
427
|
+
if (!window.isSecureContext) {
|
|
428
|
+
throw new Error('Web Crypto API requires a secure context (HTTPS)');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async hash(data, algorithm = 'SHA-256') {
|
|
432
|
+
this.ensureSecureContext();
|
|
433
|
+
const buffer = typeof data === 'string' ? new TextEncoder().encode(data) : data;
|
|
434
|
+
const hashBuffer = await this.subtle.digest(algorithm, buffer);
|
|
435
|
+
return this.bufferToHex(hashBuffer);
|
|
436
|
+
}
|
|
437
|
+
async generateAesKey(length = 256) {
|
|
438
|
+
this.ensureSecureContext();
|
|
439
|
+
return this.subtle.generateKey({ name: 'AES-GCM', length }, true, ['encrypt', 'decrypt']);
|
|
440
|
+
}
|
|
441
|
+
async encryptAes(key, data) {
|
|
442
|
+
this.ensureSecureContext();
|
|
443
|
+
const buffer = typeof data === 'string' ? new TextEncoder().encode(data) : data;
|
|
444
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
445
|
+
const ciphertext = await this.subtle.encrypt({ name: 'AES-GCM', iv }, key, buffer);
|
|
446
|
+
return { ciphertext, iv };
|
|
447
|
+
}
|
|
448
|
+
async decryptAes(key, ciphertext, iv) {
|
|
449
|
+
this.ensureSecureContext();
|
|
450
|
+
const decrypted = await this.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
|
|
451
|
+
return new TextDecoder().decode(decrypted);
|
|
452
|
+
}
|
|
453
|
+
async exportKey(key) {
|
|
454
|
+
this.ensureSecureContext();
|
|
455
|
+
return this.subtle.exportKey('jwk', key);
|
|
456
|
+
}
|
|
457
|
+
async importAesKey(jwk) {
|
|
458
|
+
this.ensureSecureContext();
|
|
459
|
+
return this.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, true, ['encrypt', 'decrypt']);
|
|
460
|
+
}
|
|
461
|
+
generateRandomBytes(length) {
|
|
462
|
+
if (!this.isSupported()) {
|
|
463
|
+
throw new Error('Web Crypto API not supported');
|
|
464
|
+
}
|
|
465
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
466
|
+
}
|
|
467
|
+
randomUUID() {
|
|
468
|
+
if (!this.isSupported()) {
|
|
469
|
+
throw new Error('Web Crypto API not supported');
|
|
470
|
+
}
|
|
471
|
+
return crypto.randomUUID();
|
|
472
|
+
}
|
|
473
|
+
bufferToHex(buffer) {
|
|
474
|
+
return Array.from(new Uint8Array(buffer))
|
|
475
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
476
|
+
.join('');
|
|
477
|
+
}
|
|
478
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebCryptoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
479
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebCryptoService });
|
|
480
|
+
}
|
|
481
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebCryptoService, decorators: [{
|
|
482
|
+
type: Injectable
|
|
483
|
+
}] });
|
|
484
|
+
|
|
414
485
|
const defaultSecurityConfig = {
|
|
415
486
|
enableRegexSecurity: true,
|
|
487
|
+
enableWebCrypto: true,
|
|
416
488
|
defaultTimeout: 5000,
|
|
417
489
|
safeMode: false,
|
|
418
490
|
};
|
|
@@ -422,14 +494,20 @@ function provideSecurity(config = {}) {
|
|
|
422
494
|
if (mergedConfig.enableRegexSecurity) {
|
|
423
495
|
providers.push(RegexSecurityService);
|
|
424
496
|
}
|
|
497
|
+
if (mergedConfig.enableWebCrypto) {
|
|
498
|
+
providers.push(WebCryptoService);
|
|
499
|
+
}
|
|
425
500
|
return makeEnvironmentProviders(providers);
|
|
426
501
|
}
|
|
427
502
|
function provideRegexSecurity() {
|
|
428
503
|
return makeEnvironmentProviders([RegexSecurityService]);
|
|
429
504
|
}
|
|
505
|
+
function provideWebCrypto() {
|
|
506
|
+
return makeEnvironmentProviders([WebCryptoService]);
|
|
507
|
+
}
|
|
430
508
|
|
|
431
509
|
/**
|
|
432
510
|
* Generated bundle index. Do not edit.
|
|
433
511
|
*/
|
|
434
512
|
|
|
435
|
-
export { RegexSecurityBuilder, RegexSecurityService, defaultSecurityConfig, provideRegexSecurity, provideSecurity };
|
|
513
|
+
export { RegexSecurityBuilder, RegexSecurityService, WebCryptoService, defaultSecurityConfig, provideRegexSecurity, provideSecurity, provideWebCrypto };
|
package/package.json
CHANGED
|
@@ -151,14 +151,40 @@ declare class RegexSecurityBuilder {
|
|
|
151
151
|
execute(text: string, service: RegexSecurityService): Promise<RegexTestResult>;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
155
|
+
type AesKeyLength = 128 | 192 | 256;
|
|
156
|
+
interface AesEncryptResult {
|
|
157
|
+
ciphertext: ArrayBuffer;
|
|
158
|
+
iv: Uint8Array;
|
|
159
|
+
}
|
|
160
|
+
declare class WebCryptoService {
|
|
161
|
+
private readonly platformId;
|
|
162
|
+
isSupported(): boolean;
|
|
163
|
+
private get subtle();
|
|
164
|
+
private ensureSecureContext;
|
|
165
|
+
hash(data: string | ArrayBuffer, algorithm?: HashAlgorithm): Promise<string>;
|
|
166
|
+
generateAesKey(length?: AesKeyLength): Promise<CryptoKey>;
|
|
167
|
+
encryptAes(key: CryptoKey, data: string | ArrayBuffer): Promise<AesEncryptResult>;
|
|
168
|
+
decryptAes(key: CryptoKey, ciphertext: ArrayBuffer, iv: Uint8Array<ArrayBuffer>): Promise<string>;
|
|
169
|
+
exportKey(key: CryptoKey): Promise<JsonWebKey>;
|
|
170
|
+
importAesKey(jwk: JsonWebKey): Promise<CryptoKey>;
|
|
171
|
+
generateRandomBytes(length: number): Uint8Array;
|
|
172
|
+
randomUUID(): string;
|
|
173
|
+
private bufferToHex;
|
|
174
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<WebCryptoService, never>;
|
|
175
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<WebCryptoService>;
|
|
176
|
+
}
|
|
177
|
+
|
|
154
178
|
interface SecurityConfig {
|
|
155
179
|
enableRegexSecurity?: boolean;
|
|
180
|
+
enableWebCrypto?: boolean;
|
|
156
181
|
defaultTimeout?: number;
|
|
157
182
|
safeMode?: boolean;
|
|
158
183
|
}
|
|
159
184
|
declare const defaultSecurityConfig: SecurityConfig;
|
|
160
185
|
declare function provideSecurity(config?: SecurityConfig): EnvironmentProviders;
|
|
161
186
|
declare function provideRegexSecurity(): EnvironmentProviders;
|
|
187
|
+
declare function provideWebCrypto(): EnvironmentProviders;
|
|
162
188
|
|
|
163
|
-
export { RegexSecurityBuilder, RegexSecurityService, defaultSecurityConfig, provideRegexSecurity, provideSecurity };
|
|
164
|
-
export type { RegexBuilderOptions, RegexSecurityConfig, RegexSecurityResult, RegexTestResult, SecurityConfig };
|
|
189
|
+
export { RegexSecurityBuilder, RegexSecurityService, WebCryptoService, defaultSecurityConfig, provideRegexSecurity, provideSecurity, provideWebCrypto };
|
|
190
|
+
export type { AesEncryptResult, AesKeyLength, HashAlgorithm, RegexBuilderOptions, RegexSecurityConfig, RegexSecurityResult, RegexTestResult, SecurityConfig };
|