From 738b05822497dd19fae72381042777d9c8fd2c9e Mon Sep 17 00:00:00 2001 From: Keith Casko Date: Thu, 23 Jul 2026 06:33:45 -0400 Subject: [PATCH] Prepare ByteGeist Toolbox v1.0.0 release --- LICENSE | 21 ++++ README.md | 245 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 7 ++ docs/DEPLOYMENT.md | 61 ++++++++++ docs/PORTFOLIO.md | 79 ++++++++++++ docs/RELEASE_CHECKLIST.md | 18 +++ docs/screenshots/.gitkeep | 1 + package-lock.json | 2 +- package.json | 2 +- public/app.js | 15 ++- public/index.html | 7 +- 11 files changed, 450 insertions(+), 8 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/DEPLOYMENT.md create mode 100644 docs/PORTFOLIO.md create mode 100644 docs/RELEASE_CHECKLIST.md create mode 100644 docs/screenshots/.gitkeep diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7de5530 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Keith Casko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c0d7de --- /dev/null +++ b/README.md @@ -0,0 +1,245 @@ +# ByteGeist Toolbox + +ByteGeist Toolbox is a plain Node.js and Express web app that provides practical website and network inspection tools from a single browser page. + +Live site: [https://toolbox.casko.dev](https://toolbox.casko.dev) + +## Tools + +1. Website Status Checker + - Accepts a public HTTP or HTTPS URL. + - Returns online status, HTTP status code, response time, redirect count, final URL, and check timestamp. + +2. DNS Lookup + - Accepts a public hostname or pasted website URL. + - Returns A, AAAA, CNAME, MX, TXT, and NS records plus a check timestamp. + +3. SSL Certificate Checker + - Accepts a public hostname or pasted website URL. + - Returns certificate trust status, subject, issuer, validity dates, days remaining, TLS protocol, cipher, resolved address, SHA-256 fingerprint, authorization error when present, and check timestamp. + +4. HTTP Headers Checker + - Accepts a public HTTP or HTTPS URL. + - Returns HTTP status, redirect count, final URL, all response headers, and whether common security headers are present. + - The header review is informational. It is not a complete website security grade. + +## Technology Stack + +- Plain HTML +- Plain CSS +- Plain browser JavaScript +- Node.js +- Express +- Docker and Docker Compose +- Node's built-in test runner + +## Project Structure + +```text +. +|-- Dockerfile +|-- docker-compose.yml +|-- LICENSE +|-- package-lock.json +|-- package.json +|-- README.md +|-- docs +| |-- DEPLOYMENT.md +| |-- PORTFOLIO.md +| |-- RELEASE_CHECKLIST.md +| `-- screenshots +| `-- .gitkeep +|-- public +| |-- app.js +| |-- index.html +| `-- styles.css +|-- src +| |-- middleware +| | |-- rateLimit.js +| | `-- validateHostname.js +| |-- routes +| | |-- dns.js +| | |-- headers.js +| | |-- ssl.js +| | `-- uptime.js +| |-- server.js +| `-- services +| |-- dnsService.js +| |-- headersService.js +| |-- sslService.js +| |-- uptimeService.js +| `-- urlSecurityService.js +`-- tests + |-- dnsService.test.js + |-- headersService.test.js + |-- sslService.test.js + |-- urlSecurityService.test.js + `-- validateHostname.test.js +``` + +## Security Controls + +The code implements these controls for server-side outbound requests: + +- Allows only `http:` and `https:` URLs for URL-based tools. +- Blocks credentials in submitted URLs. +- Allows only standard ports `80` and `443` for URL-based tools. +- Blocks common local hostnames including `localhost`, `.localhost`, `.local`, and `host.docker.internal`. +- Resolves hostnames before outbound requests and blocks loopback, private, link-local, unique-local, multicast, unspecified, reserved, broadcast, and carrier-grade NAT addresses. +- Revalidates every redirect destination before following it. +- Limits redirects to 5. +- Uses 5 second network timeouts for HTTP and TLS checks. +- Applies Express rate limiting of 30 requests per IP per 15 minutes on tool API routes. +- Returns safe client-facing error messages instead of raw low-level network errors. +- Uses Node DNS, Fetch, and TLS APIs without shell execution. + +## Tests + +Current test command: + +```bash +npm test +``` + +Current automated test count: 62 tests. + +Baseline verified result: 62 pass, 0 fail, 0 skipped. + +The current `npm test` suite includes public-network integration checks for DNS, SSL, and HTTP headers. Internet access is required for the full suite as currently organized. + +## Local Development + +Install dependencies: + +```bash +npm install +``` + +Run tests: + +```bash +npm test +``` + +Start local development with nodemon: + +```bash +npm run dev +``` + +Start without nodemon: + +```bash +npm start +``` + +The app listens on port `3001` by default. The health endpoint is: + +```text +GET /health +``` + +It returns JSON shaped like: + +```json +{"status":"ok","service":"bytegeist-toolbox","timestamp":"2026-07-23T10:03:36.388Z"} +``` + +The timestamp is generated at request time. + +## Docker + +Build and run with Docker Compose: + +```bash +docker compose up -d --build +``` + +Check status: + +```bash +docker compose ps +docker compose logs --tail=100 +``` + +Stop the service: + +```bash +docker compose down +``` + +The container runs the production start command: + +```bash +npm start +``` + +The production application port is `3001`. + +## Production Deployment + +Production is intended to run as a Docker Compose service named `bytegeist-toolbox` on port `3001`, behind Nginx Proxy Manager. + +The Compose file attaches the application to the external Docker network: + +```text +nginx-proxy-manager_default +``` + +Nginx Proxy Manager should proxy to: + +```text +http://bytegeist-toolbox:3001 +``` + +Do not assume the Nginx Proxy Manager container name. Confirm container names with: + +```bash +docker ps +``` + +## Repository Workflow + +The configured remotes are: + +```text +origin https://git.casko.dev/keith/bytegeist-toolbox.git +github https://github.com/kcasko/bytegeist-toolbox.git +``` + +Use `origin` for the primary Gitea repository and `github` for the GitHub mirror. + +## Screenshots + +No screenshot image files currently exist under `docs/screenshots/`. + +Expected screenshot filenames for the v1.0.0 README are: + +```text +docs/screenshots/status-checker.png +docs/screenshots/dns-lookup.png +docs/screenshots/ssl-checker.png +docs/screenshots/http-headers.png +``` + +Add image references to this README only after those files exist. + +## Current Limitations + +- The automated test suite mixes local helper tests with public-network integration tests. +- DNS and network integration tests depend on external DNS and public websites being reachable. +- The HTTP Headers Checker reports common header presence only; it does not evaluate full security posture. +- The app checks public endpoints only and intentionally blocks local, private, reserved, and nonstandard-port destinations. +- Screenshots have not yet been captured for README display. + +## Planned Improvements + +- Split public-network integration tests from local unit tests while preserving coverage. +- Add screenshot images for all four tools. +- Add local mock-based route tests for API responses and error paths. +- Add manual release evidence for mobile screenshots and production verification. + +## Author + +Keith Casko + diff --git a/docker-compose.yml b/docker-compose.yml index e7bfedc..9327531 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,3 +10,10 @@ services: environment: PORT: 3001 NODE_ENV: production + + networks: + - nginx-proxy-manager_default + +networks: + nginx-proxy-manager_default: + external: true diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..c1e4252 --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,61 @@ +# Deployment + +## Local Use + +```bash +npm install +npm test +npm run dev +``` + +The local development server listens on port `3001` unless `PORT` is set. + +## Production Update + +```bash +cd /srv/bytegeist-toolbox +git pull origin main +docker compose down +docker compose up -d --build +docker compose ps +docker compose logs --tail=100 +``` + +## Docker Network + +The application joins the external Nginx Proxy Manager Docker network: + +```text +nginx-proxy-manager_default +``` + +Nginx Proxy Manager should proxy to: + +```text +http://bytegeist-toolbox:3001 +``` + +Do not assume the Nginx Proxy Manager container name. Confirm container names with: + +```bash +docker ps +``` + +## Internal Health Check + +```bash +docker exec -it npm curl -sS http://bytegeist-toolbox:3001/health +``` + +The `npm` container name is environment-specific. Confirm it with: + +```bash +docker ps +``` + +## Public Verification + +```bash +curl -I https://toolbox.casko.dev +``` + diff --git a/docs/PORTFOLIO.md b/docs/PORTFOLIO.md new file mode 100644 index 0000000..4066a8e --- /dev/null +++ b/docs/PORTFOLIO.md @@ -0,0 +1,79 @@ +# ByteGeist Toolbox + +## Project Description + +ByteGeist Toolbox is a lightweight website and network diagnostics app that combines a website status checker, DNS lookup, SSL certificate checker, and HTTP headers checker in one plain HTML, CSS, JavaScript, Node.js, and Express application. + +## Key Features + +- Website status checks with status code, response time, redirects, final URL, and timestamp. +- DNS lookups for A, AAAA, CNAME, MX, TXT, and NS records. +- SSL certificate inspection with issuer, subject, validity dates, trust status, TLS protocol, cipher, resolved address, and SHA-256 fingerprint. +- HTTP response header inspection with common security-header presence indicators and raw header output. +- Responsive browser interface for desktop, tablet, and phone widths. + +## Security Work + +- Restricted URL checks to HTTP and HTTPS. +- Blocked URL credentials and nonstandard ports. +- Validated DNS resolution before outbound requests. +- Blocked loopback, private, link-local, local, reserved, and related non-public address ranges. +- Revalidated redirect destinations before following them. +- Added redirect limits, network timeouts, rate limiting, and safe client-facing errors. +- Used Node APIs for network work without shell execution. + +## Testing Work + +- Uses Node's built-in test runner. +- Current automated test count: 62 tests. +- Covers hostname validation, URL security checks, DNS helpers, SSL helper logic, HTTP header analysis, and public-network integration behavior. +- Current full test suite requires internet access. + +## Deployment Architecture + +- Node.js and Express app served from a Docker container. +- Production port: `3001`. +- Docker Compose service: `bytegeist-toolbox`. +- Reverse proxy: Nginx Proxy Manager over the external `nginx-proxy-manager_default` Docker network. +- Public site: `https://toolbox.casko.dev`. + +## Technologies Used + +- HTML +- CSS +- JavaScript +- Node.js +- Express +- Docker +- Docker Compose +- Node test runner + +## Resume Entry + +ByteGeist Toolbox - Built and prepared a production-ready Node.js diagnostics toolbox with four public website inspection tools, SSRF-resistant outbound request validation, Docker deployment, and automated test coverage. + +## Resume Bullets + +- Built a lightweight Express application providing website status, DNS, SSL certificate, and HTTP header inspection tools. +- Implemented outbound request controls to block private, loopback, link-local, reserved, local, credentialed, and nonstandard-port destinations. +- Added redirect revalidation, redirect limits, network timeouts, rate limiting, and safe client-facing error handling. +- Designed a responsive plain HTML, CSS, and JavaScript interface without adding frontend frameworks. +- Wrote and maintained 62 automated tests with coverage for validation, network helper logic, and integration behavior. +- Containerized the app with Docker and Docker Compose for deployment behind Nginx Proxy Manager. +- Documented release, deployment, security controls, limitations, and production verification steps for v1.0.0. + +## LinkedIn Project Description + +ByteGeist Toolbox is a lightweight Node.js and Express diagnostics app for checking website status, DNS records, SSL certificates, and HTTP headers. I prepared the project for a v1.0.0 release with Docker deployment docs, SSRF-resistant request validation, rate limiting, responsive UI checks, and 62 automated tests. + +## Skills Demonstrated + +- Node.js backend development +- Express routing and middleware +- Secure outbound request validation +- DNS, HTTP, and TLS diagnostics +- Docker deployment +- Automated testing +- Responsive frontend implementation +- Release documentation + diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md new file mode 100644 index 0000000..17bd174 --- /dev/null +++ b/docs/RELEASE_CHECKLIST.md @@ -0,0 +1,18 @@ +# ByteGeist Toolbox v1.0.0 Release Checklist + +- [ ] Automated tests pass. +- [ ] Exact test count recorded. +- [ ] All four tools work locally. +- [ ] All four tools work in production. +- [ ] Private and loopback destinations are blocked. +- [ ] Invalid inputs return readable errors. +- [ ] Mobile layout checked at 375px, 390px, and 768px. +- [ ] Docker rebuild succeeds. +- [ ] Health endpoint succeeds. +- [ ] Nginx Proxy Manager can reach `bytegeist-toolbox:3001`. +- [ ] README screenshots exist. +- [ ] Gitea updated. +- [ ] GitHub mirror updated. +- [ ] Production deployment verified. +- [ ] v1.0.0 tag created and pushed. + diff --git a/docs/screenshots/.gitkeep b/docs/screenshots/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/screenshots/.gitkeep @@ -0,0 +1 @@ + diff --git a/package-lock.json b/package-lock.json index 7949073..da1adb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "": { "name": "bytegeist-toolbox", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "dependencies": { "express": "^5.2.1", "express-rate-limit": "^8.6.0", diff --git a/package.json b/package.json index aff3c2b..a8861fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bytegeist-toolbox", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "scripts": { "start": "node src/server.js", "dev": "nodemon src/server.js", diff --git a/public/app.js b/public/app.js index d6d895e..8615a3a 100644 --- a/public/app.js +++ b/public/app.js @@ -13,10 +13,15 @@ toolTabs.forEach((tab) => { // Mark only the selected tab as active. toolTabs.forEach((currentTab) => { - currentTab.classList.toggle( - "active", - currentTab === tab - ); + const isSelected = currentTab === tab; + + currentTab.classList.toggle("active", isSelected); + + if (isSelected) { + currentTab.setAttribute("aria-current", "page"); + } else { + currentTab.removeAttribute("aria-current"); + } }); // Show only the selected tool panel. @@ -658,4 +663,4 @@ headersForm.addEventListener("submit", async (event) => { headersButton.disabled = false; headersButton.textContent = "Check Headers"; } -}); \ No newline at end of file +}); diff --git a/public/index.html b/public/index.html index 50bc54e..907c25c 100644 --- a/public/index.html +++ b/public/index.html @@ -30,6 +30,8 @@ class="tool-tab active" type="button" data-tool="status-tool" + aria-controls="status-tool" + aria-current="page" > Website Status @@ -39,6 +41,7 @@ class="tool-tab" type="button" data-tool="dns-tool" + aria-controls="dns-tool" > DNS Lookup @@ -48,6 +51,7 @@ class="tool-tab" type="button" data-tool="ssl-tool" + aria-controls="ssl-tool" > SSL Certificate @@ -57,6 +61,7 @@ class="tool-tab" type="button" data-tool="headers-tool" + aria-controls="headers-tool" > HTTP Headers @@ -417,4 +422,4 @@ - \ No newline at end of file +