Skip to content

What NetDash Toolkit is

NetDash Toolkit is a network engineering dashboard: 48 tools covering subnet math, VLSM planning, VLAN and ACL config generation, DNS and TLS inspection, and a set of developer utilities. It ships twice from one codebase, as a static website and as a desktop app.

There is no backend. next.config.mjs sets output: "export", so next build emits a directory of static files and nothing runs on a server. That single decision drives most of what follows: there is no API to send your subnet to, no request log to leak, and no server-side rendering to reason about.

Property Value Why it matters
Framework Next.js 15 App Router, output: "export" no server, so no server-side data handling
Routing trailingSlash: true every URL is a directory with an index.html, which is what a dumb static server needs
Tools 48, enumerated in lib/tool-registry.ts one list drives the sidebar, search, routes, and these docs
Offline tools 36 of 48 the majority of the app works with no network at all
Desktop shell Electron 43, serving out/ over loopback HTTP the same static export, plus capabilities a browser lacks
Licence MIT fork it, self-host it, ship it

The tool count and the offline count in that table are not hand-maintained. They are read out of the registry when these docs are built, and a unit test in tests/unit/tool-registry.test.ts asserts that each tool’s declared runtime.offline matches whether the component actually performs network I/O.

Every tool is one entry in lib/tool-registry.ts carrying its slug, label, description, category, feature list, search keywords, and a lazy component loader. The route app/(shell)/tools/[slug]/page.tsx enumerates those slugs in generateStaticParams, with dynamicParams = false, so an unknown slug fails the build instead of rendering an empty page.

Entries that leave the device also carry a runtime block:

runtime: {
offline: false,
thirdParty: ["cloudflare-dns.com", "dns.google"],
desktopOnly: ["direct DNS queries"],
}

thirdParty names the hosts that receive your input. desktopOnly names capabilities that exist only in the Electron build. The comment above the interface is blunt about why it exists: the dashboard used to claim “100% offline ready” while a dozen tools did network I/O, and nothing in the registry could contradict it.

  • Not a monitoring system. Nothing polls, nothing alerts, nothing runs while the tab is closed.
  • Not a substitute for nmap, dig, or mtr. The desktop build shells out to your system’s ping, traceroute and arp and parses their text output; it does not reimplement them.
  • Not authenticated by default. Sign-in exists only to sync saved projects, and every tool works without it.
  • Not notarized on macOS. Builds are ad-hoc signed because notarization needs a paid Apple Developer ID. Releases and verification covers what to run instead of trusting Gatekeeper.
  • A CSP without 'unsafe-inline'. Both builds now send a Content-Security-Policy, but script-src and style-src both carry 'unsafe-inline', because a static export has no per-response anything to bind a nonce to and its inline hydration payload differs page by page, so closing it means a per-path hash policy rather than one extra token. Building the desktop app works the arithmetic, including the inline-script counts measured from out/. Safe to defer because there is no backend and the tree’s one dangerouslySetInnerHTML writes build-time constants. script-src also carries 'wasm-unsafe-eval', which the documentation search genuinely needs and which permits WebAssembly compilation only, not eval.
  • A connect-src allowlist. connect-src is 'self' https: http: on purpose, and the comment in electron/csp.ts says why: the network tester, port probe, ping fallback and TLS trust probe all fetch a host you type, so an allowlist would have to contain the whole internet or break the tools. The mitigation is that the hosts the app itself contacts are enumerated and tested rather than restricted at the CSP layer.
  • Auto-update in the desktop app. electron-builder.json sets "publish": null and there is no electron-updater anywhere in the tree, so updates are a manual download or a brew upgrade. Deferring it is defensible for a free project with signed release artifacts, since the verification path in the docs does not depend on an update channel being trustworthy.
  • A sandboxed renderer. webPreferences sets contextIsolation: true and nodeIntegration: false but leaves sandbox: false. The navigation allowlist and the single-entry permission allowlist are what currently keep the preload bridge away from remote origins.