xypriss 9.7.4 → 9.7.6
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/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js +1 -1
- package/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
- package/dist/cjs/src/plugins/builtin/RouteOptimizationPlugin.js +1 -1
- package/dist/cjs/src/plugins/core/manager/PluginSecurity.js +55 -57
- package/dist/cjs/src/plugins/core/manager/PluginSecurity.js.map +1 -1
- package/dist/cjs/src/plugins/types/PluginTypes.js.map +1 -1
- package/dist/cjs/src/server/FastServer/LogTracingMethods.js +21 -18
- package/dist/cjs/src/server/FastServer/LogTracingMethods.js.map +1 -1
- package/dist/cjs/src/server/FastServer/index.js +4 -2
- package/dist/cjs/src/server/FastServer/index.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/MonitoringManager.js +1 -1
- package/dist/cjs/src/server/components/fastapi/RouteManager.js +1 -1
- package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js +63 -923
- package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/console/types.js +6 -108
- package/dist/cjs/src/server/components/fastapi/console/types.js.map +1 -1
- package/dist/cjs/src/server/core/StartupProcessor.js +1 -1
- package/dist/cjs/src/server/core/StartupProcessor.js.map +1 -1
- package/dist/cjs/src/server/core/XHSCBridge/LogProcessor.js +19 -5
- package/dist/cjs/src/server/core/XHSCBridge/LogProcessor.js.map +1 -1
- package/dist/cjs/src/server/core/XHSCBridge/index.js +4 -1
- package/dist/cjs/src/server/core/XHSCBridge/index.js.map +1 -1
- package/dist/cjs/src/server/core/XyLifecycleManager.js +8 -0
- package/dist/cjs/src/server/core/XyLifecycleManager.js.map +1 -1
- package/dist/cjs/src/server/core/XyprissApp.js +3 -2
- package/dist/cjs/src/server/core/XyprissApp.js.map +1 -1
- package/dist/cjs/src/shared/logger/DEFAULT_LOGGER_CONFIG.js +1 -2
- package/dist/cjs/src/shared/logger/DEFAULT_LOGGER_CONFIG.js.map +1 -1
- package/dist/cjs/src/shared/logger/Logger.js +38 -0
- package/dist/cjs/src/shared/logger/Logger.js.map +1 -1
- package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js +1 -1
- package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
- package/dist/esm/src/plugins/builtin/RouteOptimizationPlugin.js +1 -1
- package/dist/esm/src/plugins/core/manager/PluginSecurity.js +55 -57
- package/dist/esm/src/plugins/core/manager/PluginSecurity.js.map +1 -1
- package/dist/esm/src/plugins/types/PluginTypes.js.map +1 -1
- package/dist/esm/src/server/FastServer/LogTracingMethods.js +21 -18
- package/dist/esm/src/server/FastServer/LogTracingMethods.js.map +1 -1
- package/dist/esm/src/server/FastServer/index.js +4 -2
- package/dist/esm/src/server/FastServer/index.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/MonitoringManager.js +1 -1
- package/dist/esm/src/server/components/fastapi/RouteManager.js +1 -1
- package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js +64 -924
- package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/console/types.js +7 -108
- package/dist/esm/src/server/components/fastapi/console/types.js.map +1 -1
- package/dist/esm/src/server/core/StartupProcessor.js +1 -1
- package/dist/esm/src/server/core/StartupProcessor.js.map +1 -1
- package/dist/esm/src/server/core/XHSCBridge/LogProcessor.js +19 -5
- package/dist/esm/src/server/core/XHSCBridge/LogProcessor.js.map +1 -1
- package/dist/esm/src/server/core/XHSCBridge/index.js +4 -1
- package/dist/esm/src/server/core/XHSCBridge/index.js.map +1 -1
- package/dist/esm/src/server/core/XyLifecycleManager.js +8 -0
- package/dist/esm/src/server/core/XyLifecycleManager.js.map +1 -1
- package/dist/esm/src/server/core/XyprissApp.js +3 -2
- package/dist/esm/src/server/core/XyprissApp.js.map +1 -1
- package/dist/esm/src/shared/logger/DEFAULT_LOGGER_CONFIG.js +1 -2
- package/dist/esm/src/shared/logger/DEFAULT_LOGGER_CONFIG.js.map +1 -1
- package/dist/esm/src/shared/logger/Logger.js +38 -0
- package/dist/esm/src/shared/logger/Logger.js.map +1 -1
- package/dist/index.d.ts +38 -90
- package/package.json +4 -49
|
@@ -1,96 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var types = require('./types.js');
|
|
4
|
-
var
|
|
5
|
-
var xyprissSecurity = require('xypriss-security');
|
|
4
|
+
var XHSCDirectIPC = require('../../../../xhsc/ipc/XHSCDirectIPC.js');
|
|
6
5
|
|
|
7
6
|
/***************************************************************************
|
|
8
|
-
* ConsoleInterceptor.ts - Console Interception System
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
* @license NehoPSLA - PROPRIETARY SOFTWARE
|
|
12
|
-
* @version 1.0
|
|
13
|
-
* @copyright Copyright (c) 2025 Nehonix. All rights reserved.
|
|
14
|
-
*
|
|
15
|
-
* PROPRIETARY AND CONFIDENTIAL
|
|
16
|
-
*
|
|
17
|
-
* This software is the proprietary information of NEHONIX and is protected
|
|
18
|
-
* by copyright law and international treaties. Unauthorized reproduction,
|
|
19
|
-
* distribution, modification, or use of this software is strictly prohibited
|
|
20
|
-
* and may result in severe civil and criminal penalties.
|
|
21
|
-
*
|
|
22
|
-
* Licensed under the NEHO Proprietary Software License Agreement (NehoPSLA).
|
|
23
|
-
* See LICENSE.md for full terms and conditions.
|
|
24
|
-
* Official License: http://dll.nehonix.com/NehoPSLA/license
|
|
25
|
-
*
|
|
26
|
-
* ACCESS RESTRICTIONS:
|
|
27
|
-
* - This software is exclusively for use by Authorized Personnel of NEHONIX
|
|
28
|
-
* - Intended for Internal Use only within NEHONIX operations
|
|
29
|
-
* - No rights granted to unauthorized individuals or entities
|
|
30
|
-
* - All modifications are works made for hire assigned to NEHONIX
|
|
31
|
-
*
|
|
32
|
-
* PROHIBITED ACTIVITIES:
|
|
33
|
-
* - Copying, distributing, or sublicensing without written permission
|
|
34
|
-
* - Reverse engineering, decompiling, or disassembling
|
|
35
|
-
* - Creating derivative works without explicit authorization
|
|
36
|
-
* - External use or commercial distribution outside NEHONIX
|
|
37
|
-
*
|
|
38
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
39
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
40
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
41
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
42
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
43
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
44
|
-
* SOFTWARE.
|
|
45
|
-
*
|
|
46
|
-
* For questions or permissions, contact:
|
|
47
|
-
* NEHONIX Legal Department
|
|
48
|
-
* Email: legal@nehonix.com
|
|
49
|
-
* Website: www.nehonix.com
|
|
50
|
-
***************************************************************************** */
|
|
7
|
+
* ConsoleInterceptor.ts - Lightweight Console Interception System
|
|
8
|
+
* Delegated to XHSC (Go) for heavy lifting
|
|
9
|
+
*************************************************************************** */
|
|
51
10
|
/**
|
|
52
|
-
* Console Interception System (CSIS)
|
|
53
|
-
*
|
|
11
|
+
* Lightweight Console Interception System (CSIS)
|
|
12
|
+
* When useNative is enabled, it delegates all filtering and encryption to XHSC (Go).
|
|
54
13
|
*/
|
|
55
14
|
class ConsoleInterceptor {
|
|
56
15
|
constructor(logger, config) {
|
|
57
|
-
this.originalConsole = {};
|
|
58
16
|
this.isIntercepting = false;
|
|
59
|
-
this.errorCount = 0;
|
|
60
|
-
this.lastSecondInterceptions = 0;
|
|
61
|
-
this.lastSecondTimestamp = 0;
|
|
62
|
-
this.performanceBuffer = [];
|
|
63
|
-
// Rate limiting
|
|
64
|
-
this.rateLimitCounter = 0;
|
|
65
|
-
this.rateLimitWindow = Date.now();
|
|
66
|
-
// Recursion prevention
|
|
67
|
-
this.isProcessing = false;
|
|
68
|
-
this.processingDepth = 0;
|
|
69
|
-
this.maxProcessingDepth = 3;
|
|
70
|
-
// Encryption handler
|
|
71
|
-
this.encryptionHandler = null;
|
|
72
|
-
// Tracing
|
|
73
|
-
this.traceBuffer = [];
|
|
74
|
-
this.traceHooks = [];
|
|
75
|
-
this.pluginEngine = null;
|
|
76
17
|
this.logger = logger;
|
|
77
|
-
// Merge with user configuration
|
|
78
|
-
const userConfig = config?.consoleInterception || {};
|
|
79
18
|
this.config = {
|
|
80
19
|
...types.DEFAULT_CONSOLE_CONFIG,
|
|
81
|
-
...
|
|
82
|
-
filters: {
|
|
83
|
-
...types.DEFAULT_CONSOLE_CONFIG.filters,
|
|
84
|
-
...userConfig.filters,
|
|
85
|
-
},
|
|
86
|
-
fallback: {
|
|
87
|
-
...types.DEFAULT_CONSOLE_CONFIG.fallback,
|
|
88
|
-
...userConfig.fallback,
|
|
89
|
-
},
|
|
90
|
-
tracing: {
|
|
91
|
-
...types.DEFAULT_CONSOLE_CONFIG.tracing,
|
|
92
|
-
...userConfig.tracing,
|
|
93
|
-
},
|
|
20
|
+
...(config?.consoleInterception || {}),
|
|
94
21
|
};
|
|
95
22
|
this.stats = {
|
|
96
23
|
totalInterceptions: 0,
|
|
@@ -101,878 +28,91 @@ class ConsoleInterceptor {
|
|
|
101
28
|
averageOverhead: 0,
|
|
102
29
|
isActive: false,
|
|
103
30
|
};
|
|
104
|
-
|
|
105
|
-
this.config.interceptMethods.forEach((method) => {
|
|
106
|
-
this.stats.methodCounts[method] = 0;
|
|
107
|
-
});
|
|
108
|
-
// Parse preserve option configuration
|
|
109
|
-
this.preserveOption = this.parsePreserveOption(this.config.preserveOriginal);
|
|
110
|
-
// Initialize encryption handler if encryption is enabled
|
|
111
|
-
this.initializeEncryptionHandler();
|
|
31
|
+
this.ipcPath = process.env.XYPRISS_IPC_PATH;
|
|
112
32
|
}
|
|
113
|
-
|
|
114
|
-
* Parse preserve option configuration
|
|
115
|
-
* Supports both boolean (backward compatibility) and object configuration
|
|
116
|
-
*/
|
|
117
|
-
parsePreserveOption(preserveOriginal) {
|
|
118
|
-
// If it's already a PreserveOption object, use it
|
|
119
|
-
if (typeof preserveOriginal === "object" && preserveOriginal !== null) {
|
|
120
|
-
return {
|
|
121
|
-
...preserveOriginal, // Use user settings
|
|
122
|
-
enabled: preserveOriginal.enabled ?? true,
|
|
123
|
-
mode: preserveOriginal.mode ?? "original",
|
|
124
|
-
showPrefix: preserveOriginal.showPrefix ?? false,
|
|
125
|
-
allowDuplication: preserveOriginal.allowDuplication ?? false,
|
|
126
|
-
separateStreams: preserveOriginal.separateStreams ?? false,
|
|
127
|
-
onlyUserApp: preserveOriginal.onlyUserApp ?? true,
|
|
128
|
-
colorize: preserveOriginal.colorize ?? true,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
// Backward compatibility: convert boolean to PreserveOption
|
|
132
|
-
if (preserveOriginal === true) {
|
|
133
|
-
// preserveOriginal: true = show original console output only
|
|
134
|
-
return types.PRESERVE_PRESETS.development;
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
// preserveOriginal: false = route through logging system
|
|
138
|
-
return types.PRESERVE_PRESETS.production;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Initialize encryption handler
|
|
143
|
-
*/
|
|
144
|
-
initializeEncryptionHandler() {
|
|
145
|
-
if (this.config.encryption?.enabled && this.config.encryption.key) {
|
|
146
|
-
try {
|
|
147
|
-
this.encryptionHandler = new ConsoleEncryption.ConsoleEncryption(this.config.encryption);
|
|
148
|
-
this.logger.info("console", "Console encryption handler initialized");
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
this.logger.error("console", "Failed to initialize encryption handler", error);
|
|
152
|
-
this.encryptionHandler = null;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
this.encryptionHandler = null;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Start console interception
|
|
161
|
-
*/
|
|
162
|
-
start() {
|
|
33
|
+
async start() {
|
|
163
34
|
if (!this.config.enabled || this.isIntercepting) {
|
|
164
35
|
return;
|
|
165
36
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
catch (error) {
|
|
175
|
-
this.handleError("Failed to start console interception", error);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Stop console interception and restore original console
|
|
180
|
-
*/
|
|
181
|
-
stop() {
|
|
182
|
-
if (!this.isIntercepting) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
try {
|
|
186
|
-
this.logger.info("console", "Stopping console interception system");
|
|
187
|
-
this.restoreOriginalConsole();
|
|
188
|
-
this.isIntercepting = false;
|
|
189
|
-
this.stats.isActive = false;
|
|
190
|
-
this.logger.info("console", "Console interception system stopped");
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
this.handleError("Failed to stop console interception", error);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Get current interception statistics
|
|
198
|
-
*/
|
|
199
|
-
getStats() {
|
|
200
|
-
return { ...this.stats };
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Update configuration at runtime
|
|
204
|
-
*/
|
|
205
|
-
updateConfig(newConfig) {
|
|
206
|
-
// Merge configurations properly
|
|
207
|
-
this.config = {
|
|
208
|
-
...this.config,
|
|
209
|
-
...newConfig,
|
|
210
|
-
filters: {
|
|
211
|
-
...this.config.filters,
|
|
212
|
-
...(newConfig.filters || {}),
|
|
213
|
-
},
|
|
214
|
-
fallback: {
|
|
215
|
-
...this.config.fallback,
|
|
216
|
-
...(newConfig.fallback || {}),
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
if (this.isIntercepting) {
|
|
220
|
-
this.stop();
|
|
221
|
-
this.start();
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Backup original console methods
|
|
226
|
-
*/
|
|
227
|
-
backupOriginalConsole() {
|
|
228
|
-
this.config.interceptMethods.forEach((method) => {
|
|
229
|
-
const consoleMethod = console[method];
|
|
230
|
-
if (typeof consoleMethod === "function") {
|
|
231
|
-
this.originalConsole[method] = consoleMethod.bind(console);
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Restore original console methods
|
|
237
|
-
*/
|
|
238
|
-
restoreOriginalConsole() {
|
|
239
|
-
Object.keys(this.originalConsole).forEach((method) => {
|
|
240
|
-
console[method] = this.originalConsole[method];
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Intercept console methods
|
|
245
|
-
*/
|
|
246
|
-
interceptConsoleMethods() {
|
|
247
|
-
this.config.interceptMethods.forEach((method) => {
|
|
248
|
-
const originalMethod = this.originalConsole[method];
|
|
249
|
-
if (!originalMethod)
|
|
250
|
-
return;
|
|
251
|
-
console[method] = (...args) => {
|
|
252
|
-
this.handleInterceptedCall(method, args, originalMethod);
|
|
253
|
-
};
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Handle intercepted console call
|
|
258
|
-
*/
|
|
259
|
-
handleInterceptedCall(method, args, originalMethod) {
|
|
260
|
-
// Prevent recursion - if we're already processing, just call original
|
|
261
|
-
if (this.isProcessing ||
|
|
262
|
-
this.processingDepth >= this.maxProcessingDepth) {
|
|
263
|
-
originalMethod(...args);
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
// Set recursion guards
|
|
267
|
-
this.isProcessing = true;
|
|
268
|
-
this.processingDepth++;
|
|
269
|
-
const startTime = this.config.performanceMode ? performance.now() : 0;
|
|
270
|
-
try {
|
|
271
|
-
// Rate limiting check
|
|
272
|
-
if (!this.checkRateLimit()) {
|
|
273
|
-
this.handlePreserveDisplay(originalMethod, args);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
// 🔧 CRITICAL FIX: Prevent recursion by ignoring logs that already have our prefixes
|
|
277
|
-
// If it's already a formatted system log, output it directly and exit
|
|
278
|
-
const message = args.join(" ");
|
|
279
|
-
if (message.includes("[USERAPP]") ||
|
|
280
|
-
message.includes("[SYSTEM]") ||
|
|
281
|
-
message.includes("[SERVER]")) {
|
|
282
|
-
originalMethod(...args);
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
// Create intercepted call object
|
|
286
|
-
const interceptedCall = {
|
|
287
|
-
method,
|
|
288
|
-
args,
|
|
289
|
-
timestamp: Date.now(),
|
|
290
|
-
level: this.mapMethodToLogLevel(method),
|
|
291
|
-
};
|
|
292
|
-
// Classify the call
|
|
293
|
-
this.classifyCall(interceptedCall);
|
|
294
|
-
// Add source mapping if enabled
|
|
295
|
-
if (this.config.sourceMapping || this.config.stackTrace) {
|
|
296
|
-
this.addSourceInformation(interceptedCall);
|
|
297
|
-
}
|
|
298
|
-
// Filter the call
|
|
299
|
-
if (!this.shouldInterceptCall(interceptedCall)) {
|
|
300
|
-
this.handlePreserveDisplay(originalMethod, args);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
// Process the intercepted call (async but don't wait to avoid blocking)
|
|
304
|
-
this.processInterceptedCall(interceptedCall).catch((error) => {
|
|
305
|
-
this.handleError("Error in async processing", error);
|
|
306
|
-
});
|
|
307
|
-
// Handle preserve display based on new preserve option
|
|
308
|
-
this.handlePreserveDisplay(originalMethod, args);
|
|
309
|
-
// 🔍 Handle tracing if enabled
|
|
310
|
-
if (this.config.tracing?.enabled) {
|
|
311
|
-
this.addToTraceBuffer(interceptedCall);
|
|
312
|
-
this.triggerTraceHooks(interceptedCall);
|
|
37
|
+
if (this.ipcPath) {
|
|
38
|
+
try {
|
|
39
|
+
const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
|
|
40
|
+
await ipc.sendCommand("console", "update-config", this.config);
|
|
41
|
+
ipc.close();
|
|
42
|
+
this.logger.info("console", "Native XHSC console interception activated via IPC");
|
|
43
|
+
this.isIntercepting = true;
|
|
44
|
+
this.stats.isActive = true;
|
|
313
45
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
this.handleError(`Error processing intercepted ${method} call`, error);
|
|
319
|
-
// Fallback to original method
|
|
320
|
-
this.handlePreserveDisplay(originalMethod, args);
|
|
321
|
-
}
|
|
322
|
-
finally {
|
|
323
|
-
// Always reset recursion guards
|
|
324
|
-
this.processingDepth--;
|
|
325
|
-
if (this.processingDepth <= 0) {
|
|
326
|
-
this.isProcessing = false;
|
|
327
|
-
this.processingDepth = 0;
|
|
46
|
+
catch (err) {
|
|
47
|
+
this.logger.error("console", `Failed to activate native interception: ${err.message}`);
|
|
328
48
|
}
|
|
329
49
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
* Handle preserve display based on preserve option configuration
|
|
333
|
-
*/
|
|
334
|
-
handlePreserveDisplay(originalMethod, args) {
|
|
335
|
-
if (!this.preserveOption.enabled) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
const mode = this.preserveOption.mode;
|
|
339
|
-
switch (mode) {
|
|
340
|
-
case "original":
|
|
341
|
-
// Show original console output only
|
|
342
|
-
originalMethod(...args);
|
|
343
|
-
break;
|
|
344
|
-
case "intercepted":
|
|
345
|
-
// Will be handled by processInterceptedCall routing to logger
|
|
346
|
-
break;
|
|
347
|
-
case "both":
|
|
348
|
-
// Show both original and intercepted (for debugging)
|
|
349
|
-
// Always show original when mode is "both"
|
|
350
|
-
originalMethod(...args);
|
|
351
|
-
break;
|
|
352
|
-
case "none":
|
|
353
|
-
// No console output at all
|
|
354
|
-
break;
|
|
355
|
-
default:
|
|
356
|
-
// Fallback to original
|
|
357
|
-
originalMethod(...args);
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Determine if logs should be routed to logger system
|
|
363
|
-
*/
|
|
364
|
-
shouldRouteToLogger() {
|
|
365
|
-
if (!this.preserveOption.enabled) {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
const mode = this.preserveOption.mode;
|
|
369
|
-
return mode === "intercepted" || mode === "both";
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Check rate limiting
|
|
373
|
-
*/
|
|
374
|
-
checkRateLimit() {
|
|
375
|
-
const now = Date.now();
|
|
376
|
-
const windowSize = 1000; // 1 second
|
|
377
|
-
// Reset counter if we're in a new window
|
|
378
|
-
if (now - this.rateLimitWindow >= windowSize) {
|
|
379
|
-
this.rateLimitCounter = 0;
|
|
380
|
-
this.rateLimitWindow = now;
|
|
381
|
-
}
|
|
382
|
-
this.rateLimitCounter++;
|
|
383
|
-
return this.rateLimitCounter <= this.config.maxInterceptionsPerSecond;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Map console method to log level
|
|
387
|
-
*/
|
|
388
|
-
mapMethodToLogLevel(method) {
|
|
389
|
-
switch (method) {
|
|
390
|
-
case "error":
|
|
391
|
-
return "error";
|
|
392
|
-
case "warn":
|
|
393
|
-
return "warn";
|
|
394
|
-
case "info":
|
|
395
|
-
return "info";
|
|
396
|
-
case "debug":
|
|
397
|
-
return "debug";
|
|
398
|
-
case "log":
|
|
399
|
-
default:
|
|
400
|
-
return "info";
|
|
50
|
+
else {
|
|
51
|
+
this.logger.warn("console", "XYPRISS_IPC_PATH not set — native interception unavailable");
|
|
401
52
|
}
|
|
402
53
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
*/
|
|
406
|
-
addSourceInformation(call) {
|
|
407
|
-
if (!this.config.sourceMapping && !this.config.stackTrace)
|
|
54
|
+
async stop() {
|
|
55
|
+
if (!this.isIntercepting)
|
|
408
56
|
return;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (this.config.sourceMapping && relevantLine) {
|
|
418
|
-
call.source = relevantLine.trim();
|
|
419
|
-
}
|
|
420
|
-
if (this.config.stackTrace) {
|
|
421
|
-
call.stackTrace = lines.slice(4).join("\n");
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
catch (error) {
|
|
426
|
-
// Silently ignore source mapping errors
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Check if a message matches exclude patterns (supports regex and strings)
|
|
431
|
-
*/
|
|
432
|
-
matchesExcludePattern(message, source) {
|
|
433
|
-
const filters = this.config.filters;
|
|
434
|
-
if (!filters?.excludePatterns?.length)
|
|
435
|
-
return false;
|
|
436
|
-
for (const pattern of filters.excludePatterns) {
|
|
437
|
-
// Check if pattern is a regex (starts and ends with /)
|
|
438
|
-
if (typeof pattern === "string" &&
|
|
439
|
-
pattern.startsWith("/") &&
|
|
440
|
-
pattern.endsWith("/")) {
|
|
441
|
-
try {
|
|
442
|
-
const regexPattern = pattern.slice(1, -1);
|
|
443
|
-
const regex = new RegExp(regexPattern);
|
|
444
|
-
if (regex.test(message) || regex.test(source)) {
|
|
445
|
-
return true;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
catch (error) {
|
|
449
|
-
// Invalid regex, treat as string
|
|
450
|
-
if (source.includes(pattern) || message.includes(pattern)) {
|
|
451
|
-
return true;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
// String pattern - simple includes check
|
|
457
|
-
if (source.includes(pattern) || message.includes(pattern)) {
|
|
458
|
-
return true;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
return false;
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Check if call should be intercepted based on filters
|
|
466
|
-
*/
|
|
467
|
-
shouldInterceptCall(call) {
|
|
468
|
-
const filters = this.config.filters;
|
|
469
|
-
if (!filters)
|
|
470
|
-
return true;
|
|
471
|
-
// Check minimum level
|
|
472
|
-
if (filters.minLevel) {
|
|
473
|
-
const levelOrder = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
474
|
-
const callLevel = levelOrder[call.level] ?? 1;
|
|
475
|
-
const minLevel = levelOrder[filters.minLevel] ?? 0;
|
|
476
|
-
if (callLevel < minLevel)
|
|
477
|
-
return false;
|
|
478
|
-
}
|
|
479
|
-
// Check message length
|
|
480
|
-
const message = call.args.join(" ");
|
|
481
|
-
if (filters.maxLength && message.length > filters.maxLength) {
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
// Check exclude patterns - if matched, mark for original display
|
|
485
|
-
const source = call.source || call.stackTrace || "";
|
|
486
|
-
if (this.matchesExcludePattern(message, source)) {
|
|
487
|
-
// Mark this call to be displayed in original format
|
|
488
|
-
call.excludedByPattern = true;
|
|
489
|
-
return false; // Don't intercept, will be shown in original format
|
|
490
|
-
}
|
|
491
|
-
// Check include patterns (if specified, at least one must match)
|
|
492
|
-
if (filters.includePatterns?.length) {
|
|
493
|
-
const hasMatch = filters.includePatterns.some((pattern) => source.includes(pattern) || message.includes(pattern));
|
|
494
|
-
if (!hasMatch)
|
|
495
|
-
return false;
|
|
496
|
-
}
|
|
497
|
-
return true;
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Classify intercepted call into a category
|
|
501
|
-
*/
|
|
502
|
-
classifyCall(call) {
|
|
503
|
-
const message = call.args.join(" ");
|
|
504
|
-
const filters = this.config.filters;
|
|
505
|
-
// Check user application patterns
|
|
506
|
-
if (filters?.userAppPatterns?.length) {
|
|
507
|
-
for (const pattern of filters.userAppPatterns) {
|
|
508
|
-
if (message.includes(pattern)) {
|
|
509
|
-
call.category = "userApp";
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
57
|
+
if (this.ipcPath) {
|
|
58
|
+
try {
|
|
59
|
+
const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
|
|
60
|
+
await ipc.sendCommand("console", "update-config", {
|
|
61
|
+
...this.config,
|
|
62
|
+
enabled: false,
|
|
63
|
+
});
|
|
64
|
+
ipc.close();
|
|
512
65
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
if (filters?.systemPatterns?.length) {
|
|
516
|
-
for (const pattern of filters.systemPatterns) {
|
|
517
|
-
if (message.includes(pattern)) {
|
|
518
|
-
call.category = "system";
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
// Ignore stop errors
|
|
521
68
|
}
|
|
522
69
|
}
|
|
523
|
-
|
|
70
|
+
this.isIntercepting = false;
|
|
71
|
+
this.stats.isActive = false;
|
|
524
72
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (this.encryptionHandler && this.config.encryption?.enabled) {
|
|
535
|
-
try {
|
|
536
|
-
await this.encryptionHandler.encryptLogEntry(call);
|
|
537
|
-
}
|
|
538
|
-
catch (error) {
|
|
539
|
-
this.logger.warn("console", "Failed to encrypt log entry", error);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
// 🔧 CRITICAL: Respect new preserve option setting
|
|
543
|
-
if (!this.shouldRouteToLogger()) {
|
|
544
|
-
// Don't route through logger based on preserve option mode
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
// Route through our logger system with appropriate prefix
|
|
548
|
-
// DISPLAY: Based on preserve option configuration
|
|
549
|
-
let displayMessage = call.args.join(" ");
|
|
550
|
-
// Determine display format only if we're actually displaying
|
|
551
|
-
const displayMode = this.config.encryption?.displayMode || "readable";
|
|
552
|
-
const showEncryptionStatus = this.config.encryption?.showEncryptionStatus || false;
|
|
553
|
-
// Apply display mode transformations if encryption is enabled
|
|
554
|
-
if (this.encryptionHandler &&
|
|
555
|
-
this.config.encryption?.enabled &&
|
|
556
|
-
displayMode !== "readable") {
|
|
557
|
-
// Get the last encrypted entry for display
|
|
558
|
-
const encryptedLogs = this.encryptionHandler.getEncryptedLogsAsStrings();
|
|
559
|
-
if (encryptedLogs.length > 0) {
|
|
560
|
-
const latestEncrypted = encryptedLogs[encryptedLogs.length - 1];
|
|
561
|
-
const encryptedHash = await this.extractEncryptedHash(latestEncrypted);
|
|
562
|
-
const enc = typeof encryptedHash !== "string"
|
|
563
|
-
? encryptedHash.toString("hex")
|
|
564
|
-
: encryptedHash;
|
|
565
|
-
switch (displayMode) {
|
|
566
|
-
case "encrypted":
|
|
567
|
-
// Show only the encrypted hash
|
|
568
|
-
displayMessage = enc;
|
|
569
|
-
break;
|
|
570
|
-
case "both":
|
|
571
|
-
// Show both readable and encrypted hash
|
|
572
|
-
displayMessage = `${call.args.join(" ")} [${enc.substring(0, 32)}...]`;
|
|
573
|
-
break;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
// Add encryption status indicator if enabled
|
|
578
|
-
if (showEncryptionStatus && this.config.encryption?.enabled) {
|
|
579
|
-
displayMessage = `${displayMessage}`;
|
|
580
|
-
}
|
|
581
|
-
const component = call.category === "system" ? "server" : "userApp";
|
|
582
|
-
// Add metadata if available
|
|
583
|
-
const metadata = [];
|
|
584
|
-
if (call.source) {
|
|
585
|
-
metadata.push(`[${call.source}]`);
|
|
586
|
-
}
|
|
587
|
-
// Route through our logging system (only if preserveOriginal is true)
|
|
588
|
-
switch (call.level) {
|
|
589
|
-
case "error":
|
|
590
|
-
this.logger.error(component, displayMessage, ...metadata);
|
|
591
|
-
break;
|
|
592
|
-
case "warn":
|
|
593
|
-
this.logger.warn(component, displayMessage, ...metadata);
|
|
594
|
-
break;
|
|
595
|
-
case "debug":
|
|
596
|
-
this.logger.debug(component, displayMessage, ...metadata);
|
|
597
|
-
break;
|
|
598
|
-
default:
|
|
599
|
-
this.logger.info(component, displayMessage, ...metadata);
|
|
600
|
-
break;
|
|
73
|
+
async getStats() {
|
|
74
|
+
if (this.ipcPath && this.isIntercepting) {
|
|
75
|
+
try {
|
|
76
|
+
const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
|
|
77
|
+
const res = await ipc.sendCommand("console", "get-stats", {});
|
|
78
|
+
ipc.close();
|
|
79
|
+
// Merge/process remote stats if needed
|
|
80
|
+
// For now, return local state with remote markers
|
|
81
|
+
return { ...this.stats, methodCounts: res.data || {} };
|
|
601
82
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
// If logging fails and preserveOriginal is true, use original console
|
|
605
|
-
if (this.config.preserveOriginal) {
|
|
606
|
-
const originalMethod = this.originalConsole[call.method] ||
|
|
607
|
-
this.originalConsole.log;
|
|
608
|
-
if (originalMethod) {
|
|
609
|
-
originalMethod(`[USERAPP] ${call.args.join(" ")}`);
|
|
610
|
-
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return { ...this.stats };
|
|
611
85
|
}
|
|
612
86
|
}
|
|
613
|
-
|
|
614
|
-
// Restore processing state
|
|
615
|
-
this.isProcessing = wasProcessing;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* Update statistics
|
|
620
|
-
*/
|
|
621
|
-
updateStats(method, startTime) {
|
|
622
|
-
this.stats.totalInterceptions++;
|
|
623
|
-
this.stats.methodCounts[method] =
|
|
624
|
-
(this.stats.methodCounts[method] || 0) + 1;
|
|
625
|
-
this.stats.lastInterceptionTime = Date.now();
|
|
626
|
-
// Calculate performance overhead
|
|
627
|
-
if (this.config.performanceMode && startTime > 0) {
|
|
628
|
-
const overhead = performance.now() - startTime;
|
|
629
|
-
this.performanceBuffer.push(overhead);
|
|
630
|
-
// Keep only last 100 measurements
|
|
631
|
-
if (this.performanceBuffer.length > 100) {
|
|
632
|
-
this.performanceBuffer.shift();
|
|
633
|
-
}
|
|
634
|
-
this.stats.averageOverhead =
|
|
635
|
-
this.performanceBuffer.reduce((a, b) => a + b, 0) /
|
|
636
|
-
this.performanceBuffer.length;
|
|
637
|
-
}
|
|
638
|
-
// Update interceptions per second
|
|
639
|
-
const now = Date.now();
|
|
640
|
-
if (now - this.lastSecondTimestamp >= 1000) {
|
|
641
|
-
this.stats.interceptionsPerSecond = this.lastSecondInterceptions;
|
|
642
|
-
this.lastSecondInterceptions = 0;
|
|
643
|
-
this.lastSecondTimestamp = now;
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
this.lastSecondInterceptions++;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Handle errors in the interception system
|
|
651
|
-
*/
|
|
652
|
-
handleError(message, error) {
|
|
653
|
-
this.errorCount++;
|
|
654
|
-
this.stats.errorCount = this.errorCount;
|
|
655
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
656
|
-
switch (this.config.fallback.onError) {
|
|
657
|
-
case "silent":
|
|
658
|
-
// Do nothing
|
|
659
|
-
break;
|
|
660
|
-
case "throw":
|
|
661
|
-
throw new Error(`${message}: ${errorMessage}`);
|
|
662
|
-
case "console":
|
|
663
|
-
default:
|
|
664
|
-
// Use original console.error to avoid recursion
|
|
665
|
-
if (this.originalConsole.error) {
|
|
666
|
-
this.originalConsole.error(`[ConsoleInterceptor] ${message}:`, errorMessage);
|
|
667
|
-
}
|
|
668
|
-
break;
|
|
669
|
-
}
|
|
670
|
-
// Check for graceful degradation
|
|
671
|
-
if (this.config.fallback.gracefulDegradation &&
|
|
672
|
-
this.errorCount >= this.config.fallback.maxErrors) {
|
|
673
|
-
this.logger.warn("console", "Too many errors in console interception, disabling system");
|
|
674
|
-
this.stop();
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
/**
|
|
678
|
-
* Check if interception is currently active
|
|
679
|
-
*/
|
|
680
|
-
isActive() {
|
|
681
|
-
return this.isIntercepting && this.stats.isActive;
|
|
87
|
+
return { ...this.stats };
|
|
682
88
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
this.stats = {
|
|
688
|
-
totalInterceptions: 0,
|
|
689
|
-
interceptionsPerSecond: 0,
|
|
690
|
-
errorCount: 0,
|
|
691
|
-
lastInterceptionTime: 0,
|
|
692
|
-
methodCounts: {},
|
|
693
|
-
averageOverhead: 0,
|
|
694
|
-
isActive: this.isIntercepting,
|
|
89
|
+
async updateConfig(newConfig) {
|
|
90
|
+
this.config = {
|
|
91
|
+
...this.config,
|
|
92
|
+
...newConfig,
|
|
695
93
|
};
|
|
696
|
-
this.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
// ENCRYPTION METHODS
|
|
703
|
-
/**
|
|
704
|
-
* Enable console encryption with a key
|
|
705
|
-
* @param key - Encryption key (if not provided, will use environment variable)
|
|
706
|
-
*/
|
|
707
|
-
enableEncryption(key) {
|
|
708
|
-
if (!this.config.encryption) {
|
|
709
|
-
this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
|
|
710
|
-
}
|
|
711
|
-
// Preserve existing display mode settings when enabling encryption
|
|
712
|
-
const existingDisplayMode = this.config.encryption.displayMode;
|
|
713
|
-
const existingShowStatus = this.config.encryption.showEncryptionStatus;
|
|
714
|
-
this.config.encryption.enabled = true;
|
|
715
|
-
// Restore display mode settings if they were previously configured
|
|
716
|
-
if (existingDisplayMode) {
|
|
717
|
-
this.config.encryption.displayMode = existingDisplayMode;
|
|
718
|
-
}
|
|
719
|
-
if (existingShowStatus !== undefined) {
|
|
720
|
-
this.config.encryption.showEncryptionStatus = existingShowStatus;
|
|
721
|
-
}
|
|
722
|
-
if (key) {
|
|
723
|
-
this.config.encryption.key = key;
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
// Try to get key from environment
|
|
727
|
-
this.config.encryption.key =
|
|
728
|
-
process.env.XYPRISS_CONSOLE_ENCRYPTION_KEY ||
|
|
729
|
-
process.env.ENC_SECRET_KEY ||
|
|
730
|
-
this.generateTemporaryKey();
|
|
731
|
-
}
|
|
732
|
-
// Initialize or update encryption handler
|
|
733
|
-
this.initializeEncryptionHandler();
|
|
734
|
-
this.logger.info("console", `Console encryption enabled (displayMode: ${this.config.encryption.displayMode})`);
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Disable console encryption
|
|
738
|
-
*/
|
|
739
|
-
disableEncryption() {
|
|
740
|
-
if (this.config.encryption) {
|
|
741
|
-
this.config.encryption.enabled = false;
|
|
742
|
-
this.config.encryption.key = undefined;
|
|
743
|
-
}
|
|
744
|
-
this.logger.info("console", "Console encryption disabled");
|
|
745
|
-
}
|
|
746
|
-
/**
|
|
747
|
-
* Set encryption key for console output
|
|
748
|
-
* @param key - The encryption key to use
|
|
749
|
-
*/
|
|
750
|
-
setEncryptionKey(key) {
|
|
751
|
-
if (!this.config.encryption) {
|
|
752
|
-
this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
|
|
753
|
-
}
|
|
754
|
-
this.config.encryption.key = key;
|
|
755
|
-
this.logger.info("console", "Console encryption key updated");
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Simple encrypt method - enables encryption with key
|
|
759
|
-
* Works independently from preserveOriginal setting
|
|
760
|
-
* @param key - Encryption key
|
|
761
|
-
*/
|
|
762
|
-
encrypt(key) {
|
|
763
|
-
this.enableEncryption(key);
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Update encryption display mode
|
|
767
|
-
* @param displayMode - How to display encrypted logs
|
|
768
|
-
* @param showEncryptionStatus - Whether to show encryption indicators
|
|
769
|
-
*/
|
|
770
|
-
setEncryptionDisplayMode(displayMode, showEncryptionStatus) {
|
|
771
|
-
if (!this.config.encryption) {
|
|
772
|
-
this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
|
|
773
|
-
}
|
|
774
|
-
this.config.encryption.displayMode = displayMode;
|
|
775
|
-
if (showEncryptionStatus !== undefined) {
|
|
776
|
-
this.config.encryption.showEncryptionStatus = showEncryptionStatus;
|
|
777
|
-
}
|
|
778
|
-
this.logger.info("console", `Console encryption display mode updated: ${displayMode}`);
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* Get encrypted console logs (for external transmission)
|
|
782
|
-
* @returns Array of encrypted log entries
|
|
783
|
-
*/
|
|
784
|
-
getEncryptedLogs() {
|
|
785
|
-
if (!this.encryptionHandler) {
|
|
786
|
-
throw new Error("Encryption is not enabled or handler is not initialized");
|
|
787
|
-
}
|
|
788
|
-
return this.encryptionHandler.getEncryptedLogsAsStrings();
|
|
789
|
-
}
|
|
790
|
-
/**
|
|
791
|
-
* Restore console logs from encrypted data
|
|
792
|
-
* @param encryptedData - Array of encrypted log entries
|
|
793
|
-
* @param key - Decryption key
|
|
794
|
-
* @returns Array of decrypted log entries
|
|
795
|
-
*/
|
|
796
|
-
async restoreFromEncrypted(encryptedData, key) {
|
|
797
|
-
try {
|
|
798
|
-
if (!this.encryptionHandler) {
|
|
799
|
-
// Create a temporary encryption handler for decryption
|
|
800
|
-
const tempConfig = {
|
|
801
|
-
...types.DEFAULT_CONSOLE_CONFIG.encryption,
|
|
802
|
-
enabled: true,
|
|
803
|
-
key,
|
|
804
|
-
};
|
|
805
|
-
this.encryptionHandler = new ConsoleEncryption.ConsoleEncryption(tempConfig);
|
|
94
|
+
if (this.ipcPath) {
|
|
95
|
+
try {
|
|
96
|
+
const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
|
|
97
|
+
await ipc.sendCommand("console", "update-config", this.config);
|
|
98
|
+
ipc.close();
|
|
806
99
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
this.logger.info("console", `Restored ${decryptedMessages.length} encrypted log entries`);
|
|
810
|
-
return decryptedMessages;
|
|
811
|
-
}
|
|
812
|
-
catch (error) {
|
|
813
|
-
this.logger.error("console", "Failed to restore encrypted logs", error);
|
|
814
|
-
throw error;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Generate a temporary encryption key (for development)
|
|
819
|
-
*/
|
|
820
|
-
generateTemporaryKey() {
|
|
821
|
-
const key = Math.random().toString(36).substring(2, 15) +
|
|
822
|
-
Math.random().toString(36).substring(2, 15);
|
|
823
|
-
this.logger.warn("console", "Using temporary encryption key. Set CONSOLE_ENCRYPTION_KEY for production.");
|
|
824
|
-
return key;
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Extract encrypted hash from the full encrypted JSON structure
|
|
828
|
-
*/
|
|
829
|
-
async extractEncryptedHash(encryptedData) {
|
|
830
|
-
try {
|
|
831
|
-
// Parse the encrypted JSON structure
|
|
832
|
-
const encryptedObj = JSON.parse(encryptedData);
|
|
833
|
-
// Get the encoding type from config
|
|
834
|
-
const encoding = this.config.encryption?.encoding || "base64";
|
|
835
|
-
// Extract just the encrypted data field and encode it properly
|
|
836
|
-
const encrypt = async (out) => {
|
|
837
|
-
const encr = await xyprissSecurity.Hash.create(encryptedObj.data, {
|
|
838
|
-
outputFormat: out,
|
|
839
|
-
});
|
|
840
|
-
return encr;
|
|
841
|
-
};
|
|
842
|
-
if (encryptedObj.data) {
|
|
843
|
-
switch (encoding) {
|
|
844
|
-
case "base64":
|
|
845
|
-
return await encrypt("base64");
|
|
846
|
-
case "hex":
|
|
847
|
-
return await encrypt("hex");
|
|
848
|
-
default:
|
|
849
|
-
return await encrypt("base64");
|
|
850
|
-
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
this.logger.error("console", `Failed to update console config: ${err.message}`);
|
|
851
102
|
}
|
|
852
|
-
// Fallback: create a hash of the entire encrypted structure
|
|
853
|
-
const buffer = Buffer.from(encryptedData);
|
|
854
|
-
return encoding === "base64"
|
|
855
|
-
? buffer.toString("base64")
|
|
856
|
-
: buffer.toString("hex");
|
|
857
103
|
}
|
|
858
|
-
catch (error) {
|
|
859
|
-
// If parsing fails, create a simple hash of the raw data
|
|
860
|
-
const encoding = this.config.encryption?.encoding || "base64";
|
|
861
|
-
const buffer = Buffer.from(encryptedData);
|
|
862
|
-
return encoding === "base64"
|
|
863
|
-
? buffer.toString("base64")
|
|
864
|
-
: buffer.toString("hex");
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* Check if encryption is currently enabled
|
|
869
|
-
*/
|
|
870
|
-
isEncryptionEnabled() {
|
|
871
|
-
return (this.config.encryption?.enabled === true &&
|
|
872
|
-
!!this.config.encryption.key);
|
|
873
|
-
}
|
|
874
|
-
/**
|
|
875
|
-
* Get encryption status and configuration
|
|
876
|
-
*/
|
|
877
|
-
getEncryptionStatus() {
|
|
878
|
-
const encryption = this.config.encryption;
|
|
879
|
-
return {
|
|
880
|
-
enabled: encryption?.enabled === true,
|
|
881
|
-
algorithm: encryption?.algorithm,
|
|
882
|
-
hasKey: !!encryption?.key,
|
|
883
|
-
externalLogging: encryption?.externalLogging?.enabled,
|
|
884
|
-
};
|
|
885
104
|
}
|
|
886
|
-
/**
|
|
887
|
-
* Add log to trace buffer
|
|
888
|
-
*/
|
|
889
|
-
addToTraceBuffer(log) {
|
|
890
|
-
const maxSize = this.config.tracing?.maxBufferSize || 1000;
|
|
891
|
-
this.traceBuffer.push({ ...log });
|
|
892
|
-
if (this.traceBuffer.length > maxSize) {
|
|
893
|
-
this.traceBuffer.shift();
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Set plugin engine for triggering hooks
|
|
898
|
-
*/
|
|
899
105
|
setPluginEngine(engine) {
|
|
900
106
|
this.pluginEngine = engine;
|
|
901
107
|
}
|
|
902
108
|
/**
|
|
903
|
-
*
|
|
904
|
-
|
|
905
|
-
triggerTraceHooks(log) {
|
|
906
|
-
const logCopy = { ...log };
|
|
907
|
-
this.traceHooks.forEach((hook) => {
|
|
908
|
-
try {
|
|
909
|
-
hook(logCopy);
|
|
910
|
-
}
|
|
911
|
-
catch (error) {
|
|
912
|
-
// Ignore hook errors to prevent affecting main flow
|
|
913
|
-
}
|
|
914
|
-
});
|
|
915
|
-
// Trigger plugin engine hooks if available
|
|
916
|
-
if (this.pluginEngine) {
|
|
917
|
-
try {
|
|
918
|
-
this.pluginEngine.triggerConsoleLogHook(logCopy);
|
|
919
|
-
}
|
|
920
|
-
catch (error) {
|
|
921
|
-
// Silently ignore
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Register a new trace hook
|
|
927
|
-
* Restricted: Only allowed if explicitly permitted or in development
|
|
928
|
-
*/
|
|
929
|
-
onTrace(hook) {
|
|
930
|
-
// Strict security: tracing must be enabled in config
|
|
931
|
-
if (!this.config.tracing?.enabled) {
|
|
932
|
-
this.logger.warn("console", "Attempted to register trace hook but tracing is disabled in configuration");
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
this.traceHooks.push(hook);
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* Get tracked logs
|
|
939
|
-
*/
|
|
940
|
-
getTraceBuffer() {
|
|
941
|
-
return [...this.traceBuffer];
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Clear trace buffer
|
|
945
|
-
*/
|
|
946
|
-
clearTraceBuffer() {
|
|
947
|
-
this.traceBuffer = [];
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* Enable tracing at runtime
|
|
951
|
-
*/
|
|
952
|
-
enableTracing(maxBufferSize) {
|
|
953
|
-
if (!this.config.tracing) {
|
|
954
|
-
this.config.tracing = {
|
|
955
|
-
enabled: true,
|
|
956
|
-
maxBufferSize: maxBufferSize || 1000,
|
|
957
|
-
includeStack: false,
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
else {
|
|
961
|
-
this.config.tracing.enabled = true;
|
|
962
|
-
if (maxBufferSize) {
|
|
963
|
-
this.config.tracing.maxBufferSize = maxBufferSize;
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
this.logger.info("console", "Console log tracing enabled");
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
|
-
* Disable tracing at runtime
|
|
109
|
+
* Called by LogProcessor when a log is received from the native engine.
|
|
110
|
+
* This triggers the plugin hooks if enabled.
|
|
970
111
|
*/
|
|
971
|
-
|
|
972
|
-
if (this.
|
|
973
|
-
this.
|
|
112
|
+
handleNativeLog(log) {
|
|
113
|
+
if (this.isIntercepting && this.pluginEngine?.triggerConsoleLogHook) {
|
|
114
|
+
this.pluginEngine.triggerConsoleLogHook(log);
|
|
974
115
|
}
|
|
975
|
-
this.logger.info("console", "Console log tracing disabled");
|
|
976
116
|
}
|
|
977
117
|
}
|
|
978
118
|
|