@networkpro/web 1.7.9 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +238 -75
- package/cspell.json +3 -0
- package/netlify/edge-functions/csp-report.js +151 -0
- package/netlify.toml +3 -3
- package/package.json +6 -6
- package/scripts/generateTest.js +61 -0
- package/src/hooks.server.js +1 -1
- package/src/lib/components/foss/FossItemContent.svelte +28 -30
- package/src/lib/components/layout/HeaderDefault.svelte +1 -1
- package/src/lib/components/layout/HeaderHome.svelte +1 -1
- package/src/lib/pages/AboutContent.svelte +15 -5
- package/src/lib/pages/FossContent.svelte +1 -2
- package/src/lib/pages/LicenseContent.svelte +2 -2
- package/src/lib/styles/css/default.css +11 -2
- package/src/lib/styles/global.min.css +1 -1
- package/src/lib/types/fossTypes.js +23 -0
- package/src/lib/utils/purify.js +74 -0
- package/src/routes/status/+page.server.js +32 -0
- package/tests/internal/auditCoverage.test.js +99 -0
- package/tests/unit/csp-report.test.js +81 -0
- package/tests/unit/lib/utils/purify.test.js +50 -0
- package/vitest.config.client.js +5 -1
- package/vitest.config.server.js +1 -0
- package/netlify-functions/cspReport.js +0 -76
- package/tests/unit/auditScripts.test.js +0 -43
- package/tests/unit/cspReport.test.js +0 -81
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ This file is part of Network Pro.
|
|
|
17
17
|
[](https://github.com/prettier/prettier) [](https://stylelint.io/)
|
|
18
18
|
[](https://github.com/netwk-pro/netwk-pro.github.io/blob/master/CODE_OF_CONDUCT.md)
|
|
19
19
|
|
|
20
|
+
<section id="top">
|
|
21
|
+
|
|
20
22
|
## 🚀 Project Overview
|
|
21
23
|
|
|
22
24
|
This GitHub repository powers the official web presence of **[Network Pro Strategies](https://netwk.pro/about)** — a privacy-first consultancy specializing in cybersecurity, network engineering, and information security. We also lead public advocacy efforts promoting digital privacy and responsible cyber policy.
|
|
@@ -26,36 +28,64 @@ Built with [SvelteKit](https://kit.svelte.dev/) and deployed via [Netlify](https
|
|
|
26
28
|
|
|
27
29
|
All infrastructure and data flows are designed with **maximum transparency, self-hosting, and user privacy** in mind.
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
</section>
|
|
32
|
+
|
|
33
|
+
### Table of Contents
|
|
34
|
+
|
|
35
|
+
- [Repository Structure](#structure)
|
|
36
|
+
- [Getting Started](#getting-started)
|
|
37
|
+
- [Configuration](#configuration)
|
|
38
|
+
- [Service Worker Utilities](#sw-utilities)
|
|
39
|
+
- [CSP Report Handler](#cspreport)
|
|
40
|
+
- [Testing](#testing)
|
|
41
|
+
- [Recommended Toolchain](#toolchain)
|
|
42
|
+
- [Tooling Configuration](#toolconfig)
|
|
43
|
+
- [Available Scripts](#scripts)
|
|
44
|
+
- [License](#license)
|
|
45
|
+
- [Questions](#questions)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<section id="structure">
|
|
50
|
+
|
|
51
|
+
## 📁 Repository Structure
|
|
30
52
|
|
|
31
53
|
```bash
|
|
32
|
-
.
|
|
33
|
-
├── .github/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
│ ├──
|
|
37
|
-
│ ├── extensions.
|
|
38
|
-
│
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
├──
|
|
42
|
-
|
|
43
|
-
│
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
│ ├──
|
|
47
|
-
│ ├──
|
|
48
|
-
│
|
|
49
|
-
├──
|
|
50
|
-
│ ├──
|
|
51
|
-
│ ├──
|
|
52
|
-
│ └──
|
|
53
|
-
├──
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
├──
|
|
57
|
-
├──
|
|
58
|
-
|
|
54
|
+
.
|
|
55
|
+
├── .github/
|
|
56
|
+
│ └── workflows/ # CI workflows (e.g. test, deploy)
|
|
57
|
+
├── .vscode/
|
|
58
|
+
│ ├── customData.json # Custom CSS IntelliSense (e.g. FontAwesome)
|
|
59
|
+
│ ├── extensions.json # Recommended VS Code / VSCodium extensions
|
|
60
|
+
│ ├── extensions.jsonc # Commented version of extensions.json
|
|
61
|
+
│ └── settings.json # Workspace settings
|
|
62
|
+
├── netlify/
|
|
63
|
+
│ ├── edge-functions/
|
|
64
|
+
│ │ └── csp-report.js # Receives CSP violation reports
|
|
65
|
+
│ └── netlify.toml # Netlify configuration
|
|
66
|
+
├── scripts/ # General-purpose utility scripts
|
|
67
|
+
├── src/
|
|
68
|
+
│ ├── app.html # Entry HTML (CSP meta, bootstrapping)
|
|
69
|
+
│ ├── hooks.client.ts # PWA install prompt & client-side logging
|
|
70
|
+
│ ├── hooks.server.js # Injects CSP headers and permissions policy
|
|
71
|
+
│ ├── lib/ # Components, utilities, types, styles
|
|
72
|
+
│ │ ├── components/ # Svelte components
|
|
73
|
+
│ │ ├── data/ # Custom data (e.g. JSON, metadata, constants)
|
|
74
|
+
│ │ └── utils/ # Helper utilities
|
|
75
|
+
│ ├── routes/ # SvelteKit pages (+page.svelte, +server.js)
|
|
76
|
+
│ └── service-worker.js # Custom PWA service worker
|
|
77
|
+
├── static/ # Public assets served at site root
|
|
78
|
+
│ ├── disableSw.js # Service worker bypass (via ?nosw param)
|
|
79
|
+
│ ├── manifest.json # PWA metadata
|
|
80
|
+
│ ├── robots.txt # SEO: allow/disallow crawlers
|
|
81
|
+
│ └── sitemap.xml # SEO: full site map
|
|
82
|
+
├── tests/
|
|
83
|
+
│ ├── e2e/ # Playwright end-to-end tests
|
|
84
|
+
│ ├── internal/ # Internal audit/test helpers
|
|
85
|
+
│ │ └── auditCoverage.test.js # Warns about untested source modules
|
|
86
|
+
│ └── unit/ # Vitest unit tests
|
|
87
|
+
├── _redirects # Netlify redirect rules
|
|
88
|
+
└── package.json # Project manifest (scripts, deps, etc.)
|
|
59
89
|
```
|
|
60
90
|
|
|
61
91
|
|
|
@@ -74,8 +104,14 @@ tests/
|
|
|
74
104
|
└── ...
|
|
75
105
|
```
|
|
76
106
|
|
|
107
|
+
</section>
|
|
108
|
+
|
|
109
|
+
<sub>[Back to top](#top)</sub>
|
|
110
|
+
|
|
77
111
|
---
|
|
78
112
|
|
|
113
|
+
<section id="getting-started">
|
|
114
|
+
|
|
79
115
|
## 🛠 Getting Started
|
|
80
116
|
|
|
81
117
|
### 📦 Environment Setup
|
|
@@ -119,9 +155,9 @@ npm install
|
|
|
119
155
|
> You can also use `bootstrap.local.sh` to automate the steps above and more (optional).
|
|
120
156
|
> `ENV_MODE` controls local tooling behavior — it is not used by the app runtime directly.
|
|
121
157
|
|
|
122
|
-
|
|
158
|
+
|
|
123
159
|
|
|
124
|
-
|
|
160
|
+
### 💾 Version Enforcement
|
|
125
161
|
|
|
126
162
|
To ensure consistent environments across contributors and CI systems, this project enforces specific Node.js and npm versions via the `"engines"` field in `package.json`:
|
|
127
163
|
|
|
@@ -185,7 +221,13 @@ node -v # Should fall within engines.node
|
|
|
185
221
|
npm -v # Should fall within engines.npm
|
|
186
222
|
```
|
|
187
223
|
|
|
188
|
-
|
|
224
|
+
</section>
|
|
225
|
+
|
|
226
|
+
<sub>[Back to top](#top)</sub>
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
<section id="configuration">
|
|
189
231
|
|
|
190
232
|
## 🛡️ Configuration
|
|
191
233
|
|
|
@@ -208,36 +250,117 @@ To re-enable nonce generation for inline scripts in the future:
|
|
|
208
250
|
|
|
209
251
|
> 💡 The `[headers]` block in `netlify.toml` has been deprecated — all headers are now set dynamically from within SvelteKit.
|
|
210
252
|
|
|
211
|
-
|
|
253
|
+
|
|
212
254
|
|
|
213
255
|
### 🧭 `hooks.client.ts`
|
|
214
256
|
|
|
215
|
-
|
|
257
|
+
Located at `src/hooks.client.ts`, this file is currently limited to handling uncaught client-side errors via the `handleError()` lifecycle hook.
|
|
258
|
+
|
|
259
|
+
Client-side PWA logic (such as handling the `beforeinstallprompt` event, checking browser compatibility, and registering the service worker) has been moved to `src/lib/registerServiceWorker.js` for better modularity and testability.
|
|
216
260
|
|
|
217
|
-
|
|
218
|
-
- Provides a `handleError()` hook that logs uncaught client-side errors
|
|
261
|
+
> 💡 This separation ensures that error handling is isolated from PWA lifecycle logic, making both concerns easier to maintain.
|
|
219
262
|
|
|
220
|
-
|
|
263
|
+
</section>
|
|
264
|
+
|
|
265
|
+
<sub>[Back to top](#top)</sub>
|
|
221
266
|
|
|
222
267
|
---
|
|
223
268
|
|
|
224
|
-
|
|
269
|
+
<section id="sw-utilities">
|
|
270
|
+
|
|
271
|
+
## ⚙️ Service Worker Utilities
|
|
272
|
+
|
|
273
|
+
This project includes modular service worker management to support PWA functionality, update lifecycles, and debugging workflows.
|
|
274
|
+
|
|
275
|
+
### ✅ `registerServiceWorker.js`
|
|
276
|
+
|
|
277
|
+
Located at `src/lib/registerServiceWorker.js`, this module handles:
|
|
278
|
+
|
|
279
|
+
- **Service worker registration** (`service-worker.js`)
|
|
280
|
+
- **Update lifecycle**: prompts users when new content is available
|
|
281
|
+
- **Cache hygiene**: removes unexpected caches not prefixed with `cache-`
|
|
282
|
+
- **Install prompt support**: dispatches a `pwa-install-available` event for custom handling
|
|
283
|
+
- **Firefox compatibility**: skips registration in Firefox during localhost development
|
|
284
|
+
|
|
285
|
+
This function is typically called during client boot from `+layout.svelte` or another root-level component.
|
|
286
|
+
|
|
287
|
+
> ℹ️ The service worker will not register if the `?nosw` flag is present or if `window.__DISABLE_SW__` is set (see below).
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
### 🧹 `unregisterServiceWorker.js`
|
|
292
|
+
|
|
293
|
+
Located at `src/lib/unregisterServiceWorker.js`, this utility allows for manual deactivation of service workers during debugging or user opt-out flows.
|
|
294
|
+
|
|
295
|
+
It unregisters **all active service worker registrations** and logs the result.
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
### 🚫 `disableSw.js`
|
|
300
|
+
|
|
301
|
+
Located at `static/disableSw.js`, this file sets a global flag if the URL contains the `?nosw` query parameter:
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
if (location.search.includes("nosw")) {
|
|
305
|
+
window.__DISABLE_SW__ = true;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
This flag is used by `registerServiceWorker.js` to bypass registration. It's helpful for testing environments, browser compatibility checks, or simulating first-load conditions without service worker interference.
|
|
310
|
+
|
|
311
|
+
To use:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
https://netwk.pro/?nosw
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
> 💡 `disableSw.js` is loaded via a `<script>` tag in `app.html` from the `static` directory. This ensures the `__DISABLE_SW__` flag is set before any service worker logic runs.
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
#### 🔧 Example Usage
|
|
322
|
+
|
|
323
|
+
To register the service worker conditionally, call the function from client code:
|
|
324
|
+
|
|
325
|
+
```js
|
|
326
|
+
import { registerServiceWorker } from "$lib/registerServiceWorker.js";
|
|
327
|
+
|
|
328
|
+
registerServiceWorker();
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
You can optionally import unregisterServiceWorker() in a debug menu or settings panel to let users opt out of offline behavior.
|
|
332
|
+
|
|
333
|
+
</section>
|
|
334
|
+
|
|
335
|
+
<sub>[Back to top](#top)</sub>
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
<section id="cspreport">
|
|
340
|
+
|
|
341
|
+
## 📣 CSP Report Handler
|
|
225
342
|
|
|
226
343
|
To receive and inspect CSP violation reports in development or production, the repo includes a Netlify-compatible function at:
|
|
227
344
|
|
|
228
345
|
```bash
|
|
229
|
-
netlify-functions/
|
|
346
|
+
netlify/edge-functions/csp-report.js
|
|
230
347
|
```
|
|
231
348
|
|
|
232
|
-
This
|
|
349
|
+
This Edge Function receives Content Security Policy (CSP) violation reports at `/api/csp-report` and logs relevant details to the console. High-risk violations (e.g., `script-src`, `form-action`) also trigger real-time alerts via `ntfy`. You can further integrate with logging tools, SIEM platforms, or notification systems as needed.
|
|
233
350
|
|
|
234
351
|
Make sure to include the `report-uri` directive in your CSP header:
|
|
235
352
|
|
|
236
353
|
```bash
|
|
237
|
-
Content-Security-Policy: ...; report-uri
|
|
354
|
+
Content-Security-Policy: ...; report-uri /api/csp-report;
|
|
238
355
|
```
|
|
239
356
|
|
|
240
|
-
|
|
357
|
+
</section>
|
|
358
|
+
|
|
359
|
+
<sub>[Back to top](#top)</sub>
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
<section id="testing">
|
|
241
364
|
|
|
242
365
|
## 🧪 Testing
|
|
243
366
|
|
|
@@ -299,8 +422,14 @@ npm run test:coverage # Collect code coverage reports
|
|
|
299
422
|
npm run test:e2e # Runs Playwright E2E tests (with one retry on failure)
|
|
300
423
|
```
|
|
301
424
|
|
|
425
|
+
<!-- markdownlint-disable MD028 -->
|
|
426
|
+
|
|
427
|
+
> The unit test suite includes a coverage audit (`auditCoverage.test.js`) that warns when source files in `src/` or `scripts/` do not have corresponding unit tests. This helps track test completeness without failing CI.
|
|
428
|
+
|
|
302
429
|
> Playwright will retry failed tests once `(--retries=1)` to reduce false negatives from transient flakiness (network, render delay, etc.).
|
|
303
430
|
|
|
431
|
+
<!-- markdownlint-enable MD028 -->
|
|
432
|
+
|
|
304
433
|
Audit your app using Lighthouse:
|
|
305
434
|
|
|
306
435
|
```bash
|
|
@@ -332,8 +461,14 @@ You can also audit locally using Chrome DevTools → Lighthouse tab for on-the-f
|
|
|
332
461
|
|
|
333
462
|
<!-- markdownlint-disable MD028 -->
|
|
334
463
|
|
|
464
|
+
</section>
|
|
465
|
+
|
|
466
|
+
<sub>[Back to top](#top)</sub>
|
|
467
|
+
|
|
335
468
|
---
|
|
336
469
|
|
|
470
|
+
<section id="toolchain">
|
|
471
|
+
|
|
337
472
|
## 🛠 Recommended Toolchain
|
|
338
473
|
|
|
339
474
|
To streamline development and align with project conventions, we recommend the following setup — especially for contributors without a strong existing preference.
|
|
@@ -371,8 +506,14 @@ npm run lint:fix
|
|
|
371
506
|
npm run format:fix
|
|
372
507
|
```
|
|
373
508
|
|
|
509
|
+
</section>
|
|
510
|
+
|
|
511
|
+
<sub>[Back to top](#top)</sub>
|
|
512
|
+
|
|
374
513
|
---
|
|
375
514
|
|
|
515
|
+
<section id="toolconfig">
|
|
516
|
+
|
|
376
517
|
## ⚙️ Tooling Configuration
|
|
377
518
|
|
|
378
519
|
All linting, formatting, and version settings are defined in versioned project config files:
|
|
@@ -395,8 +536,14 @@ These are the same rules used by CI and automation, so aligning your local setup
|
|
|
395
536
|
|
|
396
537
|
> Note: `.vscode/extensions.json` defines a minimal recommended dev stack for VSCodium / VS Code. These extensions are **optional but thoughtfully curated** to improve developer experience without introducing bloat.
|
|
397
538
|
|
|
539
|
+
</section>
|
|
540
|
+
|
|
541
|
+
<sub>[Back to top](#top)</sub>
|
|
542
|
+
|
|
398
543
|
---
|
|
399
544
|
|
|
545
|
+
<section id="scripts">
|
|
546
|
+
|
|
400
547
|
## 📜 Available Scripts
|
|
401
548
|
|
|
402
549
|
The following CLI commands are available via `npm run <script>` or `pnpm run <script>`.
|
|
@@ -412,20 +559,20 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
412
559
|
| `build:netlify` | Build using Netlify CLI |
|
|
413
560
|
| `css:bundle` | Bundle and minify CSS |
|
|
414
561
|
|
|
415
|
-
|
|
562
|
+
|
|
416
563
|
|
|
417
564
|
### ✅ Pre-check / Sync
|
|
418
565
|
|
|
419
|
-
| Script | Description
|
|
420
|
-
| ------------- |
|
|
421
|
-
| `prepare` | Run SvelteKit sync
|
|
422
|
-
| `check` | Run SvelteKit sync and type check with `svelte-check`
|
|
423
|
-
| `check:watch` | Watch mode for type checks
|
|
424
|
-
| `check:node` | Validate Node & npm versions match package.json `engines`
|
|
425
|
-
| `checkout` | Full local validation: check versions, test, lint, typecheck |
|
|
426
|
-
| `verify` | Alias for `checkout`
|
|
566
|
+
| Script | Description |
|
|
567
|
+
| ------------- | ----------------------------------------------------------------------------------- |
|
|
568
|
+
| `prepare` | Run SvelteKit sync |
|
|
569
|
+
| `check` | Run SvelteKit sync and type check with `svelte-check` |
|
|
570
|
+
| `check:watch` | Watch mode for type checks |
|
|
571
|
+
| `check:node` | Validate Node & npm versions match package.json `engines` |
|
|
572
|
+
| `checkout` | Full local validation: check versions, test (incl. audit coverage), lint, typecheck |
|
|
573
|
+
| `verify` | Alias for `checkout` |
|
|
427
574
|
|
|
428
|
-
|
|
575
|
+
|
|
429
576
|
|
|
430
577
|
### 🧹 Cleanup & Maintenance
|
|
431
578
|
|
|
@@ -435,7 +582,7 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
435
582
|
| `clean` | Fully reset environment and reinstall |
|
|
436
583
|
| `upgrade` | Update all dependencies via `npm-check-updates` |
|
|
437
584
|
|
|
438
|
-
|
|
585
|
+
|
|
439
586
|
|
|
440
587
|
<!-- markdownlint-disable MD024 -->
|
|
441
588
|
|
|
@@ -443,17 +590,17 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
443
590
|
|
|
444
591
|
<!-- markdownlint-enable MD024 -->
|
|
445
592
|
|
|
446
|
-
| Script | Description
|
|
447
|
-
| --------------- |
|
|
448
|
-
| `test` | Alias for `test:all`
|
|
449
|
-
| `test:all` | Run both client and server test suites
|
|
450
|
-
| `test:client` | Run client tests with Vitest
|
|
451
|
-
| `test:server` | Run server-side tests with Vitest
|
|
452
|
-
| `test:watch` | Watch mode for client tests
|
|
453
|
-
| `test:coverage` | Collect coverage from both client and server
|
|
454
|
-
| `test:e2e` | Runs E2E tests with up to 1 automatic retry on failure
|
|
593
|
+
| Script | Description |
|
|
594
|
+
| --------------- | ------------------------------------------------------------- |
|
|
595
|
+
| `test` | Alias for `test:all` |
|
|
596
|
+
| `test:all` | Run both client and server test suites (incl. audit coverage) |
|
|
597
|
+
| `test:client` | Run client tests with Vitest |
|
|
598
|
+
| `test:server` | Run server-side tests with Vitest |
|
|
599
|
+
| `test:watch` | Watch mode for client tests |
|
|
600
|
+
| `test:coverage` | Collect coverage from both client and server |
|
|
601
|
+
| `test:e2e` | Runs E2E tests with up to 1 automatic retry on failure |
|
|
455
602
|
|
|
456
|
-
|
|
603
|
+
|
|
457
604
|
|
|
458
605
|
### 🧼 Linting & Formatting
|
|
459
606
|
|
|
@@ -468,7 +615,7 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
468
615
|
| `format` | Run Prettier formatting check |
|
|
469
616
|
| `format:fix` | Auto-format code using Prettier |
|
|
470
617
|
|
|
471
|
-
|
|
618
|
+
|
|
472
619
|
|
|
473
620
|
### 💡 Lighthouse / Performance
|
|
474
621
|
|
|
@@ -477,17 +624,17 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
477
624
|
| `lhci` | Alias for Lighthouse CI |
|
|
478
625
|
| `lhci:run` | Run Lighthouse CI autorun |
|
|
479
626
|
|
|
480
|
-
|
|
627
|
+
|
|
481
628
|
|
|
482
629
|
### 📋 Audits / Validation
|
|
483
630
|
|
|
484
|
-
| Script
|
|
485
|
-
|
|
|
486
|
-
| `audit:
|
|
487
|
-
| `head:flatten`
|
|
488
|
-
| `head:validate`
|
|
631
|
+
| Script | Description |
|
|
632
|
+
| ---------------- | ---------------------------------------------------- |
|
|
633
|
+
| `audit:coverage` | Warn about untested modules in `src/` and `scripts/` |
|
|
634
|
+
| `head:flatten` | Flatten headers for Netlify |
|
|
635
|
+
| `head:validate` | Validate headers file against project config |
|
|
489
636
|
|
|
490
|
-
|
|
637
|
+
|
|
491
638
|
|
|
492
639
|
### 🔄 Lifecycle Hooks
|
|
493
640
|
|
|
@@ -495,10 +642,14 @@ The following CLI commands are available via `npm run <script>` or `pnpm run <sc
|
|
|
495
642
|
| ------------- | ----------------------------------- |
|
|
496
643
|
| `postinstall` | Ensures version check after install |
|
|
497
644
|
|
|
498
|
-
|
|
645
|
+
</section>
|
|
646
|
+
|
|
647
|
+
<sub>[Back to top](#top)</sub>
|
|
499
648
|
|
|
500
649
|
---
|
|
501
650
|
|
|
651
|
+
<section id="license">
|
|
652
|
+
|
|
502
653
|
## 🧾 License
|
|
503
654
|
|
|
504
655
|
This project is licensed under:
|
|
@@ -509,11 +660,21 @@ This project is licensed under:
|
|
|
509
660
|
|
|
510
661
|
Source code, branding, and visual assets are subject to reuse and distribution terms specified on our [Legal, Copyright, and Licensing page](https://netwk.pro/license).
|
|
511
662
|
|
|
512
|
-
|
|
663
|
+
</section>
|
|
664
|
+
|
|
665
|
+
<sub>[Back to top](#top)</sub>
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
<section id="questions">
|
|
513
670
|
|
|
514
671
|
## 🙋♂️Questions?
|
|
515
672
|
|
|
516
|
-
Reach out via [
|
|
673
|
+
Reach out via our [Contact Form](https://netwk.pro/contact), open an issue on this repo, or email us directly at `support (at) neteng.pro`.
|
|
674
|
+
|
|
675
|
+
</section>
|
|
676
|
+
|
|
677
|
+
<sub>[Back to top](#top)</sub>
|
|
517
678
|
|
|
518
679
|
|
|
519
680
|
|
|
@@ -522,7 +683,7 @@ _Designed for professionals. Hardened for privacy. Built with intent._
|
|
|
522
683
|
|
|
523
684
|
---
|
|
524
685
|
|
|
525
|
-
<
|
|
686
|
+
<span style="font-size: 12px; text-align: center;">
|
|
526
687
|
|
|
527
688
|
Copyright © 2025
|
|
528
689
|
**[Network Pro Strategies](https://netwk.pro) (Network Pro™)**
|
|
@@ -531,4 +692,6 @@ Network Pro™, the shield logo, and the "Locking Down Networks™" slog
|
|
|
531
692
|
|
|
532
693
|
Licensed under **[CC BY 4.0](https://netwk.pro/license#cc-by)** and the **[GNU GPL](https://netwk.pro/license#gnu-gpl)**, as published by the [Free Software Foundation](https://www.fsf.org), either version 3 of the License, or (at your option) any later version.
|
|
533
694
|
|
|
534
|
-
</
|
|
695
|
+
</span>
|
|
696
|
+
|
|
697
|
+
<!-- cspell:ignore cspreport toolconfig -->
|
package/cspell.json
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"homescreen",
|
|
20
20
|
"Izzy",
|
|
21
21
|
"lhci",
|
|
22
|
+
"lifecycles",
|
|
22
23
|
"lighthouseci",
|
|
23
24
|
"lighthouserc",
|
|
24
25
|
"lightningcss",
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"nosniff",
|
|
36
37
|
"nosw",
|
|
37
38
|
"npmjs",
|
|
39
|
+
"ntfy",
|
|
38
40
|
"obtainium",
|
|
39
41
|
"posthog",
|
|
40
42
|
"SIEM",
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
"subsites",
|
|
46
48
|
"Supercookie",
|
|
47
49
|
"supercookies",
|
|
50
|
+
"unregisters",
|
|
48
51
|
"urlcheck",
|
|
49
52
|
"vcard",
|
|
50
53
|
"vite",
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
edge-functions/csp-report.js
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
This file is part of Network Pro.
|
|
7
|
+
========================================================================== */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @file csp-report.js
|
|
11
|
+
* @description Netlify Edge Function to handle CSP violation reports.
|
|
12
|
+
*
|
|
13
|
+
* Accepts POST requests to /api/csp-report and logs relevant CSP reports.
|
|
14
|
+
* Filters out common low-value reports (e.g., img-src) to reduce invocation
|
|
15
|
+
* cost. Alerts on high-risk violations via ntfy topic.
|
|
16
|
+
*
|
|
17
|
+
* @module netlify/edge-functions
|
|
18
|
+
* @author SunDevil311
|
|
19
|
+
* @updated 2025-05-31
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Netlify Edge Function entry point for CSP reporting.
|
|
24
|
+
*
|
|
25
|
+
* @param {Request} request - The incoming HTTP request object
|
|
26
|
+
* @param {import('@netlify/edge-functions').Context} _context - The Netlify Edge Function context (unused)
|
|
27
|
+
* @returns {Promise<Response>} HTTP Response with status 204 or 405
|
|
28
|
+
*/
|
|
29
|
+
export default async (request, _context) => {
|
|
30
|
+
if (request.method !== "POST") {
|
|
31
|
+
return new Response("Method Not Allowed", { status: 405 });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const body = await request.json();
|
|
36
|
+
const report = body["csp-report"];
|
|
37
|
+
|
|
38
|
+
// Ignore if report is missing or malformed
|
|
39
|
+
if (!report || typeof report !== "object") {
|
|
40
|
+
return new Response(null, { status: 204 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const violated = report["violated-directive"] ?? "";
|
|
44
|
+
const blockedUri = report["blocked-uri"] ?? "";
|
|
45
|
+
|
|
46
|
+
// Filter: Skip img-src violations and empty URIs
|
|
47
|
+
const ignored = [
|
|
48
|
+
violated.startsWith("img-src"),
|
|
49
|
+
blockedUri === "",
|
|
50
|
+
blockedUri === "about",
|
|
51
|
+
blockedUri.startsWith("chrome-extension://"),
|
|
52
|
+
blockedUri.startsWith("moz-extension://"),
|
|
53
|
+
].some(Boolean);
|
|
54
|
+
|
|
55
|
+
if (ignored) {
|
|
56
|
+
return new Response(null, { status: 204 });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Send alert for high-risk directives
|
|
60
|
+
await sendToNtfy(violated, blockedUri, report);
|
|
61
|
+
|
|
62
|
+
// Log useful violations
|
|
63
|
+
console.log("[CSP-Edge] Violation:", {
|
|
64
|
+
directive: violated,
|
|
65
|
+
uri: blockedUri,
|
|
66
|
+
referrer: report["referrer"],
|
|
67
|
+
source: report["source-file"],
|
|
68
|
+
line: report["line-number"],
|
|
69
|
+
});
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.warn("[CSP-Edge] Failed to parse CSP report:", err.message);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Response(null, { status: 204 });
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const recentViolations = new Map();
|
|
78
|
+
const VIOLATION_TTL_MS = 60_000;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Sends a high-priority alert to your ntfy topic for high-risk CSP violations.
|
|
82
|
+
* Applies rate-limiting to avoid sending duplicate alerts within 60 seconds.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} violated - The violated CSP directive
|
|
85
|
+
* @param {string} blockedUri - The URI that was blocked
|
|
86
|
+
* @param {Record<string, any>} report - The full CSP report object
|
|
87
|
+
*/
|
|
88
|
+
async function sendToNtfy(violated, blockedUri, report) {
|
|
89
|
+
const highRiskDirectives = [
|
|
90
|
+
"script-src",
|
|
91
|
+
"form-action",
|
|
92
|
+
"frame-ancestors",
|
|
93
|
+
"base-uri",
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
const directiveKey = violated.split(" ")[0]; // strip fallback values or sources
|
|
97
|
+
const isHighRisk = highRiskDirectives.includes(directiveKey);
|
|
98
|
+
console.log(`[CSP-Edge] Checking directive: ${directiveKey}`);
|
|
99
|
+
if (!isHighRisk) return;
|
|
100
|
+
|
|
101
|
+
const key = `${violated}|${blockedUri}`;
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
|
|
104
|
+
// Skip and log if violation was reported recently
|
|
105
|
+
if (
|
|
106
|
+
recentViolations.has(key) &&
|
|
107
|
+
now - recentViolations.get(key) < VIOLATION_TTL_MS
|
|
108
|
+
) {
|
|
109
|
+
console.log(`[CSP-Edge] Skipped duplicate alert for ${key}`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Record the current timestamp
|
|
114
|
+
recentViolations.set(key, now);
|
|
115
|
+
|
|
116
|
+
// Cleanup old entries (memory-safe for low volume)
|
|
117
|
+
for (const [k, t] of recentViolations.entries()) {
|
|
118
|
+
if (now - t > VIOLATION_TTL_MS) {
|
|
119
|
+
recentViolations.delete(k);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const topicUrl = "https://ntfy.neteng.pro/csp-alerts";
|
|
124
|
+
|
|
125
|
+
const message = [
|
|
126
|
+
`🚨 CSP Violation Detected`,
|
|
127
|
+
`Directive: ${violated}`,
|
|
128
|
+
`Blocked URI: ${blockedUri}`,
|
|
129
|
+
`Referrer: ${report.referrer || "N/A"}`,
|
|
130
|
+
`Source: ${report["source-file"] || "N/A"}`,
|
|
131
|
+
`Line: ${report["line-number"] || "N/A"}`,
|
|
132
|
+
].join("\n");
|
|
133
|
+
|
|
134
|
+
await fetch(topicUrl, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: {
|
|
137
|
+
"Content-Type": "text/plain",
|
|
138
|
+
"X-Title": "High-Risk CSP Violation",
|
|
139
|
+
"X-Priority": "5",
|
|
140
|
+
},
|
|
141
|
+
body: message,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Configuration block for the Edge Function.
|
|
147
|
+
* This sets the endpoint route to /api/csp-report
|
|
148
|
+
*/
|
|
149
|
+
export const config = {
|
|
150
|
+
path: "/api/csp-report",
|
|
151
|
+
};
|
package/netlify.toml
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
targetPort = 5173
|
|
12
12
|
port = 8888
|
|
13
13
|
|
|
14
|
-
[
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
[[edge_functions]]
|
|
15
|
+
path = "/api/csp-report"
|
|
16
|
+
function = "csp-report"
|
|
17
17
|
|
|
18
18
|
[[plugins]]
|
|
19
19
|
package = "netlify-plugin-submit-sitemap"
|