@angular-helpers/security 21.4.3 → 21.5.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.
@@ -108,12 +108,12 @@ function hibpPassword(path, options) {
108
108
  validateAsync(path, {
109
109
  params: ({ value }) => {
110
110
  const raw = value();
111
- return raw && raw.length >= 8 ? raw : undefined;
111
+ return { password: raw && raw.length >= 8 ? raw : '' };
112
112
  },
113
- factory: (passwordSignal) => {
113
+ factory: (paramsSignal) => {
114
114
  const hibp = inject(HibpService);
115
115
  return resource({
116
- params: () => passwordSignal(),
116
+ params: () => paramsSignal()?.password,
117
117
  loader: async ({ params: password, abortSignal }) => {
118
118
  if (!password)
119
119
  return undefined;
@@ -1,55 +1,137 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DestroyRef, Injectable, PLATFORM_ID, InjectionToken, signal, computed, NgZone, Injector, makeEnvironmentProviders } from '@angular/core';
2
+ import { Injectable, inject, PLATFORM_ID, InjectionToken, DestroyRef, signal, computed, NgZone, Injector, makeEnvironmentProviders } from '@angular/core';
3
+ import { injectWorkerPool } from '@angular-helpers/core';
3
4
  import { isPlatformBrowser, DOCUMENT } from '@angular/common';
4
5
  import { Observable, Subject, fromEvent, merge } from 'rxjs';
5
6
  import { throttleTime } from 'rxjs/operators';
6
7
 
7
8
  /**
8
- * Security service for regular expressions that prevents ReDoS
9
- * using Web Workers for safe execution with timeout
9
+ * Builder pattern to construct safe regular expressions
10
10
  */
11
- class RegexSecurityService {
12
- destroyRef = inject(DestroyRef);
13
- workers = new Map();
11
+ class RegexSecurityBuilder {
12
+ patternValue = '';
13
+ optionsValue = {};
14
+ securityConfigValue = {};
14
15
  /**
15
- * Builder pattern to construct safe regular expressions
16
+ * Defines the base pattern
16
17
  */
17
- static builder() {
18
- return new RegexSecurityBuilder();
18
+ pattern(pattern) {
19
+ this.patternValue = pattern;
20
+ return this;
19
21
  }
20
22
  /**
21
- * Executes a regular expression safely with a timeout
23
+ * Appends text to the current pattern
22
24
  */
23
- async testRegex(pattern, text, config = {}) {
24
- const startTime = performance.now();
25
- const finalConfig = this.mergeConfig(config);
26
- try {
27
- // First, analyze pattern security
28
- const securityCheck = await this.analyzePatternSecurity(pattern);
29
- if (!securityCheck.safe && !finalConfig.safeMode) {
30
- return {
31
- match: false,
32
- executionTime: performance.now() - startTime,
33
- timeout: false,
34
- error: `Pattern rejected: ${securityCheck.warnings.join(', ')}`,
35
- };
36
- }
37
- // Execute in Web Worker with timeout
38
- const result = await this.executeInWorker(pattern, text, finalConfig);
39
- return {
40
- ...result,
41
- executionTime: performance.now() - startTime,
42
- };
25
+ append(text) {
26
+ this.patternValue += text;
27
+ return this;
28
+ }
29
+ /**
30
+ * Adds a capturing group
31
+ */
32
+ group(content, name) {
33
+ if (name) {
34
+ this.patternValue += `(?<${name}>${content})`;
43
35
  }
44
- catch (error) {
45
- return {
46
- match: false,
47
- executionTime: performance.now() - startTime,
48
- timeout: false,
49
- error: error instanceof Error ? error.message : 'Unknown error',
50
- };
36
+ else {
37
+ this.patternValue += `(${content})`;
51
38
  }
39
+ return this;
40
+ }
41
+ /**
42
+ * Adds a non-capturing group
43
+ */
44
+ nonCapturingGroup(content) {
45
+ this.patternValue += `(?:${content})`;
46
+ return this;
47
+ }
48
+ /**
49
+ * Adds an alternative
50
+ */
51
+ or(alternative) {
52
+ this.patternValue += `|${alternative}`;
53
+ return this;
54
+ }
55
+ /**
56
+ * Adds a quantifier
57
+ */
58
+ quantifier(quantifier) {
59
+ this.patternValue += quantifier;
60
+ return this;
52
61
  }
62
+ /**
63
+ * Adds a character set
64
+ */
65
+ characterSet(chars, negate = false) {
66
+ this.patternValue += `[${negate ? '^' : ''}${chars}]`;
67
+ return this;
68
+ }
69
+ /**
70
+ * Adds a start of line anchor
71
+ */
72
+ startOfLine() {
73
+ this.patternValue += '^';
74
+ return this;
75
+ }
76
+ /**
77
+ * Adds an end of line anchor
78
+ */
79
+ endOfLine() {
80
+ this.patternValue += '$';
81
+ return this;
82
+ }
83
+ /**
84
+ * Configures regular expression options
85
+ */
86
+ options(options) {
87
+ this.optionsValue = { ...this.optionsValue, ...options };
88
+ return this;
89
+ }
90
+ /**
91
+ * Configures security options
92
+ */
93
+ security(config) {
94
+ this.securityConfigValue = { ...this.securityConfigValue, ...config };
95
+ return this;
96
+ }
97
+ /**
98
+ * Configures timeout
99
+ */
100
+ timeout(ms) {
101
+ this.securityConfigValue.timeout = ms;
102
+ return this;
103
+ }
104
+ /**
105
+ * Activates safe mode
106
+ */
107
+ safeMode() {
108
+ this.securityConfigValue.safeMode = true;
109
+ return this;
110
+ }
111
+ /**
112
+ * Builds the final regular expression
113
+ */
114
+ build() {
115
+ return {
116
+ pattern: this.patternValue,
117
+ options: this.optionsValue,
118
+ security: this.securityConfigValue,
119
+ };
120
+ }
121
+ /**
122
+ * Builds and executes the regular expression
123
+ */
124
+ async execute(text, service) {
125
+ const { pattern, security } = this.build();
126
+ return service.testRegex(pattern, text, security);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Service responsible for statically analyzing regular expressions
132
+ * to detect ReDoS vulnerabilities and complexity issues.
133
+ */
134
+ class RegexAnalyzerService {
53
135
  /**
54
136
  * Analyzes the security of a regular expression pattern
55
137
  */
@@ -114,131 +196,6 @@ class RegexSecurityService {
114
196
  recommendations,
115
197
  };
116
198
  }
117
- /**
118
- * Executes the regular expression in a Web Worker
119
- */
120
- async executeInWorker(pattern, text, config) {
121
- return new Promise((resolve) => {
122
- const workerName = `regex-worker-${Date.now()}`;
123
- try {
124
- // Create temporary worker
125
- const workerCode = this.generateWorkerCode();
126
- const blob = new Blob([workerCode], { type: 'application/javascript' });
127
- const worker = new Worker(URL.createObjectURL(blob));
128
- this.workers.set(workerName, worker);
129
- const taskId = `regex_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
130
- const task = {
131
- id: taskId,
132
- type: 'regex-test',
133
- data: {
134
- pattern,
135
- text,
136
- timeout: config.timeout || 5000,
137
- },
138
- };
139
- // Timeout for execution
140
- const timeoutId = setTimeout(() => {
141
- worker.terminate();
142
- this.workers.delete(workerName);
143
- resolve({
144
- match: false,
145
- executionTime: 0,
146
- timeout: true,
147
- error: 'Execution timeout',
148
- });
149
- }, config.timeout || 5000);
150
- worker.onmessage = (event) => {
151
- clearTimeout(timeoutId);
152
- worker.terminate();
153
- this.workers.delete(workerName);
154
- if (event.data.id === taskId) {
155
- resolve(event.data.data);
156
- }
157
- };
158
- worker.onerror = (error) => {
159
- clearTimeout(timeoutId);
160
- worker.terminate();
161
- this.workers.delete(workerName);
162
- resolve({
163
- match: false,
164
- executionTime: 0,
165
- timeout: false,
166
- error: `Worker error: ${error.message || 'Unknown error'}`,
167
- });
168
- };
169
- worker.postMessage(task);
170
- }
171
- catch (error) {
172
- resolve({
173
- match: false,
174
- executionTime: 0,
175
- timeout: false,
176
- error: `Failed to create worker: ${error instanceof Error ? error.message : 'Unknown error'}`,
177
- });
178
- }
179
- });
180
- }
181
- /**
182
- * Generates the Web Worker code
183
- */
184
- generateWorkerCode() {
185
- return `
186
- self.addEventListener('message', function(event) {
187
- const task = event.data;
188
-
189
- if (task.type === 'regex-test') {
190
- const { pattern, text, timeout } = task.data;
191
- const startTime = performance.now();
192
-
193
- try {
194
- const regex = new RegExp(pattern, 'g');
195
- const matches = [];
196
- let match;
197
-
198
- while ((match = regex.exec(text)) !== null) {
199
- matches.push([...match]);
200
-
201
- // Prevention of infinite loops
202
- if (matches.length > 1000) {
203
- throw new Error('Too many matches - possible infinite loop');
204
- }
205
- }
206
-
207
- const groups = {};
208
- if (matches.length > 0) {
209
- const firstMatch = matches[0];
210
- for (let i = 1; i < firstMatch.length; i++) {
211
- groups[\`group\${i}\`] = firstMatch[i];
212
- }
213
- }
214
-
215
- self.postMessage({
216
- id: task.id,
217
- type: 'regex-result',
218
- data: {
219
- match: matches.length > 0,
220
- matches,
221
- groups,
222
- executionTime: performance.now() - startTime,
223
- timeout: false
224
- }
225
- });
226
- } catch (error) {
227
- self.postMessage({
228
- id: task.id,
229
- type: 'regex-result',
230
- data: {
231
- match: false,
232
- executionTime: performance.now() - startTime,
233
- timeout: false,
234
- error: error.message || 'Execution error'
235
- }
236
- });
237
- }
238
- }
239
- });
240
- `;
241
- }
242
199
  /**
243
200
  * Calculates the complexity of a pattern
244
201
  */
@@ -266,153 +223,146 @@ class RegexSecurityService {
266
223
  const levels = { low: 1, medium: 2, high: 3, critical: 4 };
267
224
  return levels[risk] || 0;
268
225
  }
269
- /**
270
- * Merges configuration with default values
271
- */
272
- mergeConfig(config) {
273
- return {
274
- timeout: config.timeout || 5000,
275
- maxComplexity: config.maxComplexity || 10,
276
- allowBacktracking: config.allowBacktracking || false,
277
- safeMode: config.safeMode || false,
278
- };
279
- }
280
- /**
281
- * Cleans up resources when the service is destroyed
282
- */
283
- ngOnDestroy() {
284
- this.workers.forEach((worker) => {
285
- worker.terminate();
286
- });
287
- this.workers.clear();
288
- }
289
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
290
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService });
226
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexAnalyzerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
227
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexAnalyzerService });
291
228
  }
292
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService, decorators: [{
229
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexAnalyzerService, decorators: [{
293
230
  type: Injectable
294
231
  }] });
232
+
295
233
  /**
296
- * Builder pattern to construct safe regular expressions
234
+ * Service responsible for managing Web Workers for safe regex execution.
235
+ * Avoids creating a new worker for every single execution.
297
236
  */
298
- class RegexSecurityBuilder {
299
- patternValue = '';
300
- optionsValue = {};
301
- securityConfigValue = {};
302
- /**
303
- * Defines the base pattern
304
- */
305
- pattern(pattern) {
306
- this.patternValue = pattern;
307
- return this;
308
- }
309
- /**
310
- * Appends text to the current pattern
311
- */
312
- append(text) {
313
- this.patternValue += text;
314
- return this;
237
+ class RegexWorkerPoolService {
238
+ pool;
239
+ constructor() {
240
+ this.pool = injectWorkerPool(new URL('../workers/regex.worker', import.meta.url), {
241
+ defaultTimeout: 5000,
242
+ fallbackExecutor: async (type, data) => {
243
+ if (type !== 'regex-test')
244
+ throw new Error(`Unknown task type: ${type}`);
245
+ const { pattern, text } = data;
246
+ try {
247
+ const start = Date.now();
248
+ const regex = new RegExp(pattern);
249
+ const match = regex.test(text);
250
+ return {
251
+ match,
252
+ executionTime: Date.now() - start,
253
+ timeout: false,
254
+ };
255
+ }
256
+ catch (e) {
257
+ return {
258
+ match: false,
259
+ executionTime: 0,
260
+ timeout: false,
261
+ error: e.message,
262
+ };
263
+ }
264
+ },
265
+ });
315
266
  }
316
267
  /**
317
- * Adds a capturing group
268
+ * Executes the regular expression in a Web Worker
318
269
  */
319
- group(content, name) {
320
- if (name) {
321
- this.patternValue += `(?<${name}>${content})`;
270
+ async executeInWorker(pattern, text, config) {
271
+ try {
272
+ return await this.pool.execute('regex-test', {
273
+ pattern,
274
+ text,
275
+ timeout: config.timeout || 5000,
276
+ }, config.timeout || 5000);
322
277
  }
323
- else {
324
- this.patternValue += `(${content})`;
278
+ catch (err) {
279
+ return {
280
+ match: false,
281
+ executionTime: 0,
282
+ timeout: err.message === 'Execution timeout',
283
+ error: err.message,
284
+ };
325
285
  }
326
- return this;
327
- }
328
- /**
329
- * Adds a non-capturing group
330
- */
331
- nonCapturingGroup(content) {
332
- this.patternValue += `(?:${content})`;
333
- return this;
334
- }
335
- /**
336
- * Adds an alternative
337
- */
338
- or(alternative) {
339
- this.patternValue += `|${alternative}`;
340
- return this;
341
- }
342
- /**
343
- * Adds a quantifier
344
- */
345
- quantifier(quantifier) {
346
- this.patternValue += quantifier;
347
- return this;
348
- }
349
- /**
350
- * Adds a character set
351
- */
352
- characterSet(chars, negate = false) {
353
- this.patternValue += `[${negate ? '^' : ''}${chars}]`;
354
- return this;
355
- }
356
- /**
357
- * Adds a start of line anchor
358
- */
359
- startOfLine() {
360
- this.patternValue += '^';
361
- return this;
362
- }
363
- /**
364
- * Adds an end of line anchor
365
- */
366
- endOfLine() {
367
- this.patternValue += '$';
368
- return this;
369
286
  }
370
- /**
371
- * Configures regular expression options
372
- */
373
- options(options) {
374
- this.optionsValue = { ...this.optionsValue, ...options };
375
- return this;
287
+ ngOnDestroy() {
288
+ this.pool.terminate();
376
289
  }
290
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexWorkerPoolService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
291
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexWorkerPoolService });
292
+ }
293
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexWorkerPoolService, decorators: [{
294
+ type: Injectable
295
+ }], ctorParameters: () => [] });
296
+
297
+ /**
298
+ * Security service for regular expressions that prevents ReDoS
299
+ * Facade pattern that delegates to Analyzer and Worker Pool.
300
+ */
301
+ class RegexSecurityService {
302
+ analyzer = inject(RegexAnalyzerService);
303
+ workerPool = inject(RegexWorkerPoolService);
377
304
  /**
378
- * Configures security options
305
+ * Builder pattern to construct safe regular expressions
379
306
  */
380
- security(config) {
381
- this.securityConfigValue = { ...this.securityConfigValue, ...config };
382
- return this;
307
+ static builder() {
308
+ return new RegexSecurityBuilder();
383
309
  }
384
310
  /**
385
- * Configures timeout
311
+ * Executes a regular expression safely with a timeout
386
312
  */
387
- timeout(ms) {
388
- this.securityConfigValue.timeout = ms;
389
- return this;
313
+ async testRegex(pattern, text, config = {}) {
314
+ const startTime = performance.now();
315
+ const finalConfig = this.mergeConfig(config);
316
+ try {
317
+ // First, analyze pattern security
318
+ const securityCheck = await this.analyzePatternSecurity(pattern);
319
+ if (!securityCheck.safe && !finalConfig.safeMode) {
320
+ return {
321
+ match: false,
322
+ executionTime: performance.now() - startTime,
323
+ timeout: false,
324
+ error: `Pattern rejected: ${securityCheck.warnings.join(', ')}`,
325
+ };
326
+ }
327
+ // Execute in Web Worker with timeout
328
+ const result = await this.workerPool.executeInWorker(pattern, text, finalConfig);
329
+ return {
330
+ ...result,
331
+ executionTime: performance.now() - startTime,
332
+ };
333
+ }
334
+ catch (error) {
335
+ return {
336
+ match: false,
337
+ executionTime: performance.now() - startTime,
338
+ timeout: false,
339
+ error: error instanceof Error ? error.message : 'Unknown error',
340
+ };
341
+ }
390
342
  }
391
343
  /**
392
- * Activates safe mode
344
+ * Analyzes the security of a regular expression pattern
393
345
  */
394
- safeMode() {
395
- this.securityConfigValue.safeMode = true;
396
- return this;
346
+ async analyzePatternSecurity(pattern) {
347
+ return this.analyzer.analyzePatternSecurity(pattern);
397
348
  }
398
349
  /**
399
- * Builds the final regular expression
350
+ * Merges configuration with default values
400
351
  */
401
- build() {
352
+ mergeConfig(config) {
402
353
  return {
403
- pattern: this.patternValue,
404
- options: this.optionsValue,
405
- security: this.securityConfigValue,
354
+ timeout: config.timeout || 5000,
355
+ maxComplexity: config.maxComplexity || 10,
356
+ allowBacktracking: config.allowBacktracking || false,
357
+ safeMode: config.safeMode || false,
406
358
  };
407
359
  }
408
- /**
409
- * Builds and executes the regular expression
410
- */
411
- async execute(text, service) {
412
- const { pattern, security } = this.build();
413
- return service.testRegex(pattern, text, security);
414
- }
360
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
361
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService });
415
362
  }
363
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RegexSecurityService, decorators: [{
364
+ type: Injectable
365
+ }] });
416
366
 
417
367
  class WebCryptoService {
418
368
  platformId = inject(PLATFORM_ID);
@@ -2021,7 +1971,7 @@ function provideSecurity(config = {}) {
2021
1971
  const mergedConfig = { ...defaultSecurityConfig, ...config };
2022
1972
  const providers = [];
2023
1973
  if (mergedConfig.enableRegexSecurity)
2024
- providers.push(RegexSecurityService);
1974
+ providers.push(RegexAnalyzerService, RegexWorkerPoolService, RegexSecurityService);
2025
1975
  if (mergedConfig.enableWebCrypto)
2026
1976
  providers.push(WebCryptoService);
2027
1977
  if (mergedConfig.enableSecureStorage)
@@ -2049,7 +1999,11 @@ function provideSecurity(config = {}) {
2049
1999
  return makeEnvironmentProviders(providers);
2050
2000
  }
2051
2001
  function provideRegexSecurity() {
2052
- return makeEnvironmentProviders([RegexSecurityService]);
2002
+ return makeEnvironmentProviders([
2003
+ RegexAnalyzerService,
2004
+ RegexWorkerPoolService,
2005
+ RegexSecurityService,
2006
+ ]);
2053
2007
  }
2054
2008
  function provideWebCrypto() {
2055
2009
  return makeEnvironmentProviders([WebCryptoService]);
@@ -2106,4 +2060,4 @@ function provideSecureMessage() {
2106
2060
  * Generated bundle index. Do not edit.
2107
2061
  */
2108
2062
 
2109
- export { CSRF_CONFIG, ClipboardUnsupportedError, CsrfService, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_TAGS, HIBP_CONFIG, HibpService, InputSanitizerService, InvalidJwtError, JwtService, PasswordStrengthService, RATE_LIMITER_CONFIG, RateLimitExceededError, RateLimiterService, RegexSecurityBuilder, RegexSecurityService, SANITIZER_CONFIG, SECURE_STORAGE_CONFIG, SecureMessageService, SecureStorageService, SensitiveClipboardService, SessionIdleService, WebCryptoService, assessPasswordStrength, containsScriptInjection, containsSqlInjectionHints, defaultSecurityConfig, isHtmlSafe, isUrlSafe, provideCsrf, provideHibp, provideInputSanitizer, provideJwt, providePasswordStrength, provideRateLimiter, provideRegexSecurity, provideSecureMessage, provideSecureStorage, provideSecurity, provideSensitiveClipboard, provideSessionIdle, provideWebCrypto, sanitizeHtmlString, sanitizeUrlString, withCsrfHeader };
2063
+ export { CSRF_CONFIG, ClipboardUnsupportedError, CsrfService, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_TAGS, HIBP_CONFIG, HibpService, InputSanitizerService, InvalidJwtError, JwtService, PasswordStrengthService, RATE_LIMITER_CONFIG, RateLimitExceededError, RateLimiterService, RegexAnalyzerService, RegexSecurityBuilder, RegexSecurityService, RegexWorkerPoolService, SANITIZER_CONFIG, SECURE_STORAGE_CONFIG, SecureMessageService, SecureStorageService, SensitiveClipboardService, SessionIdleService, WebCryptoService, assessPasswordStrength, containsScriptInjection, containsSqlInjectionHints, defaultSecurityConfig, isHtmlSafe, isUrlSafe, provideCsrf, provideHibp, provideInputSanitizer, provideJwt, providePasswordStrength, provideRateLimiter, provideRegexSecurity, provideSecureMessage, provideSecureStorage, provideSecurity, provideSensitiveClipboard, provideSessionIdle, provideWebCrypto, sanitizeHtmlString, sanitizeUrlString, withCsrfHeader };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-helpers/security",
3
- "version": "21.4.3",
3
+ "version": "21.5.0",
4
4
  "description": "Angular security helpers for preventing ReDoS and other security vulnerabilities",
5
5
  "keywords": [
6
6
  "angular",
@@ -40,6 +40,7 @@
40
40
  "@angular/common": "^21.0.0",
41
41
  "@angular/core": "^21.0.0",
42
42
  "@angular/forms": "^21.0.0",
43
+ "@angular-helpers/core": "workspace:*",
43
44
  "rxjs": "^7.0.0 || ^8.0.0"
44
45
  },
45
46
  "peerDependenciesMeta": {
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Signal, EnvironmentProviders } from '@angular/core';
2
+ import { InjectionToken, Signal, EnvironmentProviders, OnDestroy } from '@angular/core';
3
3
  import { Observable } from 'rxjs';
4
4
  import { HttpInterceptorFn } from '@angular/common/http';
5
5
 
@@ -34,52 +34,7 @@ interface RegexBuilderOptions {
34
34
  unicode?: boolean;
35
35
  sticky?: boolean;
36
36
  }
37
- /**
38
- * Security service for regular expressions that prevents ReDoS
39
- * using Web Workers for safe execution with timeout
40
- */
41
- declare class RegexSecurityService {
42
- private destroyRef;
43
- private workers;
44
- /**
45
- * Builder pattern to construct safe regular expressions
46
- */
47
- static builder(): RegexSecurityBuilder;
48
- /**
49
- * Executes a regular expression safely with a timeout
50
- */
51
- testRegex(pattern: string, text: string, config?: RegexSecurityConfig): Promise<RegexTestResult>;
52
- /**
53
- * Analyzes the security of a regular expression pattern
54
- */
55
- analyzePatternSecurity(pattern: string): Promise<RegexSecurityResult>;
56
- /**
57
- * Executes the regular expression in a Web Worker
58
- */
59
- private executeInWorker;
60
- /**
61
- * Generates the Web Worker code
62
- */
63
- private generateWorkerCode;
64
- /**
65
- * Calculates the complexity of a pattern
66
- */
67
- private calculateComplexity;
68
- /**
69
- * Gets numeric risk level
70
- */
71
- private getRiskLevel;
72
- /**
73
- * Merges configuration with default values
74
- */
75
- private mergeConfig;
76
- /**
77
- * Cleans up resources when the service is destroyed
78
- */
79
- ngOnDestroy(): void;
80
- static ɵfac: i0.ɵɵFactoryDeclaration<RegexSecurityService, never>;
81
- static ɵprov: i0.ɵɵInjectableDeclaration<RegexSecurityService>;
82
- }
37
+
83
38
  /**
84
39
  * Builder pattern to construct safe regular expressions
85
40
  */
@@ -153,6 +108,33 @@ declare class RegexSecurityBuilder {
153
108
  execute(text: string, service: RegexSecurityService): Promise<RegexTestResult>;
154
109
  }
155
110
 
111
+ /**
112
+ * Security service for regular expressions that prevents ReDoS
113
+ * Facade pattern that delegates to Analyzer and Worker Pool.
114
+ */
115
+ declare class RegexSecurityService {
116
+ private analyzer;
117
+ private workerPool;
118
+ /**
119
+ * Builder pattern to construct safe regular expressions
120
+ */
121
+ static builder(): RegexSecurityBuilder;
122
+ /**
123
+ * Executes a regular expression safely with a timeout
124
+ */
125
+ testRegex(pattern: string, text: string, config?: RegexSecurityConfig): Promise<RegexTestResult>;
126
+ /**
127
+ * Analyzes the security of a regular expression pattern
128
+ */
129
+ analyzePatternSecurity(pattern: string): Promise<RegexSecurityResult>;
130
+ /**
131
+ * Merges configuration with default values
132
+ */
133
+ private mergeConfig;
134
+ static ɵfac: i0.ɵɵFactoryDeclaration<RegexSecurityService, never>;
135
+ static ɵprov: i0.ɵɵInjectableDeclaration<RegexSecurityService>;
136
+ }
137
+
156
138
  type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
157
139
  type HmacAlgorithm = 'HMAC-SHA-256' | 'HMAC-SHA-384' | 'HMAC-SHA-512';
158
140
  type AesKeyLength = 128 | 192 | 256;
@@ -857,5 +839,42 @@ declare function provideCsrf(config?: CsrfConfig): EnvironmentProviders;
857
839
  declare function provideSessionIdle(): EnvironmentProviders;
858
840
  declare function provideSecureMessage(): EnvironmentProviders;
859
841
 
860
- export { CSRF_CONFIG, ClipboardUnsupportedError, CsrfService, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_TAGS, HIBP_CONFIG, HibpService, InputSanitizerService, InvalidJwtError, JwtService, PasswordStrengthService, RATE_LIMITER_CONFIG, RateLimitExceededError, RateLimiterService, RegexSecurityBuilder, RegexSecurityService, SANITIZER_CONFIG, SECURE_STORAGE_CONFIG, SecureMessageService, SecureStorageService, SensitiveClipboardService, SessionIdleService, WebCryptoService, assessPasswordStrength, containsScriptInjection, containsSqlInjectionHints, defaultSecurityConfig, isHtmlSafe, isUrlSafe, provideCsrf, provideHibp, provideInputSanitizer, provideJwt, providePasswordStrength, provideRateLimiter, provideRegexSecurity, provideSecureMessage, provideSecureStorage, provideSecurity, provideSensitiveClipboard, provideSessionIdle, provideWebCrypto, sanitizeHtmlString, sanitizeUrlString, withCsrfHeader };
842
+ /**
843
+ * Service responsible for statically analyzing regular expressions
844
+ * to detect ReDoS vulnerabilities and complexity issues.
845
+ */
846
+ declare class RegexAnalyzerService {
847
+ /**
848
+ * Analyzes the security of a regular expression pattern
849
+ */
850
+ analyzePatternSecurity(pattern: string): Promise<RegexSecurityResult>;
851
+ /**
852
+ * Calculates the complexity of a pattern
853
+ */
854
+ private calculateComplexity;
855
+ /**
856
+ * Gets numeric risk level
857
+ */
858
+ private getRiskLevel;
859
+ static ɵfac: i0.ɵɵFactoryDeclaration<RegexAnalyzerService, never>;
860
+ static ɵprov: i0.ɵɵInjectableDeclaration<RegexAnalyzerService>;
861
+ }
862
+
863
+ /**
864
+ * Service responsible for managing Web Workers for safe regex execution.
865
+ * Avoids creating a new worker for every single execution.
866
+ */
867
+ declare class RegexWorkerPoolService implements OnDestroy {
868
+ private pool;
869
+ constructor();
870
+ /**
871
+ * Executes the regular expression in a Web Worker
872
+ */
873
+ executeInWorker(pattern: string, text: string, config: RegexSecurityConfig): Promise<RegexTestResult>;
874
+ ngOnDestroy(): void;
875
+ static ɵfac: i0.ɵɵFactoryDeclaration<RegexWorkerPoolService, never>;
876
+ static ɵprov: i0.ɵɵInjectableDeclaration<RegexWorkerPoolService>;
877
+ }
878
+
879
+ export { CSRF_CONFIG, ClipboardUnsupportedError, CsrfService, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_TAGS, HIBP_CONFIG, HibpService, InputSanitizerService, InvalidJwtError, JwtService, PasswordStrengthService, RATE_LIMITER_CONFIG, RateLimitExceededError, RateLimiterService, RegexAnalyzerService, RegexSecurityBuilder, RegexSecurityService, RegexWorkerPoolService, SANITIZER_CONFIG, SECURE_STORAGE_CONFIG, SecureMessageService, SecureStorageService, SensitiveClipboardService, SessionIdleService, WebCryptoService, assessPasswordStrength, containsScriptInjection, containsSqlInjectionHints, defaultSecurityConfig, isHtmlSafe, isUrlSafe, provideCsrf, provideHibp, provideInputSanitizer, provideJwt, providePasswordStrength, provideRateLimiter, provideRegexSecurity, provideSecureMessage, provideSecureStorage, provideSecurity, provideSensitiveClipboard, provideSessionIdle, provideWebCrypto, sanitizeHtmlString, sanitizeUrlString, withCsrfHeader };
861
880
  export type { AesEncryptResult, AesKeyLength, CopyStatus, CsrfConfig, CsrfHeaderOptions, CsrfStorageTarget, HashAlgorithm, HibpConfig, HibpResult, HmacAlgorithm, HtmlSanitizerOptions, HttpMethod, JwtStandardClaims, PasswordAssessment, PasswordLabel, PasswordScore, PasswordStrengthResult, RateLimitPolicy, RateLimiterConfig, RegexBuilderOptions, RegexSecurityConfig, RegexSecurityResult, RegexTestResult, SanitizerConfig, SecureMessage, SecureMessageConfig, SecureStorageConfig, SecurityConfig, SensitiveCopyOptions, SessionIdleConfig, StorageTarget };