@wgtechlabs/log-engine 2.0.0 → 2.1.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/LICENSE +21 -21
- package/README.md +869 -608
- package/dist/formatter/data-formatter.d.ts +2 -1
- package/dist/formatter/data-formatter.d.ts.map +1 -1
- package/dist/formatter/data-formatter.js +1 -1
- package/dist/formatter/message-formatter.d.ts +23 -23
- package/dist/formatter/message-formatter.d.ts.map +1 -1
- package/dist/formatter/message-formatter.js +23 -23
- package/dist/formatter/timestamp.d.ts.map +1 -1
- package/dist/index.d.ts +130 -136
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +108 -108
- package/dist/logger/advanced-outputs.d.ts +159 -0
- package/dist/logger/advanced-outputs.d.ts.map +1 -0
- package/dist/logger/advanced-outputs.js +586 -0
- package/dist/logger/config.d.ts +18 -18
- package/dist/logger/config.d.ts.map +1 -1
- package/dist/logger/config.js +32 -29
- package/dist/logger/core.d.ts +128 -84
- package/dist/logger/core.d.ts.map +1 -1
- package/dist/logger/core.js +259 -74
- package/dist/logger/environment.d.ts +15 -15
- package/dist/logger/environment.d.ts.map +1 -1
- package/dist/logger/environment.js +15 -15
- package/dist/logger/filtering.d.ts +16 -16
- package/dist/logger/filtering.d.ts.map +1 -1
- package/dist/logger/filtering.js +37 -22
- package/dist/redaction/config.d.ts +8 -8
- package/dist/redaction/config.d.ts.map +1 -1
- package/dist/redaction/config.js +8 -8
- package/dist/redaction/redactor.d.ts +60 -60
- package/dist/redaction/redactor.d.ts.map +1 -1
- package/dist/redaction/redactor.js +101 -96
- package/dist/types/index.d.ts +98 -16
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +80 -68
package/dist/logger/filtering.js
CHANGED
|
@@ -12,37 +12,52 @@ const types_1 = require("../types");
|
|
|
12
12
|
*/
|
|
13
13
|
class LogFilter {
|
|
14
14
|
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
* Determines if a message should be logged based on current log mode
|
|
16
|
+
* Messages are shown only if their level is appropriate for the configured mode
|
|
17
|
+
* LOG level is special - it always outputs regardless of configured mode (except when OFF is set)
|
|
18
|
+
* OFF mode disables all logging including LOG level messages
|
|
19
|
+
* @param level - The log level of the message to check
|
|
20
|
+
* @param currentMode - The current logging mode
|
|
21
|
+
* @returns true if message should be logged, false otherwise
|
|
22
|
+
*/
|
|
23
23
|
static shouldLog(level, currentMode) {
|
|
24
|
-
// Get the severity rank for the message level
|
|
25
|
-
const messageSeverity =
|
|
26
|
-
// Get the minimum severity threshold for the current mode
|
|
27
|
-
const modeThreshold =
|
|
24
|
+
// Get the severity rank for the message level using safe lookup
|
|
25
|
+
const messageSeverity = LogFilter.getSeverityRank(level);
|
|
26
|
+
// Get the minimum severity threshold for the current mode using safe lookup
|
|
27
|
+
const modeThreshold = LogFilter.getModeThreshold(currentMode);
|
|
28
28
|
// Allow the message if its severity meets or exceeds the mode threshold
|
|
29
29
|
return messageSeverity >= modeThreshold;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
* Get the severity rank for a log level
|
|
33
|
+
* @param level - The log level to get rank for
|
|
34
|
+
* @returns Numeric severity rank
|
|
35
|
+
*/
|
|
36
36
|
static getSeverityRank(level) {
|
|
37
|
-
|
|
37
|
+
switch (level) {
|
|
38
|
+
case types_1.LogLevel.DEBUG: return 0;
|
|
39
|
+
case types_1.LogLevel.INFO: return 1;
|
|
40
|
+
case types_1.LogLevel.WARN: return 2;
|
|
41
|
+
case types_1.LogLevel.ERROR: return 3;
|
|
42
|
+
case types_1.LogLevel.LOG: return 99;
|
|
43
|
+
default: return 0;
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
* Get the threshold for a log mode
|
|
48
|
+
* @param mode - The log mode to get threshold for
|
|
49
|
+
* @returns Numeric threshold value
|
|
50
|
+
*/
|
|
44
51
|
static getModeThreshold(mode) {
|
|
45
|
-
|
|
52
|
+
switch (mode) {
|
|
53
|
+
case types_1.LogMode.DEBUG: return 0;
|
|
54
|
+
case types_1.LogMode.INFO: return 1;
|
|
55
|
+
case types_1.LogMode.WARN: return 2;
|
|
56
|
+
case types_1.LogMode.ERROR: return 3;
|
|
57
|
+
case types_1.LogMode.SILENT: return 99;
|
|
58
|
+
case types_1.LogMode.OFF: return 100;
|
|
59
|
+
default: return 0;
|
|
60
|
+
}
|
|
46
61
|
}
|
|
47
62
|
}
|
|
48
63
|
exports.LogFilter = LogFilter;
|
|
@@ -14,16 +14,16 @@ export declare const defaultRedactionConfig: RedactionConfig;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare class RedactionController {
|
|
16
16
|
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
* Check if redaction should be disabled based on environment variables
|
|
18
|
+
* Development mode and explicit flags can disable redaction for debugging
|
|
19
|
+
* @returns true if redaction should be disabled, false otherwise
|
|
20
|
+
*/
|
|
21
21
|
static isRedactionDisabled(): boolean;
|
|
22
22
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
* Get environment-specific configuration overrides
|
|
24
|
+
* Allows customization through environment variables
|
|
25
|
+
* @returns Partial redaction config with environment-based overrides
|
|
26
|
+
*/
|
|
27
27
|
static getEnvironmentConfig(): Partial<RedactionConfig>;
|
|
28
28
|
}
|
|
29
29
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/redaction/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAyCpC,CAAC;AAEF;;;GAGG;AACH,qBAAa,mBAAmB;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/redaction/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAyCpC,CAAC;AAEF;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B;;;;SAIK;IACL,MAAM,CAAC,mBAAmB,IAAI,OAAO;IAUrC;;;;SAIK;IACL,MAAM,CAAC,oBAAoB,IAAI,OAAO,CAAC,eAAe,CAAC;CA4BxD"}
|
package/dist/redaction/config.js
CHANGED
|
@@ -52,10 +52,10 @@ exports.defaultRedactionConfig = {
|
|
|
52
52
|
*/
|
|
53
53
|
class RedactionController {
|
|
54
54
|
/**
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
* Check if redaction should be disabled based on environment variables
|
|
56
|
+
* Development mode and explicit flags can disable redaction for debugging
|
|
57
|
+
* @returns true if redaction should be disabled, false otherwise
|
|
58
|
+
*/
|
|
59
59
|
static isRedactionDisabled() {
|
|
60
60
|
return (process.env.NODE_ENV === 'development' ||
|
|
61
61
|
process.env.LOG_REDACTION_DISABLED === 'true' ||
|
|
@@ -64,10 +64,10 @@ class RedactionController {
|
|
|
64
64
|
process.env.LOG_REDACTION_ENABLED === 'false');
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
* Get environment-specific configuration overrides
|
|
68
|
+
* Allows customization through environment variables
|
|
69
|
+
* @returns Partial redaction config with environment-based overrides
|
|
70
|
+
*/
|
|
71
71
|
static getEnvironmentConfig() {
|
|
72
72
|
const envConfig = {
|
|
73
73
|
enabled: !this.isRedactionDisabled()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Core data redaction engine
|
|
3
3
|
* Handles automatic detection and redaction of sensitive information in log data
|
|
4
4
|
*/
|
|
5
|
-
import { RedactionConfig } from '../types';
|
|
5
|
+
import { RedactionConfig, LogData } from '../types';
|
|
6
6
|
/**
|
|
7
7
|
* DataRedactor class - Core redaction logic for processing log data
|
|
8
8
|
* Automatically detects and redacts sensitive information while preserving structure
|
|
@@ -12,88 +12,88 @@ export declare class DataRedactor {
|
|
|
12
12
|
private static readonly MAX_RECURSION_DEPTH;
|
|
13
13
|
private static readonly MAX_REDACT_OBJECT_DEPTH;
|
|
14
14
|
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
* Update the redaction configuration with new settings
|
|
16
|
+
* Merges provided config with existing settings and reloads environment variables
|
|
17
|
+
* @param newConfig - Partial configuration to merge with current settings
|
|
18
|
+
*/
|
|
19
19
|
static updateConfig(newConfig: Partial<RedactionConfig>): void;
|
|
20
20
|
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
* Get the current redaction configuration
|
|
22
|
+
* @returns Deep copy of current redaction configuration
|
|
23
|
+
*/
|
|
24
24
|
static getConfig(): RedactionConfig;
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
* Refresh configuration from environment variables
|
|
27
|
+
* Useful for picking up runtime environment changes
|
|
28
|
+
*/
|
|
29
29
|
static refreshConfig(): void;
|
|
30
30
|
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
* Add custom regex patterns for advanced field detection
|
|
32
|
+
* @param patterns - Array of regex patterns to add
|
|
33
|
+
*/
|
|
34
34
|
static addCustomPatterns(patterns: RegExp[]): void;
|
|
35
35
|
/**
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
* Clear all custom regex patterns
|
|
37
|
+
*/
|
|
38
38
|
static clearCustomPatterns(): void;
|
|
39
39
|
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
* Add custom sensitive field names to the existing list
|
|
41
|
+
* @param fields - Array of field names to add
|
|
42
|
+
*/
|
|
43
43
|
static addSensitiveFields(fields: string[]): void;
|
|
44
44
|
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
* Test if a field name would be redacted with current configuration
|
|
46
|
+
* @param fieldName - Field name to test
|
|
47
|
+
* @returns true if field would be redacted, false otherwise
|
|
48
|
+
*/
|
|
49
49
|
static testFieldRedaction(fieldName: string): boolean;
|
|
50
50
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
static redactData(data:
|
|
51
|
+
* Main entry point for data redaction
|
|
52
|
+
* Processes any type of data and returns a redacted version
|
|
53
|
+
* @param data - Data to be processed for redaction
|
|
54
|
+
* @returns Redacted version of the data
|
|
55
|
+
*/
|
|
56
|
+
static redactData(data: LogData): LogData;
|
|
57
57
|
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
* Process a value of any type (primitive, object, array)
|
|
59
|
+
* Recursively handles nested structures when deepRedaction is enabled
|
|
60
|
+
* Includes circular reference protection and recursion depth limiting
|
|
61
|
+
* @param value - Value to process
|
|
62
|
+
* @param visited - Set to track visited objects (prevents circular references)
|
|
63
|
+
* @param depth - Current recursion depth (prevents stack overflow)
|
|
64
|
+
* @returns Processed value with redaction applied
|
|
65
|
+
*/
|
|
66
66
|
private static processValue;
|
|
67
67
|
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
* Process an object and redact sensitive fields
|
|
69
|
+
* Handles field-level redaction and content truncation
|
|
70
|
+
* @param obj - Object to process
|
|
71
|
+
* @param visited - Set to track visited objects (prevents circular references)
|
|
72
|
+
* @param depth - Current recursion depth (prevents stack overflow)
|
|
73
|
+
* @returns Object with sensitive fields redacted
|
|
74
|
+
*/
|
|
75
75
|
private static redactObject;
|
|
76
76
|
/**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
* Check if a field name indicates sensitive information
|
|
78
|
+
* Uses case-insensitive matching with exact and partial matches
|
|
79
|
+
* Includes smart filtering to avoid false positives and custom patterns
|
|
80
|
+
* @param fieldName - Field name to check
|
|
81
|
+
* @returns true if field should be redacted, false otherwise
|
|
82
|
+
*/
|
|
83
83
|
private static isSensitiveField;
|
|
84
84
|
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
* Check if a field name indicates content that should be truncated
|
|
86
|
+
* Uses exact case-insensitive matching for content fields
|
|
87
|
+
* @param fieldName - Field name to check
|
|
88
|
+
* @returns true if field is a content field, false otherwise
|
|
89
|
+
*/
|
|
90
90
|
private static isContentField;
|
|
91
91
|
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
* Truncate content that exceeds the maximum length
|
|
93
|
+
* Preserves readability while preventing log bloat
|
|
94
|
+
* @param content - Content string to potentially truncate
|
|
95
|
+
* @returns Original content or truncated version with indicator
|
|
96
|
+
*/
|
|
97
97
|
private static truncateContent;
|
|
98
98
|
}
|
|
99
99
|
//# sourceMappingURL=redactor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redactor.d.ts","sourceRoot":"","sources":["../../src/redaction/redactor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"redactor.d.ts","sourceRoot":"","sources":["../../src/redaction/redactor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGpD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,MAAM,CAGnB;IAGF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAM;IAErD;;;;SAIK;IACL,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAU9D;;;SAGK;IACL,MAAM,CAAC,SAAS,IAAI,eAAe;IASnC;;;SAGK;IACL,MAAM,CAAC,aAAa,IAAI,IAAI;IAQ5B;;;SAGK;IACL,MAAM,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI;IAQlD;;SAEK;IACL,MAAM,CAAC,mBAAmB,IAAI,IAAI;IAOlC;;;SAGK;IACL,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAOjD;;;;SAIK;IACL,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAWrD;;;;;SAKK;IACL,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IASzC;;;;;;;;SAQK;IACL,OAAO,CAAC,MAAM,CAAC,YAAY;IAyC3B;;;;;;;SAOK;IACL,OAAO,CAAC,MAAM,CAAC,YAAY;IA2B3B;;;;;;SAMK;IACL,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAgD/B;;;;;SAKK;IACL,OAAO,CAAC,MAAM,CAAC,cAAc;IAK7B;;;;;SAKK;IACL,OAAO,CAAC,MAAM,CAAC,eAAe;CAM/B"}
|
|
@@ -12,107 +12,112 @@ const config_1 = require("./config");
|
|
|
12
12
|
*/
|
|
13
13
|
class DataRedactor {
|
|
14
14
|
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
* Update the redaction configuration with new settings
|
|
16
|
+
* Merges provided config with existing settings and reloads environment variables
|
|
17
|
+
* @param newConfig - Partial configuration to merge with current settings
|
|
18
|
+
*/
|
|
19
19
|
static updateConfig(newConfig) {
|
|
20
20
|
// Reload environment configuration to pick up any changes
|
|
21
21
|
const envConfig = config_1.RedactionController.getEnvironmentConfig();
|
|
22
|
-
|
|
22
|
+
DataRedactor.config = {
|
|
23
23
|
...config_1.defaultRedactionConfig,
|
|
24
24
|
...envConfig,
|
|
25
25
|
...newConfig
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
* Get the current redaction configuration
|
|
30
|
+
* @returns Deep copy of current redaction configuration
|
|
31
|
+
*/
|
|
32
32
|
static getConfig() {
|
|
33
33
|
return {
|
|
34
|
-
...
|
|
35
|
-
sensitiveFields: [...
|
|
36
|
-
contentFields: [...
|
|
37
|
-
customPatterns:
|
|
34
|
+
...DataRedactor.config,
|
|
35
|
+
sensitiveFields: [...DataRedactor.config.sensitiveFields],
|
|
36
|
+
contentFields: [...DataRedactor.config.contentFields],
|
|
37
|
+
customPatterns: DataRedactor.config.customPatterns ? [...DataRedactor.config.customPatterns] : undefined
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
* Refresh configuration from environment variables
|
|
42
|
+
* Useful for picking up runtime environment changes
|
|
43
|
+
*/
|
|
44
44
|
static refreshConfig() {
|
|
45
45
|
const envConfig = config_1.RedactionController.getEnvironmentConfig();
|
|
46
|
-
|
|
46
|
+
DataRedactor.config = {
|
|
47
47
|
...config_1.defaultRedactionConfig,
|
|
48
48
|
...envConfig
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
* Add custom regex patterns for advanced field detection
|
|
53
|
+
* @param patterns - Array of regex patterns to add
|
|
54
|
+
*/
|
|
55
55
|
static addCustomPatterns(patterns) {
|
|
56
|
-
const currentPatterns =
|
|
57
|
-
|
|
58
|
-
...
|
|
56
|
+
const currentPatterns = DataRedactor.config.customPatterns || [];
|
|
57
|
+
DataRedactor.config = {
|
|
58
|
+
...DataRedactor.config,
|
|
59
59
|
customPatterns: [...currentPatterns, ...patterns]
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
* Clear all custom regex patterns
|
|
64
|
+
*/
|
|
65
65
|
static clearCustomPatterns() {
|
|
66
|
-
|
|
67
|
-
...
|
|
66
|
+
DataRedactor.config = {
|
|
67
|
+
...DataRedactor.config,
|
|
68
68
|
customPatterns: []
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
* Add custom sensitive field names to the existing list
|
|
73
|
+
* @param fields - Array of field names to add
|
|
74
|
+
*/
|
|
75
75
|
static addSensitiveFields(fields) {
|
|
76
|
-
|
|
77
|
-
...
|
|
78
|
-
sensitiveFields: [...
|
|
76
|
+
DataRedactor.config = {
|
|
77
|
+
...DataRedactor.config,
|
|
78
|
+
sensitiveFields: [...DataRedactor.config.sensitiveFields, ...fields]
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
* Test if a field name would be redacted with current configuration
|
|
83
|
+
* @param fieldName - Field name to test
|
|
84
|
+
* @returns true if field would be redacted, false otherwise
|
|
85
|
+
*/
|
|
86
86
|
static testFieldRedaction(fieldName) {
|
|
87
87
|
const testObj = { [fieldName]: 'test-value' };
|
|
88
|
-
const result =
|
|
89
|
-
|
|
88
|
+
const result = DataRedactor.redactData(testObj); // Use safe property access to prevent object injection
|
|
89
|
+
if (Object.prototype.hasOwnProperty.call(result, fieldName)) {
|
|
90
|
+
// Safe access to avoid object injection
|
|
91
|
+
const value = result[fieldName];
|
|
92
|
+
return value !== 'test-value';
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
90
95
|
}
|
|
91
96
|
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
* Main entry point for data redaction
|
|
98
|
+
* Processes any type of data and returns a redacted version
|
|
99
|
+
* @param data - Data to be processed for redaction
|
|
100
|
+
* @returns Redacted version of the data
|
|
101
|
+
*/
|
|
97
102
|
static redactData(data) {
|
|
98
103
|
// Skip processing if redaction is disabled or data is null/undefined
|
|
99
|
-
if (!
|
|
104
|
+
if (!DataRedactor.config.enabled || data === null || data === undefined) {
|
|
100
105
|
return data;
|
|
101
106
|
}
|
|
102
|
-
return
|
|
107
|
+
return DataRedactor.processValue(data, new WeakSet(), 0);
|
|
103
108
|
}
|
|
104
109
|
/**
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
* Process a value of any type (primitive, object, array)
|
|
111
|
+
* Recursively handles nested structures when deepRedaction is enabled
|
|
112
|
+
* Includes circular reference protection and recursion depth limiting
|
|
113
|
+
* @param value - Value to process
|
|
114
|
+
* @param visited - Set to track visited objects (prevents circular references)
|
|
115
|
+
* @param depth - Current recursion depth (prevents stack overflow)
|
|
116
|
+
* @returns Processed value with redaction applied
|
|
117
|
+
*/
|
|
113
118
|
static processValue(value, visited = new WeakSet(), depth = 0) {
|
|
114
119
|
// Check recursion depth limit to prevent stack overflow
|
|
115
|
-
if (depth >=
|
|
120
|
+
if (depth >= DataRedactor.MAX_RECURSION_DEPTH) {
|
|
116
121
|
return '[Max Depth Exceeded]';
|
|
117
122
|
}
|
|
118
123
|
// Handle null and undefined
|
|
@@ -126,7 +131,7 @@ class DataRedactor {
|
|
|
126
131
|
return '[Circular Array]';
|
|
127
132
|
}
|
|
128
133
|
visited.add(value);
|
|
129
|
-
const result = value.map(item =>
|
|
134
|
+
const result = value.map(item => DataRedactor.processValue(item, visited, depth + 1));
|
|
130
135
|
// Keep value in visited set to detect circular references across branches
|
|
131
136
|
return result;
|
|
132
137
|
}
|
|
@@ -137,7 +142,7 @@ class DataRedactor {
|
|
|
137
142
|
return '[Circular Object]';
|
|
138
143
|
}
|
|
139
144
|
visited.add(value);
|
|
140
|
-
const result =
|
|
145
|
+
const result = DataRedactor.redactObject(value, visited, depth + 1);
|
|
141
146
|
// Keep value in visited set to detect circular references across branches
|
|
142
147
|
return result;
|
|
143
148
|
}
|
|
@@ -145,57 +150,57 @@ class DataRedactor {
|
|
|
145
150
|
return value;
|
|
146
151
|
}
|
|
147
152
|
/**
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
* Process an object and redact sensitive fields
|
|
154
|
+
* Handles field-level redaction and content truncation
|
|
155
|
+
* @param obj - Object to process
|
|
156
|
+
* @param visited - Set to track visited objects (prevents circular references)
|
|
157
|
+
* @param depth - Current recursion depth (prevents stack overflow)
|
|
158
|
+
* @returns Object with sensitive fields redacted
|
|
159
|
+
*/
|
|
155
160
|
static redactObject(obj, visited = new WeakSet(), depth = 0) {
|
|
156
161
|
// Check recursion depth limit to prevent stack overflow
|
|
157
|
-
if (depth >=
|
|
162
|
+
if (depth >= DataRedactor.MAX_REDACT_OBJECT_DEPTH) {
|
|
158
163
|
return { '[Max Depth Exceeded]': '[Max Depth Exceeded]' };
|
|
159
164
|
}
|
|
160
165
|
const redacted = {};
|
|
161
166
|
for (const [key, value] of Object.entries(obj)) {
|
|
162
167
|
// Check if this field should be completely redacted
|
|
163
|
-
if (
|
|
164
|
-
redacted
|
|
168
|
+
if (DataRedactor.isSensitiveField(key)) {
|
|
169
|
+
Object.defineProperty(redacted, key, { value: DataRedactor.config.redactionText, enumerable: true, writable: true, configurable: true });
|
|
165
170
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
redacted
|
|
171
|
+
else if (DataRedactor.isContentField(key) && typeof value === 'string') {
|
|
172
|
+
// Check if this field should be truncated (for large content)
|
|
173
|
+
Object.defineProperty(redacted, key, { value: DataRedactor.truncateContent(value), enumerable: true, writable: true, configurable: true });
|
|
169
174
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
redacted
|
|
175
|
+
else if (DataRedactor.config.deepRedaction && (typeof value === 'object' && value !== null)) {
|
|
176
|
+
// Recursively process nested objects/arrays if deep redaction is enabled
|
|
177
|
+
Object.defineProperty(redacted, key, { value: DataRedactor.processValue(value, visited, depth + 1), enumerable: true, writable: true, configurable: true });
|
|
173
178
|
}
|
|
174
|
-
// Keep the value unchanged
|
|
175
179
|
else {
|
|
176
|
-
|
|
180
|
+
// Keep the value unchanged
|
|
181
|
+
Object.defineProperty(redacted, key, { value: value, enumerable: true, writable: true, configurable: true });
|
|
177
182
|
}
|
|
178
183
|
}
|
|
179
184
|
return redacted;
|
|
180
185
|
}
|
|
181
186
|
/**
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
* Check if a field name indicates sensitive information
|
|
188
|
+
* Uses case-insensitive matching with exact and partial matches
|
|
189
|
+
* Includes smart filtering to avoid false positives and custom patterns
|
|
190
|
+
* @param fieldName - Field name to check
|
|
191
|
+
* @returns true if field should be redacted, false otherwise
|
|
192
|
+
*/
|
|
188
193
|
static isSensitiveField(fieldName) {
|
|
189
194
|
const lowerField = fieldName.toLowerCase();
|
|
190
195
|
// Check custom regex patterns first (highest priority)
|
|
191
|
-
if (
|
|
192
|
-
for (const pattern of
|
|
196
|
+
if (DataRedactor.config.customPatterns && DataRedactor.config.customPatterns.length > 0) {
|
|
197
|
+
for (const pattern of DataRedactor.config.customPatterns) {
|
|
193
198
|
if (pattern.test(fieldName)) {
|
|
194
199
|
return true;
|
|
195
200
|
}
|
|
196
201
|
}
|
|
197
202
|
}
|
|
198
|
-
return
|
|
203
|
+
return DataRedactor.config.sensitiveFields.some(sensitive => {
|
|
199
204
|
const lowerSensitive = sensitive.toLowerCase();
|
|
200
205
|
// Exact match (highest confidence)
|
|
201
206
|
if (lowerField === lowerSensitive) {
|
|
@@ -224,26 +229,26 @@ class DataRedactor {
|
|
|
224
229
|
});
|
|
225
230
|
}
|
|
226
231
|
/**
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
+
* Check if a field name indicates content that should be truncated
|
|
233
|
+
* Uses exact case-insensitive matching for content fields
|
|
234
|
+
* @param fieldName - Field name to check
|
|
235
|
+
* @returns true if field is a content field, false otherwise
|
|
236
|
+
*/
|
|
232
237
|
static isContentField(fieldName) {
|
|
233
238
|
const lowerField = fieldName.toLowerCase();
|
|
234
|
-
return
|
|
239
|
+
return DataRedactor.config.contentFields.some(content => content.toLowerCase() === lowerField);
|
|
235
240
|
}
|
|
236
241
|
/**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
+
* Truncate content that exceeds the maximum length
|
|
243
|
+
* Preserves readability while preventing log bloat
|
|
244
|
+
* @param content - Content string to potentially truncate
|
|
245
|
+
* @returns Original content or truncated version with indicator
|
|
246
|
+
*/
|
|
242
247
|
static truncateContent(content) {
|
|
243
|
-
if (content.length <=
|
|
248
|
+
if (content.length <= DataRedactor.config.maxContentLength) {
|
|
244
249
|
return content;
|
|
245
250
|
}
|
|
246
|
-
return content.substring(0,
|
|
251
|
+
return content.substring(0, DataRedactor.config.maxContentLength) + DataRedactor.config.truncationText;
|
|
247
252
|
}
|
|
248
253
|
}
|
|
249
254
|
exports.DataRedactor = DataRedactor;
|