packetsnitch 1.5.600 → 1.5.601

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.
@@ -1,1697 +0,0 @@
1
- /******/ (() => { // webpackBootstrap
2
- /******/ var __webpack_modules__ = ({
3
-
4
- /***/ "./node_modules/electron-squirrel-startup/index.js"
5
- /*!*********************************************************!*\
6
- !*** ./node_modules/electron-squirrel-startup/index.js ***!
7
- \*********************************************************/
8
- (module, __unused_webpack_exports, __webpack_require__) {
9
-
10
- var path = __webpack_require__(/*! path */ "path");
11
- var spawn = (__webpack_require__(/*! child_process */ "child_process").spawn);
12
- var debug = __webpack_require__(/*! debug */ "./node_modules/electron-squirrel-startup/node_modules/debug/src/index.js")('electron-squirrel-startup');
13
- var app = (__webpack_require__(/*! electron */ "electron").app);
14
-
15
- var run = function(args, done) {
16
- var updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
17
- debug('Spawning `%s` with args `%s`', updateExe, args);
18
- spawn(updateExe, args, {
19
- detached: true
20
- }).on('close', done);
21
- };
22
-
23
- var check = function() {
24
- if (process.platform === 'win32') {
25
- var cmd = process.argv[1];
26
- debug('processing squirrel command `%s`', cmd);
27
- var target = path.basename(process.execPath);
28
-
29
- if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') {
30
- run(['--createShortcut=' + target + ''], app.quit);
31
- return true;
32
- }
33
- if (cmd === '--squirrel-uninstall') {
34
- run(['--removeShortcut=' + target + ''], app.quit);
35
- return true;
36
- }
37
- if (cmd === '--squirrel-obsolete') {
38
- app.quit();
39
- return true;
40
- }
41
- }
42
- return false;
43
- };
44
-
45
- module.exports = check();
46
-
47
-
48
- /***/ },
49
-
50
- /***/ "./node_modules/electron-squirrel-startup/node_modules/debug/src/browser.js"
51
- /*!**********************************************************************************!*\
52
- !*** ./node_modules/electron-squirrel-startup/node_modules/debug/src/browser.js ***!
53
- \**********************************************************************************/
54
- (module, exports, __webpack_require__) {
55
-
56
- /**
57
- * This is the web browser implementation of `debug()`.
58
- *
59
- * Expose `debug()` as the module.
60
- */
61
-
62
- exports = module.exports = __webpack_require__(/*! ./debug */ "./node_modules/electron-squirrel-startup/node_modules/debug/src/debug.js");
63
- exports.log = log;
64
- exports.formatArgs = formatArgs;
65
- exports.save = save;
66
- exports.load = load;
67
- exports.useColors = useColors;
68
- exports.storage = 'undefined' != typeof chrome
69
- && 'undefined' != typeof chrome.storage
70
- ? chrome.storage.local
71
- : localstorage();
72
-
73
- /**
74
- * Colors.
75
- */
76
-
77
- exports.colors = [
78
- 'lightseagreen',
79
- 'forestgreen',
80
- 'goldenrod',
81
- 'dodgerblue',
82
- 'darkorchid',
83
- 'crimson'
84
- ];
85
-
86
- /**
87
- * Currently only WebKit-based Web Inspectors, Firefox >= v31,
88
- * and the Firebug extension (any Firefox version) are known
89
- * to support "%c" CSS customizations.
90
- *
91
- * TODO: add a `localStorage` variable to explicitly enable/disable colors
92
- */
93
-
94
- function useColors() {
95
- // NB: In an Electron preload script, document will be defined but not fully
96
- // initialized. Since we know we're in Chrome, we'll just detect this case
97
- // explicitly
98
- if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
99
- return true;
100
- }
101
-
102
- // is webkit? http://stackoverflow.com/a/16459606/376773
103
- // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
104
- return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
105
- // is firebug? http://stackoverflow.com/a/398120/376773
106
- (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
107
- // is firefox >= v31?
108
- // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
109
- (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
110
- // double check webkit in userAgent just in case we are in a worker
111
- (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
112
- }
113
-
114
- /**
115
- * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
116
- */
117
-
118
- exports.formatters.j = function(v) {
119
- try {
120
- return JSON.stringify(v);
121
- } catch (err) {
122
- return '[UnexpectedJSONParseError]: ' + err.message;
123
- }
124
- };
125
-
126
-
127
- /**
128
- * Colorize log arguments if enabled.
129
- *
130
- * @api public
131
- */
132
-
133
- function formatArgs(args) {
134
- var useColors = this.useColors;
135
-
136
- args[0] = (useColors ? '%c' : '')
137
- + this.namespace
138
- + (useColors ? ' %c' : ' ')
139
- + args[0]
140
- + (useColors ? '%c ' : ' ')
141
- + '+' + exports.humanize(this.diff);
142
-
143
- if (!useColors) return;
144
-
145
- var c = 'color: ' + this.color;
146
- args.splice(1, 0, c, 'color: inherit')
147
-
148
- // the final "%c" is somewhat tricky, because there could be other
149
- // arguments passed either before or after the %c, so we need to
150
- // figure out the correct index to insert the CSS into
151
- var index = 0;
152
- var lastC = 0;
153
- args[0].replace(/%[a-zA-Z%]/g, function(match) {
154
- if ('%%' === match) return;
155
- index++;
156
- if ('%c' === match) {
157
- // we only are interested in the *last* %c
158
- // (the user may have provided their own)
159
- lastC = index;
160
- }
161
- });
162
-
163
- args.splice(lastC, 0, c);
164
- }
165
-
166
- /**
167
- * Invokes `console.log()` when available.
168
- * No-op when `console.log` is not a "function".
169
- *
170
- * @api public
171
- */
172
-
173
- function log() {
174
- // this hackery is required for IE8/9, where
175
- // the `console.log` function doesn't have 'apply'
176
- return 'object' === typeof console
177
- && console.log
178
- && Function.prototype.apply.call(console.log, console, arguments);
179
- }
180
-
181
- /**
182
- * Save `namespaces`.
183
- *
184
- * @param {String} namespaces
185
- * @api private
186
- */
187
-
188
- function save(namespaces) {
189
- try {
190
- if (null == namespaces) {
191
- exports.storage.removeItem('debug');
192
- } else {
193
- exports.storage.debug = namespaces;
194
- }
195
- } catch(e) {}
196
- }
197
-
198
- /**
199
- * Load `namespaces`.
200
- *
201
- * @return {String} returns the previously persisted debug modes
202
- * @api private
203
- */
204
-
205
- function load() {
206
- var r;
207
- try {
208
- r = exports.storage.debug;
209
- } catch(e) {}
210
-
211
- // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
212
- if (!r && typeof process !== 'undefined' && 'env' in process) {
213
- r = process.env.DEBUG;
214
- }
215
-
216
- return r;
217
- }
218
-
219
- /**
220
- * Enable namespaces listed in `localStorage.debug` initially.
221
- */
222
-
223
- exports.enable(load());
224
-
225
- /**
226
- * Localstorage attempts to return the localstorage.
227
- *
228
- * This is necessary because safari throws
229
- * when a user disables cookies/localstorage
230
- * and you attempt to access it.
231
- *
232
- * @return {LocalStorage}
233
- * @api private
234
- */
235
-
236
- function localstorage() {
237
- try {
238
- return window.localStorage;
239
- } catch (e) {}
240
- }
241
-
242
-
243
- /***/ },
244
-
245
- /***/ "./node_modules/electron-squirrel-startup/node_modules/debug/src/debug.js"
246
- /*!********************************************************************************!*\
247
- !*** ./node_modules/electron-squirrel-startup/node_modules/debug/src/debug.js ***!
248
- \********************************************************************************/
249
- (module, exports, __webpack_require__) {
250
-
251
-
252
- /**
253
- * This is the common logic for both the Node.js and web browser
254
- * implementations of `debug()`.
255
- *
256
- * Expose `debug()` as the module.
257
- */
258
-
259
- exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
260
- exports.coerce = coerce;
261
- exports.disable = disable;
262
- exports.enable = enable;
263
- exports.enabled = enabled;
264
- exports.humanize = __webpack_require__(/*! ms */ "./node_modules/electron-squirrel-startup/node_modules/ms/index.js");
265
-
266
- /**
267
- * The currently active debug mode names, and names to skip.
268
- */
269
-
270
- exports.names = [];
271
- exports.skips = [];
272
-
273
- /**
274
- * Map of special "%n" handling functions, for the debug "format" argument.
275
- *
276
- * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
277
- */
278
-
279
- exports.formatters = {};
280
-
281
- /**
282
- * Previous log timestamp.
283
- */
284
-
285
- var prevTime;
286
-
287
- /**
288
- * Select a color.
289
- * @param {String} namespace
290
- * @return {Number}
291
- * @api private
292
- */
293
-
294
- function selectColor(namespace) {
295
- var hash = 0, i;
296
-
297
- for (i in namespace) {
298
- hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
299
- hash |= 0; // Convert to 32bit integer
300
- }
301
-
302
- return exports.colors[Math.abs(hash) % exports.colors.length];
303
- }
304
-
305
- /**
306
- * Create a debugger with the given `namespace`.
307
- *
308
- * @param {String} namespace
309
- * @return {Function}
310
- * @api public
311
- */
312
-
313
- function createDebug(namespace) {
314
-
315
- function debug() {
316
- // disabled?
317
- if (!debug.enabled) return;
318
-
319
- var self = debug;
320
-
321
- // set `diff` timestamp
322
- var curr = +new Date();
323
- var ms = curr - (prevTime || curr);
324
- self.diff = ms;
325
- self.prev = prevTime;
326
- self.curr = curr;
327
- prevTime = curr;
328
-
329
- // turn the `arguments` into a proper Array
330
- var args = new Array(arguments.length);
331
- for (var i = 0; i < args.length; i++) {
332
- args[i] = arguments[i];
333
- }
334
-
335
- args[0] = exports.coerce(args[0]);
336
-
337
- if ('string' !== typeof args[0]) {
338
- // anything else let's inspect with %O
339
- args.unshift('%O');
340
- }
341
-
342
- // apply any `formatters` transformations
343
- var index = 0;
344
- args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
345
- // if we encounter an escaped % then don't increase the array index
346
- if (match === '%%') return match;
347
- index++;
348
- var formatter = exports.formatters[format];
349
- if ('function' === typeof formatter) {
350
- var val = args[index];
351
- match = formatter.call(self, val);
352
-
353
- // now we need to remove `args[index]` since it's inlined in the `format`
354
- args.splice(index, 1);
355
- index--;
356
- }
357
- return match;
358
- });
359
-
360
- // apply env-specific formatting (colors, etc.)
361
- exports.formatArgs.call(self, args);
362
-
363
- var logFn = debug.log || exports.log || console.log.bind(console);
364
- logFn.apply(self, args);
365
- }
366
-
367
- debug.namespace = namespace;
368
- debug.enabled = exports.enabled(namespace);
369
- debug.useColors = exports.useColors();
370
- debug.color = selectColor(namespace);
371
-
372
- // env-specific initialization logic for debug instances
373
- if ('function' === typeof exports.init) {
374
- exports.init(debug);
375
- }
376
-
377
- return debug;
378
- }
379
-
380
- /**
381
- * Enables a debug mode by namespaces. This can include modes
382
- * separated by a colon and wildcards.
383
- *
384
- * @param {String} namespaces
385
- * @api public
386
- */
387
-
388
- function enable(namespaces) {
389
- exports.save(namespaces);
390
-
391
- exports.names = [];
392
- exports.skips = [];
393
-
394
- var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
395
- var len = split.length;
396
-
397
- for (var i = 0; i < len; i++) {
398
- if (!split[i]) continue; // ignore empty strings
399
- namespaces = split[i].replace(/\*/g, '.*?');
400
- if (namespaces[0] === '-') {
401
- exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
402
- } else {
403
- exports.names.push(new RegExp('^' + namespaces + '$'));
404
- }
405
- }
406
- }
407
-
408
- /**
409
- * Disable debug output.
410
- *
411
- * @api public
412
- */
413
-
414
- function disable() {
415
- exports.enable('');
416
- }
417
-
418
- /**
419
- * Returns true if the given mode name is enabled, false otherwise.
420
- *
421
- * @param {String} name
422
- * @return {Boolean}
423
- * @api public
424
- */
425
-
426
- function enabled(name) {
427
- var i, len;
428
- for (i = 0, len = exports.skips.length; i < len; i++) {
429
- if (exports.skips[i].test(name)) {
430
- return false;
431
- }
432
- }
433
- for (i = 0, len = exports.names.length; i < len; i++) {
434
- if (exports.names[i].test(name)) {
435
- return true;
436
- }
437
- }
438
- return false;
439
- }
440
-
441
- /**
442
- * Coerce `val`.
443
- *
444
- * @param {Mixed} val
445
- * @return {Mixed}
446
- * @api private
447
- */
448
-
449
- function coerce(val) {
450
- if (val instanceof Error) return val.stack || val.message;
451
- return val;
452
- }
453
-
454
-
455
- /***/ },
456
-
457
- /***/ "./node_modules/electron-squirrel-startup/node_modules/debug/src/index.js"
458
- /*!********************************************************************************!*\
459
- !*** ./node_modules/electron-squirrel-startup/node_modules/debug/src/index.js ***!
460
- \********************************************************************************/
461
- (module, __unused_webpack_exports, __webpack_require__) {
462
-
463
- /**
464
- * Detect Electron renderer process, which is node, but we should
465
- * treat as a browser.
466
- */
467
-
468
- if (typeof process !== 'undefined' && process.type === 'renderer') {
469
- module.exports = __webpack_require__(/*! ./browser.js */ "./node_modules/electron-squirrel-startup/node_modules/debug/src/browser.js");
470
- } else {
471
- module.exports = __webpack_require__(/*! ./node.js */ "./node_modules/electron-squirrel-startup/node_modules/debug/src/node.js");
472
- }
473
-
474
-
475
- /***/ },
476
-
477
- /***/ "./node_modules/electron-squirrel-startup/node_modules/debug/src/node.js"
478
- /*!*******************************************************************************!*\
479
- !*** ./node_modules/electron-squirrel-startup/node_modules/debug/src/node.js ***!
480
- \*******************************************************************************/
481
- (module, exports, __webpack_require__) {
482
-
483
- /**
484
- * Module dependencies.
485
- */
486
-
487
- var tty = __webpack_require__(/*! tty */ "tty");
488
- var util = __webpack_require__(/*! util */ "util");
489
-
490
- /**
491
- * This is the Node.js implementation of `debug()`.
492
- *
493
- * Expose `debug()` as the module.
494
- */
495
-
496
- exports = module.exports = __webpack_require__(/*! ./debug */ "./node_modules/electron-squirrel-startup/node_modules/debug/src/debug.js");
497
- exports.init = init;
498
- exports.log = log;
499
- exports.formatArgs = formatArgs;
500
- exports.save = save;
501
- exports.load = load;
502
- exports.useColors = useColors;
503
-
504
- /**
505
- * Colors.
506
- */
507
-
508
- exports.colors = [6, 2, 3, 4, 5, 1];
509
-
510
- /**
511
- * Build up the default `inspectOpts` object from the environment variables.
512
- *
513
- * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
514
- */
515
-
516
- exports.inspectOpts = Object.keys(process.env).filter(function (key) {
517
- return /^debug_/i.test(key);
518
- }).reduce(function (obj, key) {
519
- // camel-case
520
- var prop = key
521
- .substring(6)
522
- .toLowerCase()
523
- .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() });
524
-
525
- // coerce string value into JS value
526
- var val = process.env[key];
527
- if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
528
- else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
529
- else if (val === 'null') val = null;
530
- else val = Number(val);
531
-
532
- obj[prop] = val;
533
- return obj;
534
- }, {});
535
-
536
- /**
537
- * The file descriptor to write the `debug()` calls to.
538
- * Set the `DEBUG_FD` env variable to override with another value. i.e.:
539
- *
540
- * $ DEBUG_FD=3 node script.js 3>debug.log
541
- */
542
-
543
- var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
544
-
545
- if (1 !== fd && 2 !== fd) {
546
- util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')()
547
- }
548
-
549
- var stream = 1 === fd ? process.stdout :
550
- 2 === fd ? process.stderr :
551
- createWritableStdioStream(fd);
552
-
553
- /**
554
- * Is stdout a TTY? Colored output is enabled when `true`.
555
- */
556
-
557
- function useColors() {
558
- return 'colors' in exports.inspectOpts
559
- ? Boolean(exports.inspectOpts.colors)
560
- : tty.isatty(fd);
561
- }
562
-
563
- /**
564
- * Map %o to `util.inspect()`, all on a single line.
565
- */
566
-
567
- exports.formatters.o = function(v) {
568
- this.inspectOpts.colors = this.useColors;
569
- return util.inspect(v, this.inspectOpts)
570
- .split('\n').map(function(str) {
571
- return str.trim()
572
- }).join(' ');
573
- };
574
-
575
- /**
576
- * Map %o to `util.inspect()`, allowing multiple lines if needed.
577
- */
578
-
579
- exports.formatters.O = function(v) {
580
- this.inspectOpts.colors = this.useColors;
581
- return util.inspect(v, this.inspectOpts);
582
- };
583
-
584
- /**
585
- * Adds ANSI color escape codes if enabled.
586
- *
587
- * @api public
588
- */
589
-
590
- function formatArgs(args) {
591
- var name = this.namespace;
592
- var useColors = this.useColors;
593
-
594
- if (useColors) {
595
- var c = this.color;
596
- var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';
597
-
598
- args[0] = prefix + args[0].split('\n').join('\n' + prefix);
599
- args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
600
- } else {
601
- args[0] = new Date().toUTCString()
602
- + ' ' + name + ' ' + args[0];
603
- }
604
- }
605
-
606
- /**
607
- * Invokes `util.format()` with the specified arguments and writes to `stream`.
608
- */
609
-
610
- function log() {
611
- return stream.write(util.format.apply(util, arguments) + '\n');
612
- }
613
-
614
- /**
615
- * Save `namespaces`.
616
- *
617
- * @param {String} namespaces
618
- * @api private
619
- */
620
-
621
- function save(namespaces) {
622
- if (null == namespaces) {
623
- // If you set a process.env field to null or undefined, it gets cast to the
624
- // string 'null' or 'undefined'. Just delete instead.
625
- delete process.env.DEBUG;
626
- } else {
627
- process.env.DEBUG = namespaces;
628
- }
629
- }
630
-
631
- /**
632
- * Load `namespaces`.
633
- *
634
- * @return {String} returns the previously persisted debug modes
635
- * @api private
636
- */
637
-
638
- function load() {
639
- return process.env.DEBUG;
640
- }
641
-
642
- /**
643
- * Copied from `node/src/node.js`.
644
- *
645
- * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
646
- * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
647
- */
648
-
649
- function createWritableStdioStream (fd) {
650
- var stream;
651
- var tty_wrap = process.binding('tty_wrap');
652
-
653
- // Note stream._type is used for test-module-load-list.js
654
-
655
- switch (tty_wrap.guessHandleType(fd)) {
656
- case 'TTY':
657
- stream = new tty.WriteStream(fd);
658
- stream._type = 'tty';
659
-
660
- // Hack to have stream not keep the event loop alive.
661
- // See https://github.com/joyent/node/issues/1726
662
- if (stream._handle && stream._handle.unref) {
663
- stream._handle.unref();
664
- }
665
- break;
666
-
667
- case 'FILE':
668
- var fs = __webpack_require__(/*! fs */ "fs");
669
- stream = new fs.SyncWriteStream(fd, { autoClose: false });
670
- stream._type = 'fs';
671
- break;
672
-
673
- case 'PIPE':
674
- case 'TCP':
675
- var net = __webpack_require__(/*! net */ "net");
676
- stream = new net.Socket({
677
- fd: fd,
678
- readable: false,
679
- writable: true
680
- });
681
-
682
- // FIXME Should probably have an option in net.Socket to create a
683
- // stream from an existing fd which is writable only. But for now
684
- // we'll just add this hack and set the `readable` member to false.
685
- // Test: ./node test/fixtures/echo.js < /etc/passwd
686
- stream.readable = false;
687
- stream.read = null;
688
- stream._type = 'pipe';
689
-
690
- // FIXME Hack to have stream not keep the event loop alive.
691
- // See https://github.com/joyent/node/issues/1726
692
- if (stream._handle && stream._handle.unref) {
693
- stream._handle.unref();
694
- }
695
- break;
696
-
697
- default:
698
- // Probably an error on in uv_guess_handle()
699
- throw new Error('Implement me. Unknown stream file type!');
700
- }
701
-
702
- // For supporting legacy API we put the FD here.
703
- stream.fd = fd;
704
-
705
- stream._isStdio = true;
706
-
707
- return stream;
708
- }
709
-
710
- /**
711
- * Init logic for `debug` instances.
712
- *
713
- * Create a new `inspectOpts` object in case `useColors` is set
714
- * differently for a particular `debug` instance.
715
- */
716
-
717
- function init (debug) {
718
- debug.inspectOpts = {};
719
-
720
- var keys = Object.keys(exports.inspectOpts);
721
- for (var i = 0; i < keys.length; i++) {
722
- debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
723
- }
724
- }
725
-
726
- /**
727
- * Enable namespaces listed in `process.env.DEBUG` initially.
728
- */
729
-
730
- exports.enable(load());
731
-
732
-
733
- /***/ },
734
-
735
- /***/ "./node_modules/electron-squirrel-startup/node_modules/ms/index.js"
736
- /*!*************************************************************************!*\
737
- !*** ./node_modules/electron-squirrel-startup/node_modules/ms/index.js ***!
738
- \*************************************************************************/
739
- (module) {
740
-
741
- /**
742
- * Helpers.
743
- */
744
-
745
- var s = 1000;
746
- var m = s * 60;
747
- var h = m * 60;
748
- var d = h * 24;
749
- var y = d * 365.25;
750
-
751
- /**
752
- * Parse or format the given `val`.
753
- *
754
- * Options:
755
- *
756
- * - `long` verbose formatting [false]
757
- *
758
- * @param {String|Number} val
759
- * @param {Object} [options]
760
- * @throws {Error} throw an error if val is not a non-empty string or a number
761
- * @return {String|Number}
762
- * @api public
763
- */
764
-
765
- module.exports = function(val, options) {
766
- options = options || {};
767
- var type = typeof val;
768
- if (type === 'string' && val.length > 0) {
769
- return parse(val);
770
- } else if (type === 'number' && isNaN(val) === false) {
771
- return options.long ? fmtLong(val) : fmtShort(val);
772
- }
773
- throw new Error(
774
- 'val is not a non-empty string or a valid number. val=' +
775
- JSON.stringify(val)
776
- );
777
- };
778
-
779
- /**
780
- * Parse the given `str` and return milliseconds.
781
- *
782
- * @param {String} str
783
- * @return {Number}
784
- * @api private
785
- */
786
-
787
- function parse(str) {
788
- str = String(str);
789
- if (str.length > 100) {
790
- return;
791
- }
792
- var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
793
- str
794
- );
795
- if (!match) {
796
- return;
797
- }
798
- var n = parseFloat(match[1]);
799
- var type = (match[2] || 'ms').toLowerCase();
800
- switch (type) {
801
- case 'years':
802
- case 'year':
803
- case 'yrs':
804
- case 'yr':
805
- case 'y':
806
- return n * y;
807
- case 'days':
808
- case 'day':
809
- case 'd':
810
- return n * d;
811
- case 'hours':
812
- case 'hour':
813
- case 'hrs':
814
- case 'hr':
815
- case 'h':
816
- return n * h;
817
- case 'minutes':
818
- case 'minute':
819
- case 'mins':
820
- case 'min':
821
- case 'm':
822
- return n * m;
823
- case 'seconds':
824
- case 'second':
825
- case 'secs':
826
- case 'sec':
827
- case 's':
828
- return n * s;
829
- case 'milliseconds':
830
- case 'millisecond':
831
- case 'msecs':
832
- case 'msec':
833
- case 'ms':
834
- return n;
835
- default:
836
- return undefined;
837
- }
838
- }
839
-
840
- /**
841
- * Short format for `ms`.
842
- *
843
- * @param {Number} ms
844
- * @return {String}
845
- * @api private
846
- */
847
-
848
- function fmtShort(ms) {
849
- if (ms >= d) {
850
- return Math.round(ms / d) + 'd';
851
- }
852
- if (ms >= h) {
853
- return Math.round(ms / h) + 'h';
854
- }
855
- if (ms >= m) {
856
- return Math.round(ms / m) + 'm';
857
- }
858
- if (ms >= s) {
859
- return Math.round(ms / s) + 's';
860
- }
861
- return ms + 'ms';
862
- }
863
-
864
- /**
865
- * Long format for `ms`.
866
- *
867
- * @param {Number} ms
868
- * @return {String}
869
- * @api private
870
- */
871
-
872
- function fmtLong(ms) {
873
- return plural(ms, d, 'day') ||
874
- plural(ms, h, 'hour') ||
875
- plural(ms, m, 'minute') ||
876
- plural(ms, s, 'second') ||
877
- ms + ' ms';
878
- }
879
-
880
- /**
881
- * Pluralization helper.
882
- */
883
-
884
- function plural(ms, n, name) {
885
- if (ms < n) {
886
- return;
887
- }
888
- if (ms < n * 1.5) {
889
- return Math.floor(ms / n) + ' ' + name;
890
- }
891
- return Math.ceil(ms / n) + ' ' + name + 's';
892
- }
893
-
894
-
895
- /***/ },
896
-
897
- /***/ "./src/back-comm.js"
898
- /*!**************************!*\
899
- !*** ./src/back-comm.js ***!
900
- \**************************/
901
- (__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
902
-
903
- const { BrowserWindow, ipcMain } = __webpack_require__(/*! electron */ "electron");
904
- const { exec } = __webpack_require__(/*! child_process */ "child_process");
905
- const os = __webpack_require__(/*! os */ "os");
906
- const platform = os.platform();
907
- const path = __webpack_require__(/*! path */ "path");
908
- const fs = __webpack_require__(/*! fs */ "fs");
909
- const systemTempDir = os.tmpdir();
910
- const testcaseOutputDir = path.join(systemTempDir, 'testcases');
911
- ipcMain.handle('run-backend-command', async (event, filename, useLLM) => {
912
- global.logBackend(`Received pcap: ${filename}`);
913
- const isDev = !(__webpack_require__(/*! electron */ "electron").app).isPackaged;
914
- const basePath = isDev
915
- ? path.join(__dirname, '../..')
916
- : process.resourcesPath;
917
- let snitchExePath;
918
-
919
- if (platform === 'win32') {
920
- snitchExePath = path.join(basePath, '\\backend\\snitch\\snitch.exe');
921
- } else if (platform === 'linux') {
922
- snitchExePath = path.join(basePath, '/backend/snitch/snitch');
923
- } else {
924
- snitchExePath = path.join(basePath, '/backend/snitch/snitch');
925
- }
926
-
927
- const backendCommand = `"${snitchExePath}" "${filename}" -a -o "${testcaseOutputDir}"${useLLM ? '' : ' --nollm'}`;
928
-
929
- // Always start with a clean output directory so snitch never hits the
930
- // interactive overwrite prompt on second (and later) runs.
931
- if (fs.existsSync(testcaseOutputDir)) {
932
- fs.rmSync(testcaseOutputDir, { recursive: true, force: true });
933
- }
934
-
935
- global.logBackend('Command to run:', backendCommand);
936
-
937
- function sendError(message) {
938
- const mainWin = BrowserWindow.getAllWindows()[0]; // or track your main window
939
- if (mainWin) {
940
- mainWin.webContents.send('backend-error', message);
941
- }
942
- }
943
-
944
- return new Promise((resolve) => {
945
- exec(backendCommand, (error, stdout, stderr) => {
946
- resolve(stdout);
947
- global.logBackend('Backend output:', stdout);
948
- global.logBackend('Backend error output:', stderr);
949
- if (stdout.includes('Ollama')) {
950
- sendError('Backend LLM generation error!');
951
- }
952
- if (error) {
953
- if (stderr.includes('supported capture file')) {
954
- sendError('Unsupported file format!');
955
- } else {
956
- sendError('Backend execution error! ' + error);
957
- }
958
- } else {
959
- setTimeout(() => {
960
- const hostsJsonPath = path.join(testcaseOutputDir, 'hosts.json');
961
- const mainWin = BrowserWindow.getAllWindows()[0];
962
- if (mainWin && fs.existsSync(hostsJsonPath)) {
963
- const hostsJsonData = fs.readFileSync(hostsJsonPath, 'utf8');
964
- mainWin.webContents.send('json-data', hostsJsonData);
965
- }
966
- }, 200);
967
- }
968
- });
969
-
970
- global.logBackend('Backend started, waiting for completion...');
971
- });
972
- });
973
-
974
-
975
- /***/ },
976
-
977
- /***/ "child_process"
978
- /*!********************************!*\
979
- !*** external "child_process" ***!
980
- \********************************/
981
- (module) {
982
-
983
- "use strict";
984
- module.exports = require("child_process");
985
-
986
- /***/ },
987
-
988
- /***/ "electron"
989
- /*!***************************!*\
990
- !*** external "electron" ***!
991
- \***************************/
992
- (module) {
993
-
994
- "use strict";
995
- module.exports = require("electron");
996
-
997
- /***/ },
998
-
999
- /***/ "fs"
1000
- /*!*********************!*\
1001
- !*** external "fs" ***!
1002
- \*********************/
1003
- (module) {
1004
-
1005
- "use strict";
1006
- module.exports = require("fs");
1007
-
1008
- /***/ },
1009
-
1010
- /***/ "net"
1011
- /*!**********************!*\
1012
- !*** external "net" ***!
1013
- \**********************/
1014
- (module) {
1015
-
1016
- "use strict";
1017
- module.exports = require("net");
1018
-
1019
- /***/ },
1020
-
1021
- /***/ "os"
1022
- /*!*********************!*\
1023
- !*** external "os" ***!
1024
- \*********************/
1025
- (module) {
1026
-
1027
- "use strict";
1028
- module.exports = require("os");
1029
-
1030
- /***/ },
1031
-
1032
- /***/ "path"
1033
- /*!***********************!*\
1034
- !*** external "path" ***!
1035
- \***********************/
1036
- (module) {
1037
-
1038
- "use strict";
1039
- module.exports = require("path");
1040
-
1041
- /***/ },
1042
-
1043
- /***/ "tty"
1044
- /*!**********************!*\
1045
- !*** external "tty" ***!
1046
- \**********************/
1047
- (module) {
1048
-
1049
- "use strict";
1050
- module.exports = require("tty");
1051
-
1052
- /***/ },
1053
-
1054
- /***/ "url"
1055
- /*!**********************!*\
1056
- !*** external "url" ***!
1057
- \**********************/
1058
- (module) {
1059
-
1060
- "use strict";
1061
- module.exports = require("url");
1062
-
1063
- /***/ },
1064
-
1065
- /***/ "util"
1066
- /*!***********************!*\
1067
- !*** external "util" ***!
1068
- \***********************/
1069
- (module) {
1070
-
1071
- "use strict";
1072
- module.exports = require("util");
1073
-
1074
- /***/ }
1075
-
1076
- /******/ });
1077
- /************************************************************************/
1078
- /******/ // The module cache
1079
- /******/ var __webpack_module_cache__ = {};
1080
- /******/
1081
- /******/ // The require function
1082
- /******/ function __webpack_require__(moduleId) {
1083
- /******/ // Check if module is in cache
1084
- /******/ var cachedModule = __webpack_module_cache__[moduleId];
1085
- /******/ if (cachedModule !== undefined) {
1086
- /******/ return cachedModule.exports;
1087
- /******/ }
1088
- /******/ // Create a new module (and put it into the cache)
1089
- /******/ var module = __webpack_module_cache__[moduleId] = {
1090
- /******/ // no module.id needed
1091
- /******/ // no module.loaded needed
1092
- /******/ exports: {}
1093
- /******/ };
1094
- /******/
1095
- /******/ // Execute the module function
1096
- /******/ if (!(moduleId in __webpack_modules__)) {
1097
- /******/ delete __webpack_module_cache__[moduleId];
1098
- /******/ var e = new Error("Cannot find module '" + moduleId + "'");
1099
- /******/ e.code = 'MODULE_NOT_FOUND';
1100
- /******/ throw e;
1101
- /******/ }
1102
- /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
1103
- /******/
1104
- /******/ // Return the exports of the module
1105
- /******/ return module.exports;
1106
- /******/ }
1107
- /******/
1108
- /************************************************************************/
1109
- /******/ /* webpack/runtime/compat */
1110
- /******/
1111
- /******/ if (typeof __webpack_require__ !== 'undefined') __webpack_require__.ab = __dirname + "/native_modules/";
1112
- /******/
1113
- /************************************************************************/
1114
- var __webpack_exports__ = {};
1115
- // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
1116
- (() => {
1117
- /*!*********************!*\
1118
- !*** ./src/main.js ***!
1119
- \*********************/
1120
- const { app, BrowserWindow, ipcMain, dialog, shell } = __webpack_require__(/*! electron */ "electron");
1121
- const fs = __webpack_require__(/*! fs */ "fs");
1122
- const path = __webpack_require__(/*! path */ "path");
1123
- const { pathToFileURL } = __webpack_require__(/*! url */ "url");
1124
- const { exec } = __webpack_require__(/*! child_process */ "child_process");
1125
- const os = __webpack_require__(/*! os */ "os");
1126
- const util = __webpack_require__(/*! util */ "util");
1127
- const platform = os.platform();
1128
- const testcaseTempDir = path.join(os.tmpdir(), 'testcases');
1129
- const CONSOLE_INSPECT_DEPTH = 6;
1130
- const CONSOLE_MAX_ARRAY_LENGTH = 50;
1131
- let mainWindow;
1132
- let selectedFilePath;
1133
- let isBackendLoaded = false;
1134
- let versionFilePath;
1135
- let activityLogFilePath;
1136
- let hasLoggedProgramShutdown = false;
1137
- const activityLogEntries = [];
1138
- const pendingActivityLogEntries = [];
1139
- let isFirstRunAfterInstall = false;
1140
- let cachedOllamaInstalled = false;
1141
- if (__webpack_require__(/*! electron-squirrel-startup */ "./node_modules/electron-squirrel-startup/index.js")) {
1142
- app.quit();
1143
- }
1144
-
1145
- ipcMain.handle('file-size', async () => {
1146
- try {
1147
- // Get file stats asynchronously
1148
- const fileStats = await fs.promises.stat(selectedFilePath); // Using promises version of stat
1149
- return fileStats.size; // Send back the file size
1150
- } catch (fileError) {
1151
- console.error('Error getting file stats:', fileError);
1152
- return 0; // Return 0 if there's an error
1153
- }
1154
- });
1155
-
1156
- // make sure we have a fresh temp dir
1157
- fs.rmSync(testcaseTempDir, { recursive: true, force: true });
1158
-
1159
- function killBackendProcess() {
1160
- console.log('Killing backend proc...');
1161
- if (platform === 'win32') {
1162
- exec('taskkill /IM snitch.exe /T /F', (fileError) => {
1163
- if (fileError) console.error(fileError);
1164
- });
1165
- }
1166
- if (platform === 'linux') {
1167
- exec('pkill -f "testcases"', (fileError) => {
1168
- if (fileError) console.error(fileError);
1169
- });
1170
- }
1171
- }
1172
-
1173
- function checkOllama() {
1174
- return new Promise((resolve) => {
1175
- exec('ollama --version', (execError) => {
1176
- if (execError) {
1177
- resolve(false); // not installed or not in PATH
1178
- } else {
1179
- resolve(true);
1180
- }
1181
- });
1182
- });
1183
- }
1184
-
1185
- function checkNewInstall() {
1186
- if (!versionFilePath) return false;
1187
- try {
1188
- if (!fs.existsSync(versionFilePath)) {
1189
- return true;
1190
- }
1191
- const storedVersion = fs.readFileSync(versionFilePath, 'utf8').trim();
1192
- return storedVersion !== app.getVersion();
1193
- } catch (err) {
1194
- console.error('Error checking install version:', err);
1195
- return true;
1196
- }
1197
- }
1198
-
1199
- function createWindow() {
1200
- mainWindow = new BrowserWindow({
1201
- minWidth: 1450,
1202
- minHeight: 750,
1203
- frame: false,
1204
- webPreferences: {
1205
- preload: '/home/marshall/Hacks/projects/packetsnitch/Main/Frontend/.webpack/renderer/main_window/preload.js',
1206
- contextIsolation: true,
1207
- nodeIntegration: true,
1208
- },
1209
- });
1210
- mainWindow.loadURL('http://localhost:3000/main_window/index.html');
1211
- mainWindow.webContents.on('did-finish-load', () => {
1212
- mainWindow.webContents.setZoomFactor(0.8); // makes everything fit snuggly
1213
- });
1214
- mainWindow.once('close', () => {
1215
- appendActivityLogLine(
1216
- timestampLifecycleMessage(
1217
- `Session closed for PacketSnitch v${app.getVersion()}`,
1218
- ),
1219
- { broadcast: false },
1220
- );
1221
- });
1222
- }
1223
-
1224
- function formatConsoleArgs(args) {
1225
- return args
1226
- .map((arg) => {
1227
- if (arg instanceof Error) {
1228
- return arg.stack || arg.message;
1229
- }
1230
- if (typeof arg === 'string') {
1231
- return arg;
1232
- }
1233
- return util.inspect(arg, {
1234
- depth: CONSOLE_INSPECT_DEPTH,
1235
- breakLength: Infinity,
1236
- maxArrayLength: CONSOLE_MAX_ARRAY_LENGTH,
1237
- });
1238
- })
1239
- .join(' ');
1240
- }
1241
-
1242
- function appendActivityLogToFile(entry) {
1243
- try {
1244
- fs.appendFileSync(activityLogFilePath, entry + os.EOL, 'utf8');
1245
- } catch (error) {
1246
- console.error('Unable to append activity log:', error);
1247
- }
1248
- }
1249
-
1250
- function cacheActivityLogEntry(entry) {
1251
- activityLogEntries.unshift(entry);
1252
- }
1253
-
1254
- function broadcastActivityLogEntry(entry) {
1255
- if (mainWindow && !mainWindow.isDestroyed()) {
1256
- mainWindow.webContents.send('activity-log-entry', entry);
1257
- }
1258
- }
1259
-
1260
- function normalizeActivityLogEntry(entry) {
1261
- if (typeof entry !== 'string' || entry.trim() === '') return null;
1262
- return entry.trim();
1263
- }
1264
-
1265
- function timestampLifecycleMessage(message) {
1266
- return `[${new Date().toISOString()}] [Core] ${message}`;
1267
- }
1268
-
1269
- function appendActivityLogLine(entry, options = {}) {
1270
- const { broadcast = true } = options;
1271
- const normalizedEntry = normalizeActivityLogEntry(entry);
1272
- if (!normalizedEntry) return;
1273
- cacheActivityLogEntry(normalizedEntry);
1274
- if (activityLogFilePath) {
1275
- appendActivityLogToFile(normalizedEntry);
1276
- } else {
1277
- pendingActivityLogEntries.push(normalizedEntry);
1278
- }
1279
- if (broadcast) {
1280
- broadcastActivityLogEntry(normalizedEntry);
1281
- }
1282
- }
1283
-
1284
- function flushPendingActivityLogEntries() {
1285
- if (!activityLogFilePath || pendingActivityLogEntries.length === 0) return;
1286
- pendingActivityLogEntries.forEach((entry) => {
1287
- appendActivityLogToFile(entry);
1288
- });
1289
- pendingActivityLogEntries.splice(0);
1290
- }
1291
-
1292
- const originalConsoleLog = console.log.bind(console);
1293
- console.log = (...args) => {
1294
- originalConsoleLog(...args);
1295
- const message = formatConsoleArgs(args);
1296
- if (!message) return;
1297
- appendActivityLogLine(
1298
- `[${new Date().toISOString()}] [Console][Main] ${message}`,
1299
- );
1300
- };
1301
-
1302
- global.logBackend = (...args) => {
1303
- const message = formatConsoleArgs(args);
1304
- if (!message) return;
1305
- originalConsoleLog(message);
1306
- const timestamp = new Date().toISOString();
1307
- message.split(/\r?\n/).forEach((line) => {
1308
- if (line.trim() === '') return;
1309
- appendActivityLogLine(`[${timestamp}] [Console][Backend] ${line}`);
1310
- });
1311
- };
1312
-
1313
- app.whenReady().then(() => {
1314
- versionFilePath = path.join(app.getPath('userData'), 'installed_version.txt');
1315
- activityLogFilePath = path.join(app.getPath('userData'), 'activity-log.txt');
1316
- flushPendingActivityLogEntries();
1317
- appendActivityLogLine(
1318
- `[${new Date().toISOString()}] [Core] Session started for PacketSnitch v${app.getVersion()}`,
1319
- );
1320
- isFirstRunAfterInstall = checkNewInstall();
1321
- checkOllama().then((isInstalled) => {
1322
- cachedOllamaInstalled = isInstalled;
1323
- if (!isInstalled) {
1324
- console.log(
1325
- 'Ollama is not installed. LLM summarisation will be unavailable.',
1326
- );
1327
- }
1328
- createWindow();
1329
- app.on('activate', function () {
1330
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
1331
- });
1332
- console.log('App ready, waiting for file selection...');
1333
- // start the process that listens for the file selection and runs the backend command
1334
- __webpack_require__(/*! ./back-comm */ "./src/back-comm.js");
1335
- ipcMain.handle('select-file', async () => {
1336
- const { canceled, filePaths } = await dialog.showOpenDialog({
1337
- properties: ['openFile'],
1338
- });
1339
- if (canceled) return null;
1340
- console.log('Accepted pcapng.. Checking for json existence...');
1341
- isBackendLoaded = true;
1342
- // Remove stale output directory so snitch always starts with a clean slate
1343
- if (fs.existsSync(testcaseTempDir)) {
1344
- fs.rmSync(testcaseTempDir, { recursive: true, force: true });
1345
- }
1346
- console.log('File selected:', filePaths[0]);
1347
- selectedFilePath = filePaths[0];
1348
- return filePaths[0];
1349
- });
1350
- });
1351
- });
1352
-
1353
- ipcMain.handle('check-first-run', async () => {
1354
- const isDev = !app.isPackaged;
1355
- const basePath = isDev
1356
- ? path.join(__dirname, '../..')
1357
- : process.resourcesPath;
1358
- const backendExe = platform === 'win32' ? 'snitch.exe' : 'snitch';
1359
- const filesToCheck = [
1360
- {
1361
- name: 'PacketSnitch Backend (' + backendExe + ')',
1362
- path: path.join(basePath, 'backend', backendExe),
1363
- },
1364
- {
1365
- name: 'GeoIP Database (GeoLite2-City.mmdb)',
1366
- path: path.join(basePath, 'backend', 'common', 'GeoLite2-City.mmdb'),
1367
- },
1368
- {
1369
- name: 'MAC Vendors Database (mac-vendors-export.csv)',
1370
- path: path.join(basePath, 'backend', 'common', 'mac-vendors-export.csv'),
1371
- },
1372
- {
1373
- name: 'Services Database (service-names-port-numbers.csv)',
1374
- path: path.join(
1375
- basePath,
1376
- 'backend',
1377
- 'common',
1378
- 'service-names-port-numbers.csv',
1379
- ),
1380
- },
1381
- ];
1382
- const installedFiles = filesToCheck.map((f) => ({
1383
- name: f.name,
1384
- path: f.path,
1385
- exists: fs.existsSync(f.path),
1386
- }));
1387
- return {
1388
- isFirstRun: isFirstRunAfterInstall,
1389
- version: app.getVersion(),
1390
- ollamaInstalled: cachedOllamaInstalled,
1391
- installedFiles,
1392
- };
1393
- });
1394
-
1395
- ipcMain.handle('dismiss-first-run', async () => {
1396
- const currentVersion = app.getVersion();
1397
- try {
1398
- fs.writeFileSync(versionFilePath, currentVersion, 'utf8');
1399
- isFirstRunAfterInstall = false;
1400
- return { success: true };
1401
- } catch (err) {
1402
- console.error('Failed to write version file:', err);
1403
- return { success: false, error: err.message };
1404
- }
1405
- });
1406
-
1407
- ipcMain.handle('quit-app', () => {
1408
- app.quit();
1409
- });
1410
-
1411
- ipcMain.handle('prompt-save-session-on-exit', async () => {
1412
- const response = await dialog.showMessageBox({
1413
- type: 'question',
1414
- buttons: ['Save Session', "Don't Save", 'Cancel'],
1415
- defaultId: 0,
1416
- cancelId: 2,
1417
- title: 'Save Session',
1418
- message: 'Do you want to save your PacketSnitch session before exiting?',
1419
- });
1420
- if (response.response === 0) return 'save';
1421
- if (response.response === 1) return 'discard';
1422
- return 'cancel';
1423
- });
1424
-
1425
- ipcMain.handle('save-json', async (_event, jsonData) => {
1426
- if (typeof jsonData !== 'string' || jsonData.trim() === '') {
1427
- return { success: false, error: 'No JSON data to save' };
1428
- }
1429
-
1430
- const { canceled, filePath } = await dialog.showSaveDialog({
1431
- title: 'Save PacketSnitch Session',
1432
- defaultPath: path.join(app.getPath('documents'), 'packetsnitch-session.json'),
1433
- filters: [{ name: 'JSON Files', extensions: ['json'] }],
1434
- });
1435
- if (canceled || !filePath) return { success: false, canceled: true };
1436
-
1437
- try {
1438
- await fs.promises.writeFile(filePath, jsonData, 'utf8');
1439
- return { success: true };
1440
- } catch (err) {
1441
- console.error('Save error:', err);
1442
- return { success: false, error: err.message };
1443
- }
1444
- });
1445
-
1446
- ipcMain.handle('save-packet', async (_event, packetData) => {
1447
- if (packetData === null || packetData === undefined) {
1448
- return { success: false, error: 'No packet data to save' };
1449
- }
1450
- const packetJson = JSON.stringify(packetData, null, 2);
1451
-
1452
- const { canceled, filePath } = await dialog.showSaveDialog({
1453
- title: 'Export Packet',
1454
- defaultPath: path.join(app.getPath('documents'), 'packet.json'),
1455
- filters: [{ name: 'JSON Files', extensions: ['json'] }],
1456
- });
1457
- if (canceled || !filePath) return { success: false, canceled: true };
1458
-
1459
- try {
1460
- await fs.promises.writeFile(filePath, packetJson, 'utf8');
1461
- return { success: true };
1462
- } catch (err) {
1463
- console.error('Packet export error:', err);
1464
- return { success: false, error: err.message };
1465
- }
1466
- });
1467
-
1468
- ipcMain.handle('save-payload', async (_event, payloadHex) => {
1469
- if (typeof payloadHex !== 'string') {
1470
- return { success: false, error: 'No payload data to save' };
1471
- }
1472
- const normalizedHex = payloadHex.replace(/\s+/g, '');
1473
- if (
1474
- normalizedHex.length === 0 ||
1475
- normalizedHex.length % 2 !== 0 ||
1476
- !/^[\da-fA-F]+$/.test(normalizedHex)
1477
- ) {
1478
- return {
1479
- success: false,
1480
- error: 'Payload must be a non-empty hex string with an even length',
1481
- };
1482
- }
1483
-
1484
- const { canceled, filePath } = await dialog.showSaveDialog({
1485
- title: 'Export Packet Payload',
1486
- defaultPath: path.join(app.getPath('documents'), 'packet-payload.bin'),
1487
- filters: [
1488
- { name: 'Binary Files', extensions: ['bin'] },
1489
- { name: 'All Files', extensions: ['*'] },
1490
- ],
1491
- });
1492
- if (canceled || !filePath) return { success: false, canceled: true };
1493
-
1494
- try {
1495
- const payloadBuffer = Buffer.from(normalizedHex, 'hex');
1496
- await fs.promises.writeFile(filePath, payloadBuffer);
1497
- return { success: true };
1498
- } catch (err) {
1499
- console.error('Payload export error:', err);
1500
- return { success: false, error: err.message };
1501
- }
1502
- });
1503
-
1504
- ipcMain.handle('save-cookie-jar', async (_event, cookieJarText) => {
1505
- if (typeof cookieJarText !== 'string' || cookieJarText.trim() === '') {
1506
- return { success: false, error: 'No cookie jar data to save' };
1507
- }
1508
-
1509
- const { canceled, filePath } = await dialog.showSaveDialog({
1510
- title: 'Save Cookie Jar',
1511
- defaultPath: path.join(app.getPath('documents'), 'cookie_jar.txt'),
1512
- filters: [
1513
- { name: 'Text Files', extensions: ['txt'] },
1514
- { name: 'All Files', extensions: ['*'] },
1515
- ],
1516
- });
1517
- if (canceled || !filePath) return { success: false, canceled: true };
1518
-
1519
- try {
1520
- await fs.promises.writeFile(filePath, cookieJarText, 'utf8');
1521
- return { success: true };
1522
- } catch (err) {
1523
- console.error('Cookie jar save error:', err);
1524
- return { success: false, error: err.message };
1525
- }
1526
- });
1527
-
1528
- ipcMain.handle('save-notes', async (_event, notesText) => {
1529
- if (typeof notesText !== 'string' || notesText.trim() === '') {
1530
- return { success: false, error: 'No notes data to save' };
1531
- }
1532
-
1533
- const { canceled, filePath } = await dialog.showSaveDialog({
1534
- title: 'Save Notes',
1535
- defaultPath: path.join(app.getPath('documents'), 'packetsnitch-notes.txt'),
1536
- filters: [
1537
- { name: 'Text Files', extensions: ['txt'] },
1538
- { name: 'All Files', extensions: ['*'] },
1539
- ],
1540
- });
1541
- if (canceled || !filePath) return { success: false, canceled: true };
1542
-
1543
- try {
1544
- await fs.promises.writeFile(filePath, notesText, 'utf8');
1545
- return { success: true };
1546
- } catch (err) {
1547
- console.error('Notes save error:', err);
1548
- return { success: false, error: err.message };
1549
- }
1550
- });
1551
-
1552
- // Map a Content-Type header value to a file extension for HTTP body exports.
1553
- function extFromContentType(contentType) {
1554
- const base = (contentType || '').split(';')[0].trim().toLowerCase();
1555
- const map = {
1556
- 'text/html': 'html',
1557
- 'text/plain': 'txt',
1558
- 'text/css': 'css',
1559
- 'text/csv': 'csv',
1560
- 'text/xml': 'xml',
1561
- 'application/javascript': 'js',
1562
- 'application/x-javascript': 'js',
1563
- 'text/javascript': 'js',
1564
- 'application/json': 'json',
1565
- 'application/xml': 'xml',
1566
- 'image/jpeg': 'jpg',
1567
- 'image/png': 'png',
1568
- 'image/gif': 'gif',
1569
- 'image/svg+xml': 'svg',
1570
- 'image/webp': 'webp',
1571
- 'image/bmp': 'bmp',
1572
- 'image/x-icon': 'ico',
1573
- 'image/ico': 'ico',
1574
- 'application/pdf': 'pdf',
1575
- 'application/zip': 'zip',
1576
- 'application/x-zip-compressed': 'zip',
1577
- 'application/gzip': 'gz',
1578
- 'application/x-gzip': 'gz',
1579
- 'application/octet-stream': 'bin',
1580
- };
1581
- return map[base] || 'bin';
1582
- }
1583
-
1584
- // Validate and decode a hex string into a Buffer; returns null on failure.
1585
- function hexToBuffer(hex) {
1586
- if (typeof hex !== 'string') return null;
1587
- const normalized = hex.replace(/\s+/g, '');
1588
- if (normalized.length === 0 || normalized.length % 2 !== 0) return null;
1589
- if (!/^[\da-fA-F]+$/.test(normalized)) return null;
1590
- return Buffer.from(normalized, 'hex');
1591
- }
1592
-
1593
- ipcMain.handle('save-http-body', async (_event, bodyHex, contentType) => {
1594
- const buf = hexToBuffer(bodyHex);
1595
- if (!buf) return { success: false, error: 'Invalid HTTP body data' };
1596
-
1597
- const ext = extFromContentType(contentType);
1598
- const { canceled, filePath } = await dialog.showSaveDialog({
1599
- title: 'Save HTTP Body',
1600
- defaultPath: path.join(app.getPath('documents'), `http-body.${ext}`),
1601
- filters: [
1602
- { name: 'HTTP Body', extensions: [ext] },
1603
- { name: 'All Files', extensions: ['*'] },
1604
- ],
1605
- });
1606
- if (canceled || !filePath) return { success: false, canceled: true };
1607
-
1608
- try {
1609
- await fs.promises.writeFile(filePath, buf);
1610
- return { success: true };
1611
- } catch (err) {
1612
- console.error('HTTP body save error:', err);
1613
- return { success: false, error: err.message };
1614
- }
1615
- });
1616
-
1617
- ipcMain.handle('preview-http-body', async (_event, bodyHex, contentType) => {
1618
- const buf = hexToBuffer(bodyHex);
1619
- if (!buf) return { success: false, error: 'Invalid HTTP body data' };
1620
-
1621
- const ext = extFromContentType(contentType);
1622
- try {
1623
- // Use a unique temp directory per preview to avoid races and data leaks.
1624
- const tmpDir = await fs.promises.mkdtemp(
1625
- path.join(os.tmpdir(), 'ps-preview-'),
1626
- );
1627
- const tmpFile = path.join(tmpDir, `http-preview.${ext}`);
1628
- await fs.promises.writeFile(tmpFile, buf);
1629
- const fileUrl = pathToFileURL(tmpFile).href;
1630
- await shell.openExternal(fileUrl);
1631
- // Schedule cleanup after a delay to give the browser time to read the file.
1632
- setTimeout(() => {
1633
- fs.promises.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
1634
- }, 30000);
1635
- return { success: true };
1636
- } catch (err) {
1637
- console.error('HTTP body preview error:', err);
1638
- return { success: false, error: err.message };
1639
- }
1640
- });
1641
-
1642
- ipcMain.handle('open-external-url', async (_event, rawUrl) => {
1643
- if (typeof rawUrl !== 'string' || !rawUrl.trim()) {
1644
- return { success: false, error: 'Invalid URL' };
1645
- }
1646
- try {
1647
- const parsed = new URL(rawUrl.trim());
1648
- if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
1649
- return { success: false, error: 'Only HTTP/HTTPS URLs are supported' };
1650
- }
1651
- await shell.openExternal(parsed.href);
1652
- return { success: true };
1653
- } catch (err) {
1654
- return { success: false, error: err?.message || 'Invalid URL' };
1655
- }
1656
- });
1657
-
1658
- ipcMain.handle('append-activity-log', async (_event, entry) => {
1659
- const normalizedEntry = normalizeActivityLogEntry(entry);
1660
- if (!normalizedEntry) {
1661
- return { success: false, error: 'Invalid log entry' };
1662
- }
1663
- // Renderer entries are already shown locally, so skip broadcasting them back.
1664
- appendActivityLogLine(normalizedEntry, { broadcast: false });
1665
- return { success: true, path: activityLogFilePath };
1666
- });
1667
-
1668
- ipcMain.handle('get-activity-log-path', async () => {
1669
- return activityLogFilePath;
1670
- });
1671
-
1672
- ipcMain.handle('get-activity-log-entries', async () => {
1673
- return [...activityLogEntries];
1674
- });
1675
-
1676
- app.on('before-quit', () => {
1677
- if (!hasLoggedProgramShutdown) {
1678
- appendActivityLogLine(
1679
- timestampLifecycleMessage(
1680
- `Program shutdown requested for PacketSnitch v${app.getVersion()}`,
1681
- ),
1682
- { broadcast: false },
1683
- );
1684
- hasLoggedProgramShutdown = true;
1685
- }
1686
- // make sure the backend snitch process dies!
1687
- if (isBackendLoaded) {
1688
- killBackendProcess();
1689
- }
1690
- });
1691
-
1692
- })();
1693
-
1694
- module.exports = __webpack_exports__;
1695
- /******/ })()
1696
- ;
1697
- //# sourceMappingURL=index.js.map