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.
@@ -0,0 +1,2 @@
1
+ (()=>{var e={995(e,t,s){var r=s(928),n=s(317).spawn,o=s(63)("electron-squirrel-startup"),a=s(157).app,i=function(e,t){var s=r.resolve(r.dirname(process.execPath),"..","Update.exe");o("Spawning `%s` with args `%s`",s,e),n(s,e,{detached:!0}).on("close",t)};e.exports=function(){if("win32"===process.platform){var e=process.argv[1];o("processing squirrel command `%s`",e);var t=r.basename(process.execPath);if("--squirrel-install"===e||"--squirrel-updated"===e)return i(["--createShortcut="+t],a.quit),!0;if("--squirrel-uninstall"===e)return i(["--removeShortcut="+t],a.quit),!0;if("--squirrel-obsolete"===e)return a.quit(),!0}return!1}()},491(e,t,s){function r(){var e;try{e=t.storage.debug}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e}(t=e.exports=s(584)).log=function(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)},t.formatArgs=function(e){var s=this.useColors;if(e[0]=(s?"%c":"")+this.namespace+(s?" %c":" ")+e[0]+(s?"%c ":" ")+"+"+t.humanize(this.diff),s){var r="color: "+this.color;e.splice(1,0,r,"color: inherit");var n=0,o=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(o=n))}),e.splice(o,0,r)}},t.save=function(e){try{null==e?t.storage.removeItem("debug"):t.storage.debug=e}catch(e){}},t.load=r,t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(r())},584(e,t,s){var r;function n(e){function s(){if(s.enabled){var e=s,n=+new Date,o=n-(r||n);e.diff=o,e.prev=r,e.curr=n,r=n;for(var a=new Array(arguments.length),i=0;i<a.length;i++)a[i]=arguments[i];a[0]=t.coerce(a[0]),"string"!=typeof a[0]&&a.unshift("%O");var c=0;a[0]=a[0].replace(/%([a-zA-Z%])/g,function(s,r){if("%%"===s)return s;c++;var n=t.formatters[r];if("function"==typeof n){var o=a[c];s=n.call(e,o),a.splice(c,1),c--}return s}),t.formatArgs.call(e,a),(s.log||t.log||console.log.bind(console)).apply(e,a)}}return s.namespace=e,s.enabled=t.enabled(e),s.useColors=t.useColors(),s.color=function(e){var s,r=0;for(s in e)r=(r<<5)-r+e.charCodeAt(s),r|=0;return t.colors[Math.abs(r)%t.colors.length]}(e),"function"==typeof t.init&&t.init(s),s}(t=e.exports=n.debug=n.default=n).coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){t.enable("")},t.enable=function(e){t.save(e),t.names=[],t.skips=[];for(var s=("string"==typeof e?e:"").split(/[\s,]+/),r=s.length,n=0;n<r;n++)s[n]&&("-"===(e=s[n].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.substr(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){var s,r;for(s=0,r=t.skips.length;s<r;s++)if(t.skips[s].test(e))return!1;for(s=0,r=t.names.length;s<r;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(567),t.names=[],t.skips=[],t.formatters={}},63(e,t,s){"undefined"!=typeof process&&"renderer"===process.type?e.exports=s(491):e.exports=s(487)},487(e,t,s){var r=s(18),n=s(23);(t=e.exports=s(584)).init=function(e){e.inspectOpts={};for(var s=Object.keys(t.inspectOpts),r=0;r<s.length;r++)e.inspectOpts[s[r]]=t.inspectOpts[s[r]]},t.log=function(){return a.write(n.format.apply(n,arguments)+"\n")},t.formatArgs=function(e){var s=this.namespace;if(this.useColors){var r=this.color,n=" [3"+r+";1m"+s+" ";e[0]=n+e[0].split("\n").join("\n"+n),e.push("[3"+r+"m+"+t.humanize(this.diff)+"")}else e[0]=(new Date).toUTCString()+" "+s+" "+e[0]},t.save=function(e){null==e?delete process.env.DEBUG:process.env.DEBUG=e},t.load=i,t.useColors=function(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):r.isatty(o)},t.colors=[6,2,3,4,5,1],t.inspectOpts=Object.keys(process.env).filter(function(e){return/^debug_/i.test(e)}).reduce(function(e,t){var s=t.substring(6).toLowerCase().replace(/_([a-z])/g,function(e,t){return t.toUpperCase()}),r=process.env[t];return r=!!/^(yes|on|true|enabled)$/i.test(r)||!/^(no|off|false|disabled)$/i.test(r)&&("null"===r?null:Number(r)),e[s]=r,e},{});var o=parseInt(process.env.DEBUG_FD,10)||2;1!==o&&2!==o&&n.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)")();var a=1===o?process.stdout:2===o?process.stderr:function(e){var t;switch(process.binding("tty_wrap").guessHandleType(e)){case"TTY":(t=new r.WriteStream(e))._type="tty",t._handle&&t._handle.unref&&t._handle.unref();break;case"FILE":(t=new(s(896).SyncWriteStream)(e,{autoClose:!1}))._type="fs";break;case"PIPE":case"TCP":(t=new(s(278).Socket)({fd:e,readable:!1,writable:!0})).readable=!1,t.read=null,t._type="pipe",t._handle&&t._handle.unref&&t._handle.unref();break;default:throw new Error("Implement me. Unknown stream file type!")}return t.fd=e,t._isStdio=!0,t}(o);function i(){return process.env.DEBUG}t.formatters.o=function(e){return this.inspectOpts.colors=this.useColors,n.inspect(e,this.inspectOpts).split("\n").map(function(e){return e.trim()}).join(" ")},t.formatters.O=function(e){return this.inspectOpts.colors=this.useColors,n.inspect(e,this.inspectOpts)},t.enable(i())},567(e){var t=1e3,s=60*t,r=60*s,n=24*r;function o(e,t,s){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+s:Math.ceil(e/t)+" "+s+"s"}e.exports=function(e,a){a=a||{};var i,c=typeof e;if("string"===c&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(o){var a=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*a;case"days":case"day":case"d":return a*n;case"hours":case"hour":case"hrs":case"hr":case"h":return a*r;case"minutes":case"minute":case"mins":case"min":case"m":return a*s;case"seconds":case"second":case"secs":case"sec":case"s":return a*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return a;default:return}}}}(e);if("number"===c&&!1===isNaN(e))return a.long?o(i=e,n,"day")||o(i,r,"hour")||o(i,s,"minute")||o(i,t,"second")||i+" ms":function(e){return e>=n?Math.round(e/n)+"d":e>=r?Math.round(e/r)+"h":e>=s?Math.round(e/s)+"m":e>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},950(e,t,s){const{BrowserWindow:r,ipcMain:n}=s(157),{exec:o}=s(317),a=s(857),i=a.platform(),c=s(928),l=s(896),u=a.tmpdir(),p=c.join(u,"testcases");n.handle("run-backend-command",async(e,t,n)=>{global.logBackend(`Received pcap: ${t}`);const a=s(157).app.isPackaged?process.resourcesPath:c.join(__dirname,"../..");let u;u="win32"===i?c.join(a,"\\backend\\snitch\\snitch.exe"):c.join(a,"/backend/snitch/snitch");const d=`"${u}" "${t}" -a -o "${p}"${n?"":" --nollm"}`;function f(e){const t=r.getAllWindows()[0];t&&t.webContents.send("backend-error",e)}return l.existsSync(p)&&l.rmSync(p,{recursive:!0,force:!0}),global.logBackend("Command to run:",d),new Promise(e=>{o(d,(t,s,n)=>{e(s),global.logBackend("Backend output:",s),global.logBackend("Backend error output:",n),s.includes("Ollama")&&f("Backend LLM generation error!"),t?n.includes("supported capture file")?f("Unsupported file format!"):f("Backend execution error! "+t):setTimeout(()=>{const e=c.join(p,"hosts.json"),t=r.getAllWindows()[0];if(t&&l.existsSync(e)){const s=l.readFileSync(e,"utf8");t.webContents.send("json-data",s)}},200)}),global.logBackend("Backend started, waiting for completion...")})})},317(e){"use strict";e.exports=require("child_process")},157(e){"use strict";e.exports=require("electron")},896(e){"use strict";e.exports=require("fs")},278(e){"use strict";e.exports=require("net")},857(e){"use strict";e.exports=require("os")},928(e){"use strict";e.exports=require("path")},18(e){"use strict";e.exports=require("tty")},16(e){"use strict";e.exports=require("url")},23(e){"use strict";e.exports=require("util")}},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}void 0!==s&&(s.ab=__dirname+"/native_modules/");const{app:r,BrowserWindow:n,ipcMain:o,dialog:a,shell:i}=s(157),c=s(896),l=s(928),{pathToFileURL:u}=s(16),{exec:p}=s(317),d=s(857),f=s(23),m=d.platform(),h=l.join(d.tmpdir(),"testcases");let g,v,y,w,b=!1,x=!1;const k=[],S=[];let P=!1,j=!1;function C(){g=new n({minWidth:1450,minHeight:750,frame:!1,webPreferences:{preload:require("path").resolve(__dirname,"../renderer","main_window","preload.js"),contextIsolation:!0,nodeIntegration:!0}}),g.loadURL(`file://${require("path").resolve(__dirname,"..","renderer","main_window","index.html")}`),g.webContents.on("did-finish-load",()=>{g.webContents.setZoomFactor(.8)}),g.once("close",()=>{B(D(`Session closed for PacketSnitch v${r.getVersion()}`),{broadcast:!1})})}function F(e){return e.map(e=>e instanceof Error?e.stack||e.message:"string"==typeof e?e:f.inspect(e,{depth:6,breakLength:1/0,maxArrayLength:50})).join(" ")}function O(e){try{c.appendFileSync(w,e+d.EOL,"utf8")}catch(e){console.error("Unable to append activity log:",e)}}function _(e){return"string"!=typeof e||""===e.trim()?null:e.trim()}function D(e){return`[${(new Date).toISOString()}] [Core] ${e}`}function B(e,t={}){const{broadcast:s=!0}=t,r=_(e);r&&(function(e){k.unshift(e)}(r),w?O(r):S.push(r),s&&function(e){g&&!g.isDestroyed()&&g.webContents.send("activity-log-entry",e)}(r))}s(995)&&r.quit(),o.handle("file-size",async()=>{try{return(await c.promises.stat(v)).size}catch(e){return console.error("Error getting file stats:",e),0}}),c.rmSync(h,{recursive:!0,force:!0});const E=console.log.bind(console);function T(e){return{"text/html":"html","text/plain":"txt","text/css":"css","text/csv":"csv","text/xml":"xml","application/javascript":"js","application/x-javascript":"js","text/javascript":"js","application/json":"json","application/xml":"xml","image/jpeg":"jpg","image/png":"png","image/gif":"gif","image/svg+xml":"svg","image/webp":"webp","image/bmp":"bmp","image/x-icon":"ico","image/ico":"ico","application/pdf":"pdf","application/zip":"zip","application/x-zip-compressed":"zip","application/gzip":"gz","application/x-gzip":"gz","application/octet-stream":"bin"}[(e||"").split(";")[0].trim().toLowerCase()]||"bin"}function q(e){if("string"!=typeof e)return null;const t=e.replace(/\s+/g,"");return 0===t.length||t.length%2!=0?null:/^[\da-fA-F]+$/.test(t)?Buffer.from(t,"hex"):null}console.log=(...e)=>{E(...e);const t=F(e);t&&B(`[${(new Date).toISOString()}] [Console][Main] ${t}`)},global.logBackend=(...e)=>{const t=F(e);if(!t)return;E(t);const s=(new Date).toISOString();t.split(/\r?\n/).forEach(e=>{""!==e.trim()&&B(`[${s}] [Console][Backend] ${e}`)})},r.whenReady().then(()=>{y=l.join(r.getPath("userData"),"installed_version.txt"),w=l.join(r.getPath("userData"),"activity-log.txt"),w&&0!==S.length&&(S.forEach(e=>{O(e)}),S.splice(0)),B(`[${(new Date).toISOString()}] [Core] Session started for PacketSnitch v${r.getVersion()}`),P=function(){if(!y)return!1;try{return!c.existsSync(y)||c.readFileSync(y,"utf8").trim()!==r.getVersion()}catch(e){return console.error("Error checking install version:",e),!0}}(),new Promise(e=>{p("ollama --version",t=>{e(!t)})}).then(e=>{j=e,e||console.log("Ollama is not installed. LLM summarisation will be unavailable."),C(),r.on("activate",function(){0===n.getAllWindows().length&&C()}),console.log("App ready, waiting for file selection..."),s(950),o.handle("select-file",async()=>{const{canceled:e,filePaths:t}=await a.showOpenDialog({properties:["openFile"]});return e?null:(console.log("Accepted pcapng.. Checking for json existence..."),b=!0,c.existsSync(h)&&c.rmSync(h,{recursive:!0,force:!0}),console.log("File selected:",t[0]),v=t[0],t[0])})})}),o.handle("check-first-run",async()=>{const e=r.isPackaged?process.resourcesPath:l.join(__dirname,"../.."),t="win32"===m?"snitch.exe":"snitch",s=[{name:"PacketSnitch Backend ("+t+")",path:l.join(e,"backend",t)},{name:"GeoIP Database (GeoLite2-City.mmdb)",path:l.join(e,"backend","common","GeoLite2-City.mmdb")},{name:"MAC Vendors Database (mac-vendors-export.csv)",path:l.join(e,"backend","common","mac-vendors-export.csv")},{name:"Services Database (service-names-port-numbers.csv)",path:l.join(e,"backend","common","service-names-port-numbers.csv")}].map(e=>({name:e.name,path:e.path,exists:c.existsSync(e.path)}));return{isFirstRun:P,version:r.getVersion(),ollamaInstalled:j,installedFiles:s}}),o.handle("dismiss-first-run",async()=>{const e=r.getVersion();try{return c.writeFileSync(y,e,"utf8"),P=!1,{success:!0}}catch(e){return console.error("Failed to write version file:",e),{success:!1,error:e.message}}}),o.handle("quit-app",()=>{r.quit()}),o.handle("prompt-save-session-on-exit",async()=>{const e=await a.showMessageBox({type:"question",buttons:["Save Session","Don't Save","Cancel"],defaultId:0,cancelId:2,title:"Save Session",message:"Do you want to save your PacketSnitch session before exiting?"});return 0===e.response?"save":1===e.response?"discard":"cancel"}),o.handle("save-json",async(e,t)=>{if("string"!=typeof t||""===t.trim())return{success:!1,error:"No JSON data to save"};const{canceled:s,filePath:n}=await a.showSaveDialog({title:"Save PacketSnitch Session",defaultPath:l.join(r.getPath("documents"),"packetsnitch-session.json"),filters:[{name:"JSON Files",extensions:["json"]}]});if(s||!n)return{success:!1,canceled:!0};try{return await c.promises.writeFile(n,t,"utf8"),{success:!0}}catch(e){return console.error("Save error:",e),{success:!1,error:e.message}}}),o.handle("save-packet",async(e,t)=>{if(null==t)return{success:!1,error:"No packet data to save"};const s=JSON.stringify(t,null,2),{canceled:n,filePath:o}=await a.showSaveDialog({title:"Export Packet",defaultPath:l.join(r.getPath("documents"),"packet.json"),filters:[{name:"JSON Files",extensions:["json"]}]});if(n||!o)return{success:!1,canceled:!0};try{return await c.promises.writeFile(o,s,"utf8"),{success:!0}}catch(e){return console.error("Packet export error:",e),{success:!1,error:e.message}}}),o.handle("save-payload",async(e,t)=>{if("string"!=typeof t)return{success:!1,error:"No payload data to save"};const s=t.replace(/\s+/g,"");if(0===s.length||s.length%2!=0||!/^[\da-fA-F]+$/.test(s))return{success:!1,error:"Payload must be a non-empty hex string with an even length"};const{canceled:n,filePath:o}=await a.showSaveDialog({title:"Export Packet Payload",defaultPath:l.join(r.getPath("documents"),"packet-payload.bin"),filters:[{name:"Binary Files",extensions:["bin"]},{name:"All Files",extensions:["*"]}]});if(n||!o)return{success:!1,canceled:!0};try{const e=Buffer.from(s,"hex");return await c.promises.writeFile(o,e),{success:!0}}catch(e){return console.error("Payload export error:",e),{success:!1,error:e.message}}}),o.handle("save-cookie-jar",async(e,t)=>{if("string"!=typeof t||""===t.trim())return{success:!1,error:"No cookie jar data to save"};const{canceled:s,filePath:n}=await a.showSaveDialog({title:"Save Cookie Jar",defaultPath:l.join(r.getPath("documents"),"cookie_jar.txt"),filters:[{name:"Text Files",extensions:["txt"]},{name:"All Files",extensions:["*"]}]});if(s||!n)return{success:!1,canceled:!0};try{return await c.promises.writeFile(n,t,"utf8"),{success:!0}}catch(e){return console.error("Cookie jar save error:",e),{success:!1,error:e.message}}}),o.handle("save-notes",async(e,t)=>{if("string"!=typeof t||""===t.trim())return{success:!1,error:"No notes data to save"};const{canceled:s,filePath:n}=await a.showSaveDialog({title:"Save Notes",defaultPath:l.join(r.getPath("documents"),"packetsnitch-notes.txt"),filters:[{name:"Text Files",extensions:["txt"]},{name:"All Files",extensions:["*"]}]});if(s||!n)return{success:!1,canceled:!0};try{return await c.promises.writeFile(n,t,"utf8"),{success:!0}}catch(e){return console.error("Notes save error:",e),{success:!1,error:e.message}}}),o.handle("save-http-body",async(e,t,s)=>{const n=q(t);if(!n)return{success:!1,error:"Invalid HTTP body data"};const o=T(s),{canceled:i,filePath:u}=await a.showSaveDialog({title:"Save HTTP Body",defaultPath:l.join(r.getPath("documents"),`http-body.${o}`),filters:[{name:"HTTP Body",extensions:[o]},{name:"All Files",extensions:["*"]}]});if(i||!u)return{success:!1,canceled:!0};try{return await c.promises.writeFile(u,n),{success:!0}}catch(e){return console.error("HTTP body save error:",e),{success:!1,error:e.message}}}),o.handle("preview-http-body",async(e,t,s)=>{const r=q(t);if(!r)return{success:!1,error:"Invalid HTTP body data"};const n=T(s);try{const e=await c.promises.mkdtemp(l.join(d.tmpdir(),"ps-preview-")),t=l.join(e,`http-preview.${n}`);await c.promises.writeFile(t,r);const s=u(t).href;return await i.openExternal(s),setTimeout(()=>{c.promises.rm(e,{recursive:!0,force:!0}).catch(()=>{})},3e4),{success:!0}}catch(e){return console.error("HTTP body preview error:",e),{success:!1,error:e.message}}}),o.handle("open-external-url",async(e,t)=>{if("string"!=typeof t||!t.trim())return{success:!1,error:"Invalid URL"};try{const e=new URL(t.trim());return"http:"!==e.protocol&&"https:"!==e.protocol?{success:!1,error:"Only HTTP/HTTPS URLs are supported"}:(await i.openExternal(e.href),{success:!0})}catch(e){return{success:!1,error:e?.message||"Invalid URL"}}}),o.handle("append-activity-log",async(e,t)=>{const s=_(t);return s?(B(s,{broadcast:!1}),{success:!0,path:w}):{success:!1,error:"Invalid log entry"}}),o.handle("get-activity-log-path",async()=>w),o.handle("get-activity-log-entries",async()=>[...k]),r.on("before-quit",()=>{x||(B(D(`Program shutdown requested for PacketSnitch v${r.getVersion()}`),{broadcast:!1}),x=!0),b&&(console.log("Killing backend proc..."),"win32"===m&&p("taskkill /IM snitch.exe /T /F",e=>{e&&console.error(e)}),"linux"===m&&p('pkill -f "testcases"',e=>{e&&console.error(e)}))}),module.exports={}})();
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://packetsnitch/./node_modules/electron-squirrel-startup/index.js","webpack://packetsnitch/./node_modules/electron-squirrel-startup/node_modules/debug/src/browser.js","webpack://packetsnitch/./node_modules/electron-squirrel-startup/node_modules/debug/src/debug.js","webpack://packetsnitch/./node_modules/electron-squirrel-startup/node_modules/debug/src/index.js","webpack://packetsnitch/./node_modules/electron-squirrel-startup/node_modules/debug/src/node.js","webpack://packetsnitch/./node_modules/electron-squirrel-startup/node_modules/ms/index.js","webpack://packetsnitch/./src/back-comm.js","webpack://packetsnitch/external node-commonjs \"child_process\"","webpack://packetsnitch/external node-commonjs \"electron\"","webpack://packetsnitch/external node-commonjs \"fs\"","webpack://packetsnitch/external node-commonjs \"net\"","webpack://packetsnitch/external node-commonjs \"os\"","webpack://packetsnitch/external node-commonjs \"path\"","webpack://packetsnitch/external node-commonjs \"tty\"","webpack://packetsnitch/external node-commonjs \"url\"","webpack://packetsnitch/external node-commonjs \"util\"","webpack://packetsnitch/webpack/bootstrap","webpack://packetsnitch/webpack/runtime/compat","webpack://packetsnitch/./src/main.js"],"sourcesContent":["var path = require('path');\nvar spawn = require('child_process').spawn;\nvar debug = require('debug')('electron-squirrel-startup');\nvar app = require('electron').app;\n\nvar run = function(args, done) {\n var updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');\n debug('Spawning `%s` with args `%s`', updateExe, args);\n spawn(updateExe, args, {\n detached: true\n }).on('close', done);\n};\n\nvar check = function() {\n if (process.platform === 'win32') {\n var cmd = process.argv[1];\n debug('processing squirrel command `%s`', cmd);\n var target = path.basename(process.execPath);\n\n if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') {\n run(['--createShortcut=' + target + ''], app.quit);\n return true;\n }\n if (cmd === '--squirrel-uninstall') {\n run(['--removeShortcut=' + target + ''], app.quit);\n return true;\n }\n if (cmd === '--squirrel-obsolete') {\n app.quit();\n return true;\n }\n }\n return false;\n};\n\nmodule.exports = check();\n","/**\n * This is the web browser implementation of `debug()`.\n *\n * Expose `debug()` as the module.\n */\n\nexports = module.exports = require('./debug');\nexports.log = log;\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = 'undefined' != typeof chrome\n && 'undefined' != typeof chrome.storage\n ? chrome.storage.local\n : localstorage();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n 'lightseagreen',\n 'forestgreen',\n 'goldenrod',\n 'dodgerblue',\n 'darkorchid',\n 'crimson'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\nfunction useColors() {\n // NB: In an Electron preload script, document will be defined but not fully\n // initialized. Since we know we're in Chrome, we'll just detect this case\n // explicitly\n if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {\n return true;\n }\n\n // is webkit? http://stackoverflow.com/a/16459606/376773\n // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n // is firebug? http://stackoverflow.com/a/398120/376773\n (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n // is firefox >= v31?\n // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||\n // double check webkit in userAgent just in case we are in a worker\n (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nexports.formatters.j = function(v) {\n try {\n return JSON.stringify(v);\n } catch (err) {\n return '[UnexpectedJSONParseError]: ' + err.message;\n }\n};\n\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n var useColors = this.useColors;\n\n args[0] = (useColors ? '%c' : '')\n + this.namespace\n + (useColors ? ' %c' : ' ')\n + args[0]\n + (useColors ? '%c ' : ' ')\n + '+' + exports.humanize(this.diff);\n\n if (!useColors) return;\n\n var c = 'color: ' + this.color;\n args.splice(1, 0, c, 'color: inherit')\n\n // the final \"%c\" is somewhat tricky, because there could be other\n // arguments passed either before or after the %c, so we need to\n // figure out the correct index to insert the CSS into\n var index = 0;\n var lastC = 0;\n args[0].replace(/%[a-zA-Z%]/g, function(match) {\n if ('%%' === match) return;\n index++;\n if ('%c' === match) {\n // we only are interested in the *last* %c\n // (the user may have provided their own)\n lastC = index;\n }\n });\n\n args.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.log()` when available.\n * No-op when `console.log` is not a \"function\".\n *\n * @api public\n */\n\nfunction log() {\n // this hackery is required for IE8/9, where\n // the `console.log` function doesn't have 'apply'\n return 'object' === typeof console\n && console.log\n && Function.prototype.apply.call(console.log, console, arguments);\n}\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\n\nfunction save(namespaces) {\n try {\n if (null == namespaces) {\n exports.storage.removeItem('debug');\n } else {\n exports.storage.debug = namespaces;\n }\n } catch(e) {}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\n\nfunction load() {\n var r;\n try {\n r = exports.storage.debug;\n } catch(e) {}\n\n // If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n if (!r && typeof process !== 'undefined' && 'env' in process) {\n r = process.env.DEBUG;\n }\n\n return r;\n}\n\n/**\n * Enable namespaces listed in `localStorage.debug` initially.\n */\n\nexports.enable(load());\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n try {\n return window.localStorage;\n } catch (e) {}\n}\n","\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n *\n * Expose `debug()` as the module.\n */\n\nexports = module.exports = createDebug.debug = createDebug['default'] = createDebug;\nexports.coerce = coerce;\nexports.disable = disable;\nexports.enable = enable;\nexports.enabled = enabled;\nexports.humanize = require('ms');\n\n/**\n * The currently active debug mode names, and names to skip.\n */\n\nexports.names = [];\nexports.skips = [];\n\n/**\n * Map of special \"%n\" handling functions, for the debug \"format\" argument.\n *\n * Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n */\n\nexports.formatters = {};\n\n/**\n * Previous log timestamp.\n */\n\nvar prevTime;\n\n/**\n * Select a color.\n * @param {String} namespace\n * @return {Number}\n * @api private\n */\n\nfunction selectColor(namespace) {\n var hash = 0, i;\n\n for (i in namespace) {\n hash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n hash |= 0; // Convert to 32bit integer\n }\n\n return exports.colors[Math.abs(hash) % exports.colors.length];\n}\n\n/**\n * Create a debugger with the given `namespace`.\n *\n * @param {String} namespace\n * @return {Function}\n * @api public\n */\n\nfunction createDebug(namespace) {\n\n function debug() {\n // disabled?\n if (!debug.enabled) return;\n\n var self = debug;\n\n // set `diff` timestamp\n var curr = +new Date();\n var ms = curr - (prevTime || curr);\n self.diff = ms;\n self.prev = prevTime;\n self.curr = curr;\n prevTime = curr;\n\n // turn the `arguments` into a proper Array\n var args = new Array(arguments.length);\n for (var i = 0; i < args.length; i++) {\n args[i] = arguments[i];\n }\n\n args[0] = exports.coerce(args[0]);\n\n if ('string' !== typeof args[0]) {\n // anything else let's inspect with %O\n args.unshift('%O');\n }\n\n // apply any `formatters` transformations\n var index = 0;\n args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {\n // if we encounter an escaped % then don't increase the array index\n if (match === '%%') return match;\n index++;\n var formatter = exports.formatters[format];\n if ('function' === typeof formatter) {\n var val = args[index];\n match = formatter.call(self, val);\n\n // now we need to remove `args[index]` since it's inlined in the `format`\n args.splice(index, 1);\n index--;\n }\n return match;\n });\n\n // apply env-specific formatting (colors, etc.)\n exports.formatArgs.call(self, args);\n\n var logFn = debug.log || exports.log || console.log.bind(console);\n logFn.apply(self, args);\n }\n\n debug.namespace = namespace;\n debug.enabled = exports.enabled(namespace);\n debug.useColors = exports.useColors();\n debug.color = selectColor(namespace);\n\n // env-specific initialization logic for debug instances\n if ('function' === typeof exports.init) {\n exports.init(debug);\n }\n\n return debug;\n}\n\n/**\n * Enables a debug mode by namespaces. This can include modes\n * separated by a colon and wildcards.\n *\n * @param {String} namespaces\n * @api public\n */\n\nfunction enable(namespaces) {\n exports.save(namespaces);\n\n exports.names = [];\n exports.skips = [];\n\n var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n var len = split.length;\n\n for (var i = 0; i < len; i++) {\n if (!split[i]) continue; // ignore empty strings\n namespaces = split[i].replace(/\\*/g, '.*?');\n if (namespaces[0] === '-') {\n exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));\n } else {\n exports.names.push(new RegExp('^' + namespaces + '$'));\n }\n }\n}\n\n/**\n * Disable debug output.\n *\n * @api public\n */\n\nfunction disable() {\n exports.enable('');\n}\n\n/**\n * Returns true if the given mode name is enabled, false otherwise.\n *\n * @param {String} name\n * @return {Boolean}\n * @api public\n */\n\nfunction enabled(name) {\n var i, len;\n for (i = 0, len = exports.skips.length; i < len; i++) {\n if (exports.skips[i].test(name)) {\n return false;\n }\n }\n for (i = 0, len = exports.names.length; i < len; i++) {\n if (exports.names[i].test(name)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Coerce `val`.\n *\n * @param {Mixed} val\n * @return {Mixed}\n * @api private\n */\n\nfunction coerce(val) {\n if (val instanceof Error) return val.stack || val.message;\n return val;\n}\n","/**\n * Detect Electron renderer process, which is node, but we should\n * treat as a browser.\n */\n\nif (typeof process !== 'undefined' && process.type === 'renderer') {\n module.exports = require('./browser.js');\n} else {\n module.exports = require('./node.js');\n}\n","/**\n * Module dependencies.\n */\n\nvar tty = require('tty');\nvar util = require('util');\n\n/**\n * This is the Node.js implementation of `debug()`.\n *\n * Expose `debug()` as the module.\n */\n\nexports = module.exports = require('./debug');\nexports.init = init;\nexports.log = log;\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\n\n/**\n * Colors.\n */\n\nexports.colors = [6, 2, 3, 4, 5, 1];\n\n/**\n * Build up the default `inspectOpts` object from the environment variables.\n *\n * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js\n */\n\nexports.inspectOpts = Object.keys(process.env).filter(function (key) {\n return /^debug_/i.test(key);\n}).reduce(function (obj, key) {\n // camel-case\n var prop = key\n .substring(6)\n .toLowerCase()\n .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() });\n\n // coerce string value into JS value\n var val = process.env[key];\n if (/^(yes|on|true|enabled)$/i.test(val)) val = true;\n else if (/^(no|off|false|disabled)$/i.test(val)) val = false;\n else if (val === 'null') val = null;\n else val = Number(val);\n\n obj[prop] = val;\n return obj;\n}, {});\n\n/**\n * The file descriptor to write the `debug()` calls to.\n * Set the `DEBUG_FD` env variable to override with another value. i.e.:\n *\n * $ DEBUG_FD=3 node script.js 3>debug.log\n */\n\nvar fd = parseInt(process.env.DEBUG_FD, 10) || 2;\n\nif (1 !== fd && 2 !== fd) {\n 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)')()\n}\n\nvar stream = 1 === fd ? process.stdout :\n 2 === fd ? process.stderr :\n createWritableStdioStream(fd);\n\n/**\n * Is stdout a TTY? Colored output is enabled when `true`.\n */\n\nfunction useColors() {\n return 'colors' in exports.inspectOpts\n ? Boolean(exports.inspectOpts.colors)\n : tty.isatty(fd);\n}\n\n/**\n * Map %o to `util.inspect()`, all on a single line.\n */\n\nexports.formatters.o = function(v) {\n this.inspectOpts.colors = this.useColors;\n return util.inspect(v, this.inspectOpts)\n .split('\\n').map(function(str) {\n return str.trim()\n }).join(' ');\n};\n\n/**\n * Map %o to `util.inspect()`, allowing multiple lines if needed.\n */\n\nexports.formatters.O = function(v) {\n this.inspectOpts.colors = this.useColors;\n return util.inspect(v, this.inspectOpts);\n};\n\n/**\n * Adds ANSI color escape codes if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n var name = this.namespace;\n var useColors = this.useColors;\n\n if (useColors) {\n var c = this.color;\n var prefix = ' \\u001b[3' + c + ';1m' + name + ' ' + '\\u001b[0m';\n\n args[0] = prefix + args[0].split('\\n').join('\\n' + prefix);\n args.push('\\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\\u001b[0m');\n } else {\n args[0] = new Date().toUTCString()\n + ' ' + name + ' ' + args[0];\n }\n}\n\n/**\n * Invokes `util.format()` with the specified arguments and writes to `stream`.\n */\n\nfunction log() {\n return stream.write(util.format.apply(util, arguments) + '\\n');\n}\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\n\nfunction save(namespaces) {\n if (null == namespaces) {\n // If you set a process.env field to null or undefined, it gets cast to the\n // string 'null' or 'undefined'. Just delete instead.\n delete process.env.DEBUG;\n } else {\n process.env.DEBUG = namespaces;\n }\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\n\nfunction load() {\n return process.env.DEBUG;\n}\n\n/**\n * Copied from `node/src/node.js`.\n *\n * XXX: It's lame that node doesn't expose this API out-of-the-box. It also\n * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.\n */\n\nfunction createWritableStdioStream (fd) {\n var stream;\n var tty_wrap = process.binding('tty_wrap');\n\n // Note stream._type is used for test-module-load-list.js\n\n switch (tty_wrap.guessHandleType(fd)) {\n case 'TTY':\n stream = new tty.WriteStream(fd);\n stream._type = 'tty';\n\n // Hack to have stream not keep the event loop alive.\n // See https://github.com/joyent/node/issues/1726\n if (stream._handle && stream._handle.unref) {\n stream._handle.unref();\n }\n break;\n\n case 'FILE':\n var fs = require('fs');\n stream = new fs.SyncWriteStream(fd, { autoClose: false });\n stream._type = 'fs';\n break;\n\n case 'PIPE':\n case 'TCP':\n var net = require('net');\n stream = new net.Socket({\n fd: fd,\n readable: false,\n writable: true\n });\n\n // FIXME Should probably have an option in net.Socket to create a\n // stream from an existing fd which is writable only. But for now\n // we'll just add this hack and set the `readable` member to false.\n // Test: ./node test/fixtures/echo.js < /etc/passwd\n stream.readable = false;\n stream.read = null;\n stream._type = 'pipe';\n\n // FIXME Hack to have stream not keep the event loop alive.\n // See https://github.com/joyent/node/issues/1726\n if (stream._handle && stream._handle.unref) {\n stream._handle.unref();\n }\n break;\n\n default:\n // Probably an error on in uv_guess_handle()\n throw new Error('Implement me. Unknown stream file type!');\n }\n\n // For supporting legacy API we put the FD here.\n stream.fd = fd;\n\n stream._isStdio = true;\n\n return stream;\n}\n\n/**\n * Init logic for `debug` instances.\n *\n * Create a new `inspectOpts` object in case `useColors` is set\n * differently for a particular `debug` instance.\n */\n\nfunction init (debug) {\n debug.inspectOpts = {};\n\n var keys = Object.keys(exports.inspectOpts);\n for (var i = 0; i < keys.length; i++) {\n debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];\n }\n}\n\n/**\n * Enable namespaces listed in `process.env.DEBUG` initially.\n */\n\nexports.enable(load());\n","/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isNaN(val) === false) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^((?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n if (ms >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (ms >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (ms >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (ms >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n return plural(ms, d, 'day') ||\n plural(ms, h, 'hour') ||\n plural(ms, m, 'minute') ||\n plural(ms, s, 'second') ||\n ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, n, name) {\n if (ms < n) {\n return;\n }\n if (ms < n * 1.5) {\n return Math.floor(ms / n) + ' ' + name;\n }\n return Math.ceil(ms / n) + ' ' + name + 's';\n}\n","const { BrowserWindow, ipcMain } = require('electron');\nconst { exec } = require('child_process');\nconst os = require('os');\nconst platform = os.platform();\nconst path = require('path');\nconst fs = require('fs');\nconst systemTempDir = os.tmpdir();\nconst testcaseOutputDir = path.join(systemTempDir, 'testcases');\nipcMain.handle('run-backend-command', async (event, filename, useLLM) => {\n global.logBackend(`Received pcap: ${filename}`);\n const isDev = !require('electron').app.isPackaged;\n const basePath = isDev\n ? path.join(__dirname, '../..')\n : process.resourcesPath;\n let snitchExePath;\n\n if (platform === 'win32') {\n snitchExePath = path.join(basePath, '\\\\backend\\\\snitch\\\\snitch.exe');\n } else if (platform === 'linux') {\n snitchExePath = path.join(basePath, '/backend/snitch/snitch');\n } else {\n snitchExePath = path.join(basePath, '/backend/snitch/snitch');\n }\n\n const backendCommand = `\"${snitchExePath}\" \"${filename}\" -a -o \"${testcaseOutputDir}\"${useLLM ? '' : ' --nollm'}`;\n\n // Always start with a clean output directory so snitch never hits the\n // interactive overwrite prompt on second (and later) runs.\n if (fs.existsSync(testcaseOutputDir)) {\n fs.rmSync(testcaseOutputDir, { recursive: true, force: true });\n }\n\n global.logBackend('Command to run:', backendCommand);\n\n function sendError(message) {\n const mainWin = BrowserWindow.getAllWindows()[0]; // or track your main window\n if (mainWin) {\n mainWin.webContents.send('backend-error', message);\n }\n }\n\n return new Promise((resolve) => {\n exec(backendCommand, (error, stdout, stderr) => {\n resolve(stdout);\n global.logBackend('Backend output:', stdout);\n global.logBackend('Backend error output:', stderr);\n if (stdout.includes('Ollama')) {\n sendError('Backend LLM generation error!');\n }\n if (error) {\n if (stderr.includes('supported capture file')) {\n sendError('Unsupported file format!');\n } else {\n sendError('Backend execution error! ' + error);\n }\n } else {\n setTimeout(() => {\n const hostsJsonPath = path.join(testcaseOutputDir, 'hosts.json');\n const mainWin = BrowserWindow.getAllWindows()[0];\n if (mainWin && fs.existsSync(hostsJsonPath)) {\n const hostsJsonData = fs.readFileSync(hostsJsonPath, 'utf8');\n mainWin.webContents.send('json-data', hostsJsonData);\n }\n }, 200);\n }\n });\n\n global.logBackend('Backend started, waiting for completion...');\n });\n});\n","module.exports = require(\"child_process\");","module.exports = require(\"electron\");","module.exports = require(\"fs\");","module.exports = require(\"net\");","module.exports = require(\"os\");","module.exports = require(\"path\");","module.exports = require(\"tty\");","module.exports = require(\"url\");","module.exports = require(\"util\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","\nif (typeof __webpack_require__ !== 'undefined') __webpack_require__.ab = __dirname + \"/native_modules/\";","const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron');\nconst fs = require('fs');\nconst path = require('path');\nconst { pathToFileURL } = require('url');\nconst { exec } = require('child_process');\nconst os = require('os');\nconst util = require('util');\nconst platform = os.platform();\nconst testcaseTempDir = path.join(os.tmpdir(), 'testcases');\nconst CONSOLE_INSPECT_DEPTH = 6;\nconst CONSOLE_MAX_ARRAY_LENGTH = 50;\nlet mainWindow;\nlet selectedFilePath;\nlet isBackendLoaded = false;\nlet versionFilePath;\nlet activityLogFilePath;\nlet hasLoggedProgramShutdown = false;\nconst activityLogEntries = [];\nconst pendingActivityLogEntries = [];\nlet isFirstRunAfterInstall = false;\nlet cachedOllamaInstalled = false;\nif (require('electron-squirrel-startup')) {\n app.quit();\n}\n\nipcMain.handle('file-size', async () => {\n try {\n // Get file stats asynchronously\n const fileStats = await fs.promises.stat(selectedFilePath); // Using promises version of stat\n return fileStats.size; // Send back the file size\n } catch (fileError) {\n console.error('Error getting file stats:', fileError);\n return 0; // Return 0 if there's an error\n }\n});\n\n// make sure we have a fresh temp dir\nfs.rmSync(testcaseTempDir, { recursive: true, force: true });\n\nfunction killBackendProcess() {\n console.log('Killing backend proc...');\n if (platform === 'win32') {\n exec('taskkill /IM snitch.exe /T /F', (fileError) => {\n if (fileError) console.error(fileError);\n });\n }\n if (platform === 'linux') {\n exec('pkill -f \"testcases\"', (fileError) => {\n if (fileError) console.error(fileError);\n });\n }\n}\n\nfunction checkOllama() {\n return new Promise((resolve) => {\n exec('ollama --version', (execError) => {\n if (execError) {\n resolve(false); // not installed or not in PATH\n } else {\n resolve(true);\n }\n });\n });\n}\n\nfunction checkNewInstall() {\n if (!versionFilePath) return false;\n try {\n if (!fs.existsSync(versionFilePath)) {\n return true;\n }\n const storedVersion = fs.readFileSync(versionFilePath, 'utf8').trim();\n return storedVersion !== app.getVersion();\n } catch (err) {\n console.error('Error checking install version:', err);\n return true;\n }\n}\n\nfunction createWindow() {\n mainWindow = new BrowserWindow({\n minWidth: 1450,\n minHeight: 750,\n frame: false,\n webPreferences: {\n preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,\n contextIsolation: true,\n nodeIntegration: true,\n },\n });\n mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);\n mainWindow.webContents.on('did-finish-load', () => {\n mainWindow.webContents.setZoomFactor(0.8); // makes everything fit snuggly\n });\n mainWindow.once('close', () => {\n appendActivityLogLine(\n timestampLifecycleMessage(\n `Session closed for PacketSnitch v${app.getVersion()}`,\n ),\n { broadcast: false },\n );\n });\n}\n\nfunction formatConsoleArgs(args) {\n return args\n .map((arg) => {\n if (arg instanceof Error) {\n return arg.stack || arg.message;\n }\n if (typeof arg === 'string') {\n return arg;\n }\n return util.inspect(arg, {\n depth: CONSOLE_INSPECT_DEPTH,\n breakLength: Infinity,\n maxArrayLength: CONSOLE_MAX_ARRAY_LENGTH,\n });\n })\n .join(' ');\n}\n\nfunction appendActivityLogToFile(entry) {\n try {\n fs.appendFileSync(activityLogFilePath, entry + os.EOL, 'utf8');\n } catch (error) {\n console.error('Unable to append activity log:', error);\n }\n}\n\nfunction cacheActivityLogEntry(entry) {\n activityLogEntries.unshift(entry);\n}\n\nfunction broadcastActivityLogEntry(entry) {\n if (mainWindow && !mainWindow.isDestroyed()) {\n mainWindow.webContents.send('activity-log-entry', entry);\n }\n}\n\nfunction normalizeActivityLogEntry(entry) {\n if (typeof entry !== 'string' || entry.trim() === '') return null;\n return entry.trim();\n}\n\nfunction timestampLifecycleMessage(message) {\n return `[${new Date().toISOString()}] [Core] ${message}`;\n}\n\nfunction appendActivityLogLine(entry, options = {}) {\n const { broadcast = true } = options;\n const normalizedEntry = normalizeActivityLogEntry(entry);\n if (!normalizedEntry) return;\n cacheActivityLogEntry(normalizedEntry);\n if (activityLogFilePath) {\n appendActivityLogToFile(normalizedEntry);\n } else {\n pendingActivityLogEntries.push(normalizedEntry);\n }\n if (broadcast) {\n broadcastActivityLogEntry(normalizedEntry);\n }\n}\n\nfunction flushPendingActivityLogEntries() {\n if (!activityLogFilePath || pendingActivityLogEntries.length === 0) return;\n pendingActivityLogEntries.forEach((entry) => {\n appendActivityLogToFile(entry);\n });\n pendingActivityLogEntries.splice(0);\n}\n\nconst originalConsoleLog = console.log.bind(console);\nconsole.log = (...args) => {\n originalConsoleLog(...args);\n const message = formatConsoleArgs(args);\n if (!message) return;\n appendActivityLogLine(\n `[${new Date().toISOString()}] [Console][Main] ${message}`,\n );\n};\n\nglobal.logBackend = (...args) => {\n const message = formatConsoleArgs(args);\n if (!message) return;\n originalConsoleLog(message);\n const timestamp = new Date().toISOString();\n message.split(/\\r?\\n/).forEach((line) => {\n if (line.trim() === '') return;\n appendActivityLogLine(`[${timestamp}] [Console][Backend] ${line}`);\n });\n};\n\napp.whenReady().then(() => {\n versionFilePath = path.join(app.getPath('userData'), 'installed_version.txt');\n activityLogFilePath = path.join(app.getPath('userData'), 'activity-log.txt');\n flushPendingActivityLogEntries();\n appendActivityLogLine(\n `[${new Date().toISOString()}] [Core] Session started for PacketSnitch v${app.getVersion()}`,\n );\n isFirstRunAfterInstall = checkNewInstall();\n checkOllama().then((isInstalled) => {\n cachedOllamaInstalled = isInstalled;\n if (!isInstalled) {\n console.log(\n 'Ollama is not installed. LLM summarisation will be unavailable.',\n );\n }\n createWindow();\n app.on('activate', function () {\n if (BrowserWindow.getAllWindows().length === 0) createWindow();\n });\n console.log('App ready, waiting for file selection...');\n // start the process that listens for the file selection and runs the backend command\n require('./back-comm');\n ipcMain.handle('select-file', async () => {\n const { canceled, filePaths } = await dialog.showOpenDialog({\n properties: ['openFile'],\n });\n if (canceled) return null;\n console.log('Accepted pcapng.. Checking for json existence...');\n isBackendLoaded = true;\n // Remove stale output directory so snitch always starts with a clean slate\n if (fs.existsSync(testcaseTempDir)) {\n fs.rmSync(testcaseTempDir, { recursive: true, force: true });\n }\n console.log('File selected:', filePaths[0]);\n selectedFilePath = filePaths[0];\n return filePaths[0];\n });\n });\n});\n\nipcMain.handle('check-first-run', async () => {\n const isDev = !app.isPackaged;\n const basePath = isDev\n ? path.join(__dirname, '../..')\n : process.resourcesPath;\n const backendExe = platform === 'win32' ? 'snitch.exe' : 'snitch';\n const filesToCheck = [\n {\n name: 'PacketSnitch Backend (' + backendExe + ')',\n path: path.join(basePath, 'backend', backendExe),\n },\n {\n name: 'GeoIP Database (GeoLite2-City.mmdb)',\n path: path.join(basePath, 'backend', 'common', 'GeoLite2-City.mmdb'),\n },\n {\n name: 'MAC Vendors Database (mac-vendors-export.csv)',\n path: path.join(basePath, 'backend', 'common', 'mac-vendors-export.csv'),\n },\n {\n name: 'Services Database (service-names-port-numbers.csv)',\n path: path.join(\n basePath,\n 'backend',\n 'common',\n 'service-names-port-numbers.csv',\n ),\n },\n ];\n const installedFiles = filesToCheck.map((f) => ({\n name: f.name,\n path: f.path,\n exists: fs.existsSync(f.path),\n }));\n return {\n isFirstRun: isFirstRunAfterInstall,\n version: app.getVersion(),\n ollamaInstalled: cachedOllamaInstalled,\n installedFiles,\n };\n});\n\nipcMain.handle('dismiss-first-run', async () => {\n const currentVersion = app.getVersion();\n try {\n fs.writeFileSync(versionFilePath, currentVersion, 'utf8');\n isFirstRunAfterInstall = false;\n return { success: true };\n } catch (err) {\n console.error('Failed to write version file:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('quit-app', () => {\n app.quit();\n});\n\nipcMain.handle('prompt-save-session-on-exit', async () => {\n const response = await dialog.showMessageBox({\n type: 'question',\n buttons: ['Save Session', \"Don't Save\", 'Cancel'],\n defaultId: 0,\n cancelId: 2,\n title: 'Save Session',\n message: 'Do you want to save your PacketSnitch session before exiting?',\n });\n if (response.response === 0) return 'save';\n if (response.response === 1) return 'discard';\n return 'cancel';\n});\n\nipcMain.handle('save-json', async (_event, jsonData) => {\n if (typeof jsonData !== 'string' || jsonData.trim() === '') {\n return { success: false, error: 'No JSON data to save' };\n }\n\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Save PacketSnitch Session',\n defaultPath: path.join(app.getPath('documents'), 'packetsnitch-session.json'),\n filters: [{ name: 'JSON Files', extensions: ['json'] }],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n await fs.promises.writeFile(filePath, jsonData, 'utf8');\n return { success: true };\n } catch (err) {\n console.error('Save error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('save-packet', async (_event, packetData) => {\n if (packetData === null || packetData === undefined) {\n return { success: false, error: 'No packet data to save' };\n }\n const packetJson = JSON.stringify(packetData, null, 2);\n\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Export Packet',\n defaultPath: path.join(app.getPath('documents'), 'packet.json'),\n filters: [{ name: 'JSON Files', extensions: ['json'] }],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n await fs.promises.writeFile(filePath, packetJson, 'utf8');\n return { success: true };\n } catch (err) {\n console.error('Packet export error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('save-payload', async (_event, payloadHex) => {\n if (typeof payloadHex !== 'string') {\n return { success: false, error: 'No payload data to save' };\n }\n const normalizedHex = payloadHex.replace(/\\s+/g, '');\n if (\n normalizedHex.length === 0 ||\n normalizedHex.length % 2 !== 0 ||\n !/^[\\da-fA-F]+$/.test(normalizedHex)\n ) {\n return {\n success: false,\n error: 'Payload must be a non-empty hex string with an even length',\n };\n }\n\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Export Packet Payload',\n defaultPath: path.join(app.getPath('documents'), 'packet-payload.bin'),\n filters: [\n { name: 'Binary Files', extensions: ['bin'] },\n { name: 'All Files', extensions: ['*'] },\n ],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n const payloadBuffer = Buffer.from(normalizedHex, 'hex');\n await fs.promises.writeFile(filePath, payloadBuffer);\n return { success: true };\n } catch (err) {\n console.error('Payload export error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('save-cookie-jar', async (_event, cookieJarText) => {\n if (typeof cookieJarText !== 'string' || cookieJarText.trim() === '') {\n return { success: false, error: 'No cookie jar data to save' };\n }\n\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Save Cookie Jar',\n defaultPath: path.join(app.getPath('documents'), 'cookie_jar.txt'),\n filters: [\n { name: 'Text Files', extensions: ['txt'] },\n { name: 'All Files', extensions: ['*'] },\n ],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n await fs.promises.writeFile(filePath, cookieJarText, 'utf8');\n return { success: true };\n } catch (err) {\n console.error('Cookie jar save error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('save-notes', async (_event, notesText) => {\n if (typeof notesText !== 'string' || notesText.trim() === '') {\n return { success: false, error: 'No notes data to save' };\n }\n\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Save Notes',\n defaultPath: path.join(app.getPath('documents'), 'packetsnitch-notes.txt'),\n filters: [\n { name: 'Text Files', extensions: ['txt'] },\n { name: 'All Files', extensions: ['*'] },\n ],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n await fs.promises.writeFile(filePath, notesText, 'utf8');\n return { success: true };\n } catch (err) {\n console.error('Notes save error:', err);\n return { success: false, error: err.message };\n }\n});\n\n// Map a Content-Type header value to a file extension for HTTP body exports.\nfunction extFromContentType(contentType) {\n const base = (contentType || '').split(';')[0].trim().toLowerCase();\n const map = {\n 'text/html': 'html',\n 'text/plain': 'txt',\n 'text/css': 'css',\n 'text/csv': 'csv',\n 'text/xml': 'xml',\n 'application/javascript': 'js',\n 'application/x-javascript': 'js',\n 'text/javascript': 'js',\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/svg+xml': 'svg',\n 'image/webp': 'webp',\n 'image/bmp': 'bmp',\n 'image/x-icon': 'ico',\n 'image/ico': 'ico',\n 'application/pdf': 'pdf',\n 'application/zip': 'zip',\n 'application/x-zip-compressed': 'zip',\n 'application/gzip': 'gz',\n 'application/x-gzip': 'gz',\n 'application/octet-stream': 'bin',\n };\n return map[base] || 'bin';\n}\n\n// Validate and decode a hex string into a Buffer; returns null on failure.\nfunction hexToBuffer(hex) {\n if (typeof hex !== 'string') return null;\n const normalized = hex.replace(/\\s+/g, '');\n if (normalized.length === 0 || normalized.length % 2 !== 0) return null;\n if (!/^[\\da-fA-F]+$/.test(normalized)) return null;\n return Buffer.from(normalized, 'hex');\n}\n\nipcMain.handle('save-http-body', async (_event, bodyHex, contentType) => {\n const buf = hexToBuffer(bodyHex);\n if (!buf) return { success: false, error: 'Invalid HTTP body data' };\n\n const ext = extFromContentType(contentType);\n const { canceled, filePath } = await dialog.showSaveDialog({\n title: 'Save HTTP Body',\n defaultPath: path.join(app.getPath('documents'), `http-body.${ext}`),\n filters: [\n { name: 'HTTP Body', extensions: [ext] },\n { name: 'All Files', extensions: ['*'] },\n ],\n });\n if (canceled || !filePath) return { success: false, canceled: true };\n\n try {\n await fs.promises.writeFile(filePath, buf);\n return { success: true };\n } catch (err) {\n console.error('HTTP body save error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('preview-http-body', async (_event, bodyHex, contentType) => {\n const buf = hexToBuffer(bodyHex);\n if (!buf) return { success: false, error: 'Invalid HTTP body data' };\n\n const ext = extFromContentType(contentType);\n try {\n // Use a unique temp directory per preview to avoid races and data leaks.\n const tmpDir = await fs.promises.mkdtemp(\n path.join(os.tmpdir(), 'ps-preview-'),\n );\n const tmpFile = path.join(tmpDir, `http-preview.${ext}`);\n await fs.promises.writeFile(tmpFile, buf);\n const fileUrl = pathToFileURL(tmpFile).href;\n await shell.openExternal(fileUrl);\n // Schedule cleanup after a delay to give the browser time to read the file.\n setTimeout(() => {\n fs.promises.rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }, 30000);\n return { success: true };\n } catch (err) {\n console.error('HTTP body preview error:', err);\n return { success: false, error: err.message };\n }\n});\n\nipcMain.handle('open-external-url', async (_event, rawUrl) => {\n if (typeof rawUrl !== 'string' || !rawUrl.trim()) {\n return { success: false, error: 'Invalid URL' };\n }\n try {\n const parsed = new URL(rawUrl.trim());\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return { success: false, error: 'Only HTTP/HTTPS URLs are supported' };\n }\n await shell.openExternal(parsed.href);\n return { success: true };\n } catch (err) {\n return { success: false, error: err?.message || 'Invalid URL' };\n }\n});\n\nipcMain.handle('append-activity-log', async (_event, entry) => {\n const normalizedEntry = normalizeActivityLogEntry(entry);\n if (!normalizedEntry) {\n return { success: false, error: 'Invalid log entry' };\n }\n // Renderer entries are already shown locally, so skip broadcasting them back.\n appendActivityLogLine(normalizedEntry, { broadcast: false });\n return { success: true, path: activityLogFilePath };\n});\n\nipcMain.handle('get-activity-log-path', async () => {\n return activityLogFilePath;\n});\n\nipcMain.handle('get-activity-log-entries', async () => {\n return [...activityLogEntries];\n});\n\napp.on('before-quit', () => {\n if (!hasLoggedProgramShutdown) {\n appendActivityLogLine(\n timestampLifecycleMessage(\n `Program shutdown requested for PacketSnitch v${app.getVersion()}`,\n ),\n { broadcast: false },\n );\n hasLoggedProgramShutdown = true;\n }\n // make sure the backend snitch process dies!\n if (isBackendLoaded) {\n killBackendProcess();\n }\n});\n"],"names":["path","spawn","debug","app","run","args","done","updateExe","resolve","dirname","process","execPath","detached","on","module","exports","platform","cmd","argv","target","basename","quit","check","load","r","storage","e","env","DEBUG","log","console","Function","prototype","apply","call","arguments","formatArgs","useColors","this","namespace","humanize","diff","c","color","splice","index","lastC","replace","match","save","namespaces","removeItem","window","type","document","documentElement","style","WebkitAppearance","firebug","exception","table","navigator","userAgent","toLowerCase","parseInt","RegExp","$1","chrome","local","localStorage","localstorage","colors","formatters","j","v","JSON","stringify","err","message","enable","prevTime","createDebug","enabled","self","curr","Date","ms","prev","Array","length","i","coerce","unshift","format","formatter","val","bind","hash","charCodeAt","Math","abs","selectColor","init","Error","stack","disable","names","skips","split","len","push","substr","name","test","tty","util","inspectOpts","keys","Object","stream","write","prefix","join","toUTCString","Boolean","isatty","fd","filter","key","reduce","obj","prop","substring","_","k","toUpperCase","Number","DEBUG_FD","deprecate","stdout","stderr","binding","guessHandleType","WriteStream","_type","_handle","unref","SyncWriteStream","autoClose","Socket","readable","writable","read","_isStdio","createWritableStdioStream","o","inspect","map","str","trim","O","s","m","h","d","plural","n","floor","ceil","options","String","exec","parseFloat","parse","isNaN","long","round","fmtShort","BrowserWindow","ipcMain","os","fs","systemTempDir","tmpdir","testcaseOutputDir","handle","async","event","filename","useLLM","global","logBackend","basePath","isPackaged","resourcesPath","__dirname","snitchExePath","backendCommand","sendError","mainWin","getAllWindows","webContents","send","existsSync","rmSync","recursive","force","Promise","error","includes","setTimeout","hostsJsonPath","hostsJsonData","readFileSync","require","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","ab","dialog","shell","pathToFileURL","testcaseTempDir","mainWindow","selectedFilePath","versionFilePath","activityLogFilePath","isBackendLoaded","hasLoggedProgramShutdown","activityLogEntries","pendingActivityLogEntries","isFirstRunAfterInstall","cachedOllamaInstalled","createWindow","minWidth","minHeight","frame","webPreferences","preload","contextIsolation","nodeIntegration","loadURL","setZoomFactor","once","appendActivityLogLine","timestampLifecycleMessage","getVersion","broadcast","formatConsoleArgs","arg","depth","breakLength","Infinity","maxArrayLength","appendActivityLogToFile","entry","appendFileSync","EOL","normalizeActivityLogEntry","toISOString","normalizedEntry","cacheActivityLogEntry","isDestroyed","broadcastActivityLogEntry","promises","stat","size","fileError","originalConsoleLog","extFromContentType","contentType","hexToBuffer","hex","normalized","Buffer","from","timestamp","forEach","line","whenReady","then","getPath","checkNewInstall","execError","isInstalled","canceled","filePaths","showOpenDialog","properties","backendExe","installedFiles","f","exists","isFirstRun","version","ollamaInstalled","currentVersion","writeFileSync","success","response","showMessageBox","buttons","defaultId","cancelId","title","_event","jsonData","filePath","showSaveDialog","defaultPath","filters","extensions","writeFile","packetData","packetJson","payloadHex","normalizedHex","payloadBuffer","cookieJarText","notesText","bodyHex","buf","ext","tmpDir","mkdtemp","tmpFile","fileUrl","href","openExternal","rm","catch","rawUrl","parsed","URL","protocol"],"sourceRoot":""}
@@ -0,0 +1,3 @@
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>PacketSnitch</title><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link rel="stylesheet" href="assets/css/style.css"/><script defer="defer" src="../main_window/index.js"></script></head><body><div class="container_box"><div class="top_bar"><div class="tagline"><img class="tagline" id="psbyline" src="../assets/images/packet-snitch-tag.webp"/></div><button id="close-btn" aria-label="Quit application" title="Quit">&#10005;</button></div><div class="entry_bar"><div class="logo-cont"><img src="../assets/images/logo.webp"/></div><div id="filters-container"><input id="host_filter" placeholder="0.0.0.0" disabled="disabled"/> <label style="color: white">Filter</label><div id="filterStr-wrap"><div id="filterStr-highlight" aria-hidden="true"></div><input id="filterStr" disabled="disabled" placeholder="wire.len: >100 && tcp.proto: https || dns.qname: example.com"/> <button id="filterStr-clear" type="button" disabled="disabled" aria-label="Clear filter" title="Clear filter">Clear</button></div><div id="filter-history"><select id="filter-history-select" disabled="disabled" aria-label="Previously used filters"><option value="" selected="selected">Previous queries</option></select></div></div></div><div class="menu_bar" id="dropdown" style="display: none"></div><div class="menu_bar" id="tab-btns"><input type="button" id="summary-btn" value="Analysis" class="custom-btns"/> <input type="button" id="data-btn" value="Host Data" class="custom-btns"/> <input type="button" id="data-tools-btn" value="Conv" title="Data Conversion" class="custom-btns"/> <input type="button" id="crypt-btn" value="Crypt" title="Encryption workspace" class="custom-btns"/> <input type="button" id="keystore-btn" value="Keystore" title="Persistent local keystore" class="custom-btns"/> <input type="button" id="stats-btn" value="Stats" class="custom-btns"/> <input type="button" id="list-btn" value="List" class="custom-btns"/> <input type="button" id="notes-btn" value="Notes" class="custom-btns"/> <input type="button" id="log-btn" value="Log" class="custom-btns"/><div id="rotate-btns" class="menu_bar"><input type="button" id="prev-btn" value="Prev" class="custom-btns" style="display: none"/> <input type="button" id="next-btn" value="Next" class="custom-btns" style="display: none"/></div></div><div class="content_area"><div class="sidebar"><form method="post" enctype="multipart/form-data" id="jsonFile" name="jsonFile"><input type="file" id="json-upload" name="json-up" hidden/> <label id="json-lab" for="json-upload" class="menu-btns">Load Session</label></form><br/><input type="button" id="pcap-filename" name="pcap-up" hidden/> <label id="pcap-lab" for="pcap-filename" class="menu-btns">Choose PCAP</label><div id="llm-toggle"><label class="menu-btns"><input type="checkbox" id="use-llm" checked="checked"/> Enable LLM</label></div><div id="leftside"><label for="target_hosts" class="menu-btns left">Target Host</label> <select id="target_hosts" hidden class="menu-btns left"></select><br/><input type="button" id="setBookmark" value="Bookmark" class="menu-btns left"/> <select id="selectBookmark" class="menu-btns left"><option class="menu-btns left" value="" disabled="disabled" selected="selected">Select a bookmark</option></select> <input type="button" id="save-json-btn" value="Save Session" class="menu-btns left"/><div id="file-info"><div id="pcap-size">PCAP size: 0</div><div id="load-time">Load time:</div><div id="total-packets">Total Packets: 0</div><div id="filter-returned">Filtered Packets: 0</div><div id="timestamp"></div></div></div></div><div id="main" class="main_panel"><div id="loading-container"><h2>Loading packets...</h2><br/><img width="25%" height="25%" id="loading" src="../assets/images/loading.gif"/></div><div id="error-container"><h2>Error!</h2><br/><p id="error-message"></p></div><div id="summary_box"><div id="summary_content">Load a file to get started!</div></div><div id="stats_box"><div id="stats_content"></div></div><div id="data_tools_box"><div class="crypt-workspace-header">Conv Workspace</div><div class="crypt-subtab-row"><button id="conv-subtab-conversions" class="crypt-subtab-btn active">Conversions</button> <button id="conv-subtab-hashes" class="crypt-subtab-btn">Hashes</button> <button id="conv-subtab-decodes" class="crypt-subtab-btn">Decodes</button></div><div id="conv-conversions-panel" class="crypt-subtab-panel"><div class="data-tools-grid"><div class="data-tools-section"><div class="data-tools-title">Input</div><label for="data-tools-format">Input format</label> <select id="data-tools-format"><option value="base64">Base64</option><option value="binary">Binary</option><option value="hex" selected="selected">Hex</option><option value="ascii">ASCII / UTF-8</option><option value="decimal">Decimal bytes</option></select> <textarea id="data-tools-input" placeholder="Paste base64, binary, hex, ascii, or decimal byte values here..."></textarea><div class="data-tools-actions"><button id="data-tools-convert-btn">Convert</button> <button id="data-tools-clear-btn">Clear</button></div><div id="data-tools-error" role="alert"></div></div><div class="data-tools-section"><div class="data-tools-title">Converted Output</div><div class="data-tools-output-label">Hex</div><textarea id="data-tools-hex-output" readonly="readonly"></textarea><div class="data-tools-output-label">Binary</div><textarea id="data-tools-binary-output" readonly="readonly"></textarea><div class="data-tools-output-label">Decimal bytes</div><textarea id="data-tools-decimal-output" readonly="readonly"></textarea><div class="data-tools-output-label">Decimal integer</div><textarea id="data-tools-decimal-integer-output" readonly="readonly"></textarea><div class="data-tools-output-label">ASCII</div><textarea id="data-tools-ascii-output" readonly="readonly"></textarea><div class="data-tools-output-label">Base64</div><textarea id="data-tools-base64-output" readonly="readonly"></textarea></div><div class="data-tools-section"><div class="data-tools-title">Data Insights</div><div id="data-tools-byte-length" class="data-tools-kv">Byte Length: 0</div><div id="data-tools-mime-type" class="data-tools-kv">MIME Type: Unknown</div><div id="data-tools-entropy" class="data-tools-kv">Shannon Entropy: 0.00 (Low)</div></div></div></div><div id="conv-hashes-panel" class="crypt-subtab-panel" hidden><div class="data-tools-section data-tools-hashes-section"><div class="data-tools-title">Hashes</div><div class="data-tools-hashes-grid"><div class="data-tools-output-label">Hashed Input</div><textarea id="data-tools-hash-input-reading" class="data-tools-hash-input-reading" placeholder="Type text here to hash..."></textarea><div class="data-tools-output-label">MD5</div><input id="data-tools-md5-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA-1</div><input id="data-tools-sha1-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA-256</div><input id="data-tools-sha256-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA-384</div><input id="data-tools-sha384-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA-512</div><input id="data-tools-sha512-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA3-256</div><input id="data-tools-sha3-256-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">SHA3-512</div><input id="data-tools-sha3-512-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">RIPEMD-160</div><input id="data-tools-ripemd160-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/><div class="data-tools-output-label">Whirlpool</div><input id="data-tools-whirlpool-output" class="data-tools-hash-output" readonly="readonly" placeholder="—"/></div></div></div><div id="conv-decodes-panel" class="crypt-subtab-panel" hidden><div class="data-tools-section data-tools-proto-section"><div class="data-tools-title">Protocol Decoder</div><label for="data-tools-proto-select">Protocol</label> <select id="data-tools-proto-select"><option value="auto" selected="selected">Auto-detect</option><option value="http">HTTP</option><option value="telnet">Telnet</option><option value="ssh">SSH / OpenSSH</option><option value="pop3">POP3</option><option value="imap">IMAP</option><option value="smtp">SMTP</option></select><div id="data-tools-proto-output"></div></div></div></div><div id="crypt_box"><div class="crypt-workspace-header">Crypt Workspace</div><div class="crypt-subtab-row"><button id="crypt-subtab-ssl" class="crypt-subtab-btn active">SSL</button> <button id="crypt-subtab-pgp" class="crypt-subtab-btn">PGP</button> <button id="crypt-subtab-openssh" class="crypt-subtab-btn">OpenSSH</button></div><div id="crypt-ssl-panel" class="crypt-subtab-panel"><div class="crypt-grid"><div class="crypt-section"><div class="crypt-section-title">Encountered SSL/TLS</div><select id="crypt-encountered-list" size="10"></select><div class="crypt-actions-row"><button id="crypt-refresh-btn">Refresh</button> <button id="crypt-apply-filter-btn">Filter packets</button> <button id="crypt-load-encountered-cert-btn">Load cert text</button></div><div id="crypt-encountered-details"></div></div><div class="crypt-section"><div class="crypt-section-title">Certificate Loader</div><div class="crypt-actions-row"><button id="crypt-load-cert-file-btn">Load certificate file</button> <button id="crypt-use-cert-input-btn">Use pasted certificate</button> <button id="crypt-clear-cert-btn">Clear</button></div><input type="file" id="crypt-cert-file-input" accept=".pem,.crt,.cer,.der,.txt" hidden/> <textarea id="crypt-cert-input" placeholder="Paste PEM certificate text here..."></textarea><pre id="crypt-cert-preview">No certificate loaded.</pre></div><div class="crypt-section"><div class="crypt-section-title">Private Key Loader</div><div class="crypt-actions-row"><button id="crypt-load-key-file-btn">Load private key file</button> <button id="crypt-use-key-input-btn">Use pasted key</button> <button id="crypt-clear-key-btn">Clear</button></div><input type="file" id="crypt-key-file-input" accept=".key,.pem,.txt" hidden/> <textarea id="crypt-key-input" placeholder="Paste PEM private key text here..."></textarea><pre id="crypt-key-preview">No private key loaded.</pre></div><div class="crypt-section"><div class="crypt-section-title">TLS/SSL Decrypt</div><div class="crypt-actions-row"><button id="crypt-decrypt-entry-btn">Decrypt selected</button> <button id="crypt-send-decrypted-conv-btn" disabled="disabled">Send to Conv</button> <button id="crypt-clear-decrypted-btn">Clear</button></div><pre id="crypt-decrypt-preview">
2
+ No decrypted TLS/SSL output yet.</pre></div></div></div><div id="crypt-pgp-panel" class="crypt-subtab-panel" hidden><div class="crypt-placeholder">PGP workspace reserved for future import/decrypt tooling.</div></div><div id="crypt-openssh-panel" class="crypt-subtab-panel" hidden><div class="crypt-placeholder">OpenSSH workspace reserved for future key/session tooling.</div></div></div><div id="keystore_box"><div class="keystore-workspace-header">Local Keystore</div><div class="keystore-grid"><div class="crypt-section"><div class="crypt-section-title">Create / Update Entry</div><div class="keystore-mode-row"><label for="crypt-keystore-mode">Keychain:</label> <select id="crypt-keystore-mode"><option value="session">Session auto keychain</option><option value="persistent">Persistent keychain</option></select></div><div id="crypt-keystore-unlock-status" role="status" aria-live="polite">Persistent keychain is unlocked for this app session.</div><input id="crypt-keystore-label" placeholder="Entry label (optional)"/> <textarea id="crypt-credential-input" placeholder="Paste credentials/secrets/notes to store locally..."></textarea><div class="crypt-actions-row"><button id="crypt-save-cert-keystore-btn">Save cert</button> <button id="crypt-save-key-keystore-btn">Save key</button> <button id="crypt-save-secret-keystore-btn">Save secret</button></div></div><div class="crypt-section"><div class="crypt-section-title">Saved Entries</div><select id="crypt-keystore-list" size="10"></select><div class="crypt-actions-row"><button id="crypt-load-keystore-entry-btn">Load selected</button> <button id="crypt-open-link-btn">Open link</button> <button id="crypt-send-to-persistent-btn">Send to persistent</button> <button id="crypt-delete-keystore-entry-btn">Delete selected</button></div><pre id="crypt-keystore-details">
3
+ No keystore entries saved.</pre></div></div></div><div id="save-session-dialog" hidden><div class="crypt-keystore-unlock-content"><div class="crypt-section-title">Save Session</div><div id="save-session-dialog-description">Do you want to save your PacketSnitch session?</div><div class="crypt-actions-row"><button id="save-session-save-btn">Save Session</button> <button id="save-session-discard-btn">Don't Save</button> <button id="save-session-cancel-btn">Cancel</button></div></div></div><div id="crypt-keystore-unlock-dialog" hidden><div class="crypt-keystore-unlock-content"><div class="crypt-section-title" id="crypt-keystore-unlock-title">Unlock Keychain</div><div id="crypt-keystore-unlock-description">Enter password to unlock the persistent keychain.</div><input id="crypt-keystore-unlock-password" type="password" placeholder="Enter keychain password"/> <input id="crypt-keystore-unlock-password-confirm" type="password" placeholder="Confirm keychain password" hidden/><div class="crypt-actions-row"><button id="crypt-keystore-unlock-confirm-btn">Unlock</button> <button id="crypt-keystore-unlock-cancel-btn">Cancel</button></div></div></div><div id="crypt-keystore-manual-uri-dialog" hidden><div class="crypt-keystore-unlock-content"><div class="crypt-section-title">Add URI/URL to Keystore</div><div id="crypt-keystore-manual-uri-description">Enter URI/URL to add to the session keychain.</div><input id="crypt-keystore-manual-uri-input" placeholder="https://example.com/path"/><div class="crypt-actions-row"><button id="crypt-keystore-manual-uri-confirm-btn">Save</button> <button id="crypt-keystore-manual-uri-cancel-btn">Cancel</button></div></div></div><div id="list_box"><div id="list_search_bar"><input id="list-search" placeholder="Filter list by host, IP, port, or protocol..."/> <label id="list-group-streams-wrap"><input id="list-group-streams" type="checkbox"/> Group by stream</label></div><div id="list_content"></div></div><div id="notes_box"><div class="notes-header">Selected Note</div><div class="notes-editor-wrap"><textarea id="notes-editor" placeholder="Select a note from the right panel..."></textarea></div></div><div id="packetInfoPane"><div id="timestamp"></div><div id="welcome">Processing packets...</div><div id="ip2ip"></div><div id="moredata"></div><div id="protoInfo"><div id="protoInfoHead" class="PHead">Network Information</div><div id="protoInfoProto" class="infop"><div id="protoInfoSrc" class="infop"></div><div id="protoInfoDest" class="infop"></div></div></div><div id="data-types"><div id="dataTypesHead" class="PHead">Data Type List</div><div id="dataTypesPane"><div id="type-head" class="infop"><div id="mime-type"></div><div id="charset"></div><div id="encoding"></div><div id="language"></div></div><ul id="types-list"></ul></div></div><div id="active-recon"><div id="protcols-head" class="PHead">Protcols Used</div><div id="protocols" class="active">Unavilable</div><div id="comp-head" class="PHead">Compression Information</div><div id="comp" class="active">Unavailable for datatype</div><div id="crypt-head" class="PHead">Encryption Details</div><div id="crypt" class="active">Unavailable for datatype</div><div id="website-head" class="PHead">Website Title</div><div id="website" class="active">Unavailable</div><div id="dns-head" class="PHead">DNS</div><div id="dns" class="active">Unavailable</div></div></div><div id="packetPayloadPane" class="main_panel"><div id="payloadascii"><div id="asciiText"></div><div id="asciiOffset"></div></div><div id="hexg" class="hexGrid"></div></div></div><div class="sidebar" id="sidedata"><div id="rightside"><div id="rightside-data"><div class="sidebar-header">Datagram Frame</div><div id="sidedatatable" class="sidetable"></div><div class="sidebar-header">Location</div><div id="locationtable" class="sidetable"></div><div id="sideloctable" class="sidetable"></div><div class="sidebar-header">Payload Entropy</div><div id="entropybox"></div></div><div id="rightside-notes" hidden><div class="sidebar-header">Notes</div><select id="notes-select" size="10"></select><div class="notes-controls-row notes-sidebar-actions"><label for="notes-new-color">Color</label> <input type="color" id="notes-new-color" value="#4caf50"/></div><textarea id="notes-new-input" placeholder="Write a new note..."></textarea><div class="notes-controls-row notes-sidebar-actions"><button id="notes-add-btn">Add note</button> <button id="notes-remove-btn">Remove selected</button></div><div class="notes-controls-row notes-sidebar-actions"><button id="notes-save-btn">Save notes file</button></div></div></div></div></div><div class="footer"><div id="status" class="footer">Status: Ready</div><div id="copyright" class="footer">oxasploits, llc (&copy; 2026)</div></div></div><div id="activity-log-panel"><div id="activity-log-header"><span>Activity Log</span> <button id="close-log-btn" aria-label="Close log">×</button></div><div id="activity-log-path"></div><div id="activity-log-entries"></div><div id="activity-log-search-bar"><input id="activity-log-search" placeholder="Search log entries..."/></div></div><div id="convert-context-menu" role="menu" aria-label="Context menu" hidden><div id="ctx-copy-submenu" class="ctx-submenu"><button id="ctx-copy-branch" class="ctx-branch" type="button">Copy...</button><div class="ctx-submenu-panel"><button id="ctx-copy" role="menuitem">Copy</button> <button id="convert-context-copy-hex" type="button">Copy Hex</button> <button id="convert-context-copy-ascii" type="button">Copy ASCII</button> <button id="convert-context-copy-raw" type="button">Copy Raw payload</button> <button id="ctx-copy-cookie-jar" role="menuitem">Copy Cookie Jar</button></div></div><button id="ctx-paste" role="menuitem">Paste</button><hr id="convert-context-divider" class="ctx-divider"/><div id="ctx-convert-submenu" class="ctx-submenu"><button id="ctx-convert-branch" class="ctx-branch" type="button">Convert to...</button><div class="ctx-submenu-panel"><button id="convert-context-hex" type="button">Load as Hex</button> <button id="convert-context-binary" type="button">Load as Binary</button> <button id="convert-context-base64" type="button">Load as Base64</button> <button id="convert-context-decimal" type="button">Load as Decimal bytes</button> <button id="convert-context-ascii" type="button">Load as ASCII / UTF-8</button> <button id="convert-context-load-cursor-ascii" type="button">Load Cursor ASCII into Conv tab</button> <button id="convert-context-load-payload" type="button">Load Raw Payload into Conv tab</button></div></div><div id="ctx-notes-submenu" class="ctx-submenu"><button id="ctx-notes-branch" class="ctx-branch" type="button">Send to Notes...</button><div class="ctx-submenu-panel"><button id="ctx-notes-send-data" type="button">Send selected/context data</button> <button id="ctx-notes-send-conv-output" type="button">Send Conv converted output</button> <button id="ctx-notes-send-conv-hashes" type="button">Send Conv hashes</button></div></div><div id="ctx-filter-submenu" class="ctx-submenu"><button id="ctx-filter-branch" class="ctx-branch" type="button">Add to filter...</button><div class="ctx-submenu-panel"><div id="ctx-filter-and-submenu" class="ctx-submenu"><button id="ctx-filter-and-branch" class="ctx-branch" type="button">Add with &&...</button><div class="ctx-submenu-panel"><button id="ctx-filter-ip" type="button">Add IP to Filter</button> <button id="ctx-filter-port" type="button">Add Port to Filter</button> <button id="ctx-filter-mac" type="button">Add MAC to Filter</button> <button id="ctx-filter-protocol" type="button">Add Protocol to Filter</button> <button id="ctx-filter-mime" type="button">Add MIME Type to Filter</button></div></div><div id="ctx-filter-or-submenu" class="ctx-submenu"><button id="ctx-filter-or-branch" class="ctx-branch" type="button">Add with ||...</button><div class="ctx-submenu-panel"><button id="ctx-filter-or-ip" type="button">Add IP to Filter</button> <button id="ctx-filter-or-port" type="button">Add Port to Filter</button> <button id="ctx-filter-or-mac" type="button">Add MAC to Filter</button> <button id="ctx-filter-or-protocol" type="button">Add Protocol to Filter</button> <button id="ctx-filter-or-mime" type="button">Add MIME Type to Filter</button></div></div><div id="ctx-filter-not-submenu" class="ctx-submenu"><button id="ctx-filter-not-branch" class="ctx-branch" type="button">is not...</button><div class="ctx-submenu-panel"><button id="ctx-filter-not-ip" type="button">Add IP to Filter</button> <button id="ctx-filter-not-port" type="button">Add Port to Filter</button> <button id="ctx-filter-not-mac" type="button">Add MAC to Filter</button> <button id="ctx-filter-not-protocol" type="button">Add Protocol to Filter</button> <button id="ctx-filter-not-mime" type="button">Add MIME Type to Filter</button></div></div><div id="ctx-filter-parentheses-submenu" class="ctx-submenu"><button id="ctx-filter-parentheses-branch" class="ctx-branch" type="button">Parentheses...</button><div class="ctx-submenu-panel"><button id="ctx-filter-paren-open" type="button">Append (</button> <button id="ctx-filter-paren-close" type="button">Append )</button> <button id="ctx-filter-paren-wrap" type="button">Wrap current query with (...)</button></div></div><hr class="ctx-divider"/><div id="ctx-filter-clear-submenu" class="ctx-submenu"><button id="ctx-filter-clear-branch" class="ctx-branch" type="button">Clear and...</button><div class="ctx-submenu-panel"><button id="ctx-filter-clear-ip" type="button">Add IP to Filter</button> <button id="ctx-filter-clear-port" type="button">Add Port to Filter</button> <button id="ctx-filter-clear-mac" type="button">Add MAC to Filter</button> <button id="ctx-filter-clear-protocol" type="button">Add Protocol to Filter</button> <button id="ctx-filter-clear-mime" type="button">Add MIME Type to Filter</button></div></div></div></div><div id="ctx-keystore-submenu" class="ctx-submenu"><button id="ctx-keystore-branch" class="ctx-branch" type="button">Add to Keystore...</button><div class="ctx-submenu-panel"><div id="ctx-keystore-password-submenu" class="ctx-submenu"><button id="ctx-keystore-password-branch" class="ctx-branch" type="button">As Password</button><div class="ctx-submenu-panel"><button id="ctx-keystore-password-session" type="button">Session keychain</button> <button id="ctx-keystore-password-persistent" type="button">Persistent keychain</button></div></div><div id="ctx-keystore-key-submenu" class="ctx-submenu"><button id="ctx-keystore-key-branch" class="ctx-branch" type="button">As Private Key</button><div class="ctx-submenu-panel"><button id="ctx-keystore-key-session" type="button">Session keychain</button> <button id="ctx-keystore-key-persistent" type="button">Persistent keychain</button></div></div><div id="ctx-keystore-cert-submenu" class="ctx-submenu"><button id="ctx-keystore-cert-branch" class="ctx-branch" type="button">As Certificate</button><div class="ctx-submenu-panel"><button id="ctx-keystore-cert-session" type="button">Session keychain</button> <button id="ctx-keystore-cert-persistent" type="button">Persistent keychain</button></div></div><div id="ctx-keystore-cookie-submenu" class="ctx-submenu"><button id="ctx-keystore-cookie-branch" class="ctx-branch" type="button">As Session Cookie</button><div class="ctx-submenu-panel"><button id="ctx-keystore-cookie-session" type="button">Session keychain</button> <button id="ctx-keystore-cookie-persistent" type="button">Persistent keychain</button></div></div><div id="ctx-keystore-uri-submenu" class="ctx-submenu"><button id="ctx-keystore-uri-branch" class="ctx-branch" type="button">As URI / URL (Manual)</button><div class="ctx-submenu-panel"><button id="ctx-keystore-uri-session" type="button">Session keychain</button> <button id="ctx-keystore-uri-persistent" type="button">Persistent keychain</button></div></div></div></div><hr id="convert-context-save-divider" class="ctx-divider"/><div id="ctx-export-submenu" class="ctx-submenu"><button id="ctx-export-branch" class="ctx-branch" type="button">Export...</button><div class="ctx-submenu-panel"><button id="ctx-save-json" role="menuitem">Save Session</button> <button id="ctx-export-packet" role="menuitem">Export Packet</button> <button id="ctx-export-payload" role="menuitem">Export Payload</button> <button id="ctx-save-cookie-jar" role="menuitem">Save to cookie_jar.txt</button></div></div><div id="ctx-http-file-submenu" class="ctx-submenu"><button id="ctx-http-file-branch" class="ctx-branch" type="button">HTTP File...</button><div class="ctx-submenu-panel"><button id="ctx-http-file-save" type="button">Save body to file</button> <button id="ctx-http-file-load" type="button">Load body into Conv tab</button> <button id="ctx-http-file-preview" type="button">Preview in browser</button></div></div></div><div id="install-screen"><div id="install-screen-inner"><div id="install-title">PacketSnitch Installation Complete</div><div id="install-version"></div><hr class="install-divider"/><div id="install-files-heading">Installed Files</div><ul id="install-file-list"></ul><hr class="install-divider"/><div id="install-ollama-status"></div><button id="install-continue-btn">Continue</button></div></div></body></html>