@networkpro/web 1.15.0 → 1.15.1

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/.node-version CHANGED
@@ -1 +1 @@
1
- 24.3.0
1
+ 24.4.0
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- 24.3.0
1
+ 24.4.0
package/CHANGELOG.md CHANGED
@@ -22,6 +22,41 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
22
22
 
23
23
  ---
24
24
 
25
+ ## [1.15.1] - 2025-07-12
26
+
27
+ ### Added
28
+
29
+ - Added `Report-To` header in `src/hooks.server.js` to support modern CSP reporting
30
+
31
+ ### Changed
32
+
33
+ - Bumped project version to `1.15.1`
34
+ - Updated CSP report URL in `src/hooks.server.js` to use external endpoint
35
+ - Updated `sitemap.xml` to reflect latest site structure
36
+ - Updated `.node-version` and `.nvmrc` to `v24.4.0`
37
+ - Cleaned up `netlify.toml`:
38
+ - Removed `[[edge_functions]]` block
39
+ - Confirmed `ENV_MODE` remains for internal tooling
40
+ - Updated to latest versions:
41
+ - `@eslint/js` to `^9.31.0`
42
+ - `@playwright/test` to `^1.54.1`
43
+ - `@sveltejs/kit` to `2.22.5`
44
+ - `@sveltejs/vite-plugin-svelte` to `6.0.0`
45
+ - `eslint` to `^9.31.0`
46
+ - `eslint-plugin-jsdoc` to `^51.3.4`
47
+ - `playwright` to `^1.54.1`
48
+ - `posthog-js` to `^1.257.0`
49
+ - `stylelint` to `^16.21.1`
50
+ - `svelte` to `5.35.6`
51
+ - `vite` to `7.0.4`
52
+
53
+ ### Removed
54
+
55
+ - Deleted `/netlify/edge-functions/` and `csp-report.js` (CSP report handling is now in its own project)
56
+ - Removed `tests/unit/server/csp-report.test.js` from project, as CSP endpoint has been relocated
57
+
58
+ ---
59
+
25
60
  ## [1.15.0] - 2025-07-01
26
61
 
27
62
  ### Added
@@ -615,7 +650,8 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
615
650
 
616
651
  <!-- Link references -->
617
652
 
618
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.15.0...HEAD
653
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.15.1...HEAD
654
+ [1.15.1]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.15.1
619
655
  [1.15.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.15.0
620
656
  [1.14.2]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.14.2
621
657
  [1.14.1]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.14.1
package/netlify.toml CHANGED
@@ -2,7 +2,6 @@
2
2
  command = "npm run build"
3
3
 
4
4
  [build.environment]
5
- NODE_VERSION = "22"
6
5
  ENV_MODE = "prod"
7
6
 
8
7
  [dev]
@@ -10,10 +9,6 @@
10
9
  targetPort = 5173
11
10
  port = 8888
12
11
 
13
- [[edge_functions]]
14
- path = "/api/csp-report"
15
- function = "csp-report"
16
-
17
12
  [[plugins]]
18
13
  package = "netlify-plugin-submit-sitemap"
19
14
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.15.0",
4
+ "version": "1.15.1",
5
5
  "description": "Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies",
6
6
  "keywords": [
7
7
  "advisory",
@@ -79,26 +79,26 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "dompurify": "^3.2.6",
82
- "posthog-js": "^1.256.0",
82
+ "posthog-js": "^1.257.0",
83
83
  "semver": "^7.7.2",
84
- "svelte": "5.34.9"
84
+ "svelte": "5.35.6"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@eslint/compat": "^1.3.1",
88
- "@eslint/js": "^9.30.0",
88
+ "@eslint/js": "^9.31.0",
89
89
  "@lhci/cli": "^0.15.1",
90
- "@playwright/test": "^1.53.2",
90
+ "@playwright/test": "^1.54.1",
91
91
  "@sveltejs/adapter-netlify": "^5.0.2",
92
- "@sveltejs/kit": "2.22.2",
93
- "@sveltejs/vite-plugin-svelte": "5.1.0",
92
+ "@sveltejs/kit": "2.22.5",
93
+ "@sveltejs/vite-plugin-svelte": "^6.0.0",
94
94
  "@testing-library/jest-dom": "^6.6.3",
95
95
  "@testing-library/svelte": "^5.2.8",
96
96
  "@vitest/coverage-v8": "^3.2.4",
97
97
  "autoprefixer": "^10.4.21",
98
98
  "browserslist": "^4.25.1",
99
- "eslint": "^9.30.0",
99
+ "eslint": "^9.31.0",
100
100
  "eslint-config-prettier": "^10.1.5",
101
- "eslint-plugin-jsdoc": "^51.3.1",
101
+ "eslint-plugin-jsdoc": "^51.3.4",
102
102
  "eslint-plugin-svelte": "^3.10.1",
103
103
  "globals": "^16.3.0",
104
104
  "jsdom": "^26.1.0",
@@ -106,11 +106,11 @@
106
106
  "markdownlint": "^0.38.0",
107
107
  "markdownlint-cli2": "^0.18.1",
108
108
  "mdsvex": "^0.12.6",
109
- "playwright": "^1.53.2",
109
+ "playwright": "^1.54.1",
110
110
  "postcss": "^8.5.6",
111
111
  "prettier": "^3.6.2",
112
112
  "prettier-plugin-svelte": "^3.4.0",
113
- "stylelint": "^16.21.0",
113
+ "stylelint": "^16.21.1",
114
114
  "stylelint-config-html": "^1.1.0",
115
115
  "stylelint-config-recommended": "^16.0.0",
116
116
  "stylelint-order": "^7.0.0",
@@ -118,7 +118,7 @@
118
118
  "svelte-eslint-parser": "^1.2.0",
119
119
  "svelte-preprocess": "^6.0.3",
120
120
  "typescript": "^5.8.3",
121
- "vite": "6.3.5",
121
+ "vite": "^7.0.4",
122
122
  "vite-plugin-lightningcss": "^0.0.5",
123
123
  "vite-tsconfig-paths": "^5.1.4",
124
124
  "vitest": "^3.2.4"
package/src/app.html CHANGED
@@ -63,7 +63,7 @@
63
63
  content="bx4ham0zkpvzztzu213bhpt76m9siq" />
64
64
  <!-- cspell:enable -->
65
65
 
66
- <meta name="generator" content="SvelteKit 2.22.2" />
66
+ <meta name="generator" content="SvelteKit 2.22.5" />
67
67
 
68
68
  <script src="/disableSw.js"></script>
69
69
 
@@ -25,7 +25,10 @@ export async function handle({ event, resolve }) {
25
25
  console.log('[CSP Debug] ENV_MODE:', process.env.ENV_MODE);
26
26
 
27
27
  // Determine report URI
28
- const reportUri = isProdEnvironment ? '/api/csp-report' : '/api/mock-csp';
28
+ const reportUri =
29
+ isProdEnvironment && !isTestEnvironment
30
+ ? 'https://csp.netwk.pro/.netlify/functions/csp-report'
31
+ : '/api/mock-csp';
29
32
 
30
33
  // Construct base policy
31
34
  const cspDirectives = [
@@ -40,7 +43,9 @@ export async function handle({ event, resolve }) {
40
43
  "object-src 'none';",
41
44
  "frame-ancestors 'none';",
42
45
  'upgrade-insecure-requests;',
46
+ // Report CSP violations to external endpoint hosted at csp.netwk.pro
43
47
  `report-uri ${reportUri};`,
48
+ 'report-to csp-endpoint;',
44
49
  ];
45
50
 
46
51
  // Loosen up CSP for test environments
@@ -54,6 +59,20 @@ export async function handle({ event, resolve }) {
54
59
  cspDirectives[5] = "connect-src 'self';";
55
60
  }
56
61
 
62
+ response.headers.set(
63
+ 'Report-To',
64
+ JSON.stringify({
65
+ group: 'csp-endpoint',
66
+ max_age: 10886400, // 18 weeks
67
+ endpoints: [
68
+ {
69
+ url: 'https://csp.netwk.pro/.netlify/functions/csp-report',
70
+ },
71
+ ],
72
+ include_subdomains: true,
73
+ }),
74
+ );
75
+
57
76
  response.headers.set('Content-Security-Policy', cspDirectives.join(' '));
58
77
 
59
78
  // Set other security headers
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <!-- Sitemap last updated on 2025-06-11 -->
2
+ <!-- Sitemap last updated on July 12, 2025 -->
3
3
 
4
4
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
5
5
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  <loc>https://netwk.pro</loc>
9
9
 
10
- <lastmod>2025-06-10</lastmod>
10
+ <lastmod>2025-07-12</lastmod>
11
11
 
12
12
  <changefreq>weekly</changefreq>
13
13
 
@@ -43,7 +43,7 @@
43
43
 
44
44
  <loc>https://netwk.pro/privacy-dashboard</loc>
45
45
 
46
- <lastmod>2025-05-28</lastmod>
46
+ <lastmod>2025-06-30</lastmod>
47
47
 
48
48
  <changefreq>monthly</changefreq>
49
49
 
@@ -55,7 +55,7 @@
55
55
 
56
56
  <loc>https://netwk.pro/privacy</loc>
57
57
 
58
- <lastmod>2025-06-02</lastmod>
58
+ <lastmod>2025-06-30</lastmod>
59
59
 
60
60
  <changefreq>monthly</changefreq>
61
61
 
@@ -1,160 +0,0 @@
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 noisy or unactionable reports
47
- const ignored = [
48
- violated.startsWith('img-src'),
49
- blockedUri === '',
50
- blockedUri === 'eval',
51
- blockedUri === 'about',
52
- blockedUri.startsWith('chrome-extension://'),
53
- blockedUri.startsWith('moz-extension://'),
54
- !report['source-file'],
55
- !report['document-uri'],
56
- ].some(Boolean);
57
-
58
- if (ignored) {
59
- console.log('[CSP-Edge] Ignored low-value violation:', {
60
- directive: violated,
61
- uri: blockedUri,
62
- });
63
- return new Response(null, { status: 204 });
64
- }
65
-
66
- // Send alert for high-risk directives
67
- await sendToNtfy(violated, blockedUri, report);
68
-
69
- // Log useful violations
70
- console.log('[CSP-Edge] Violation:', {
71
- directive: violated,
72
- uri: blockedUri,
73
- referrer: report['referrer'],
74
- source: report['source-file'],
75
- line: report['line-number'],
76
- });
77
- } catch (err) {
78
- console.warn('[CSP-Edge] Failed to parse CSP report:', err.message);
79
- }
80
-
81
- return new Response(null, { status: 204 });
82
- };
83
-
84
- const recentViolations = new Map();
85
- const VIOLATION_TTL_MS = 60_000;
86
-
87
- /**
88
- * Sends a high-priority alert to your ntfy topic for high-risk CSP violations.
89
- * Applies rate-limiting to avoid sending duplicate alerts within 60 seconds.
90
- *
91
- * @param {string} violated - The violated CSP directive
92
- * @param {string} blockedUri - The URI that was blocked
93
- * @param {Record<string, any>} report - The full CSP report object
94
- */
95
- async function sendToNtfy(violated, blockedUri, report) {
96
- const highRiskDirectives = [
97
- 'script-src',
98
- 'form-action',
99
- 'frame-ancestors',
100
- 'base-uri',
101
- ];
102
-
103
- const directiveKey = violated.split(' ')[0]; // strip fallback values or sources
104
- const isHighRisk = highRiskDirectives.includes(directiveKey);
105
- console.log(
106
- `[CSP-Edge] Directive ${directiveKey} is ${isHighRisk ? '' : 'not '}high-risk`,
107
- );
108
- if (!isHighRisk) return;
109
-
110
- const key = `${violated}|${blockedUri}`;
111
- const now = Date.now();
112
-
113
- // Skip and log if violation was reported recently
114
- if (
115
- recentViolations.has(key) &&
116
- now - recentViolations.get(key) < VIOLATION_TTL_MS
117
- ) {
118
- console.log(`[CSP-Edge] Skipped duplicate alert for ${key}`);
119
- return;
120
- }
121
-
122
- // Record the current timestamp
123
- recentViolations.set(key, now);
124
-
125
- // Cleanup old entries (memory-safe for low volume)
126
- for (const [k, t] of recentViolations.entries()) {
127
- if (now - t > VIOLATION_TTL_MS) {
128
- recentViolations.delete(k);
129
- }
130
- }
131
-
132
- const topicUrl = 'https://ntfy.neteng.pro/csp-alerts';
133
-
134
- const message = [
135
- `🚨 CSP Violation Detected`,
136
- `Directive: ${violated}`,
137
- `Blocked URI: ${blockedUri}`,
138
- `Referrer: ${report.referrer || 'N/A'}`,
139
- `Source: ${report['source-file'] || 'N/A'}`,
140
- `Line: ${report['line-number'] || 'N/A'}`,
141
- ].join('\n');
142
-
143
- await fetch(topicUrl, {
144
- method: 'POST',
145
- headers: {
146
- 'Content-Type': 'text/plain',
147
- 'X-Title': 'High-Risk CSP Violation',
148
- 'X-Priority': '5',
149
- },
150
- body: message,
151
- });
152
- }
153
-
154
- /**
155
- * Configuration block for the Edge Function.
156
- * This sets the endpoint route to /api/csp-report
157
- */
158
- export const config = {
159
- path: '/api/csp-report',
160
- };
@@ -1,81 +0,0 @@
1
- /* ==========================================================================
2
- tests/unit/server/csp-report.test.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
- * Tests the edge-functions/csp-report.js CSP reporting endpoint
11
- *
12
- * @module tests/unit
13
- * @author SunDevil311
14
- * @updated 2025-05-31
15
- */
16
-
17
- /** @file Unit tests for edge-functions/csp-report.js using Vitest */
18
- /** @typedef {import('vitest').TestContext} TestContext */
19
-
20
- import { beforeEach, describe, expect, it, vi } from 'vitest';
21
- import handler from '../../../netlify/edge-functions/csp-report.js';
22
-
23
- // 🧪 Mock fetch used by sendToNtfy inside the Edge Function
24
- global.fetch = vi.fn(() =>
25
- Promise.resolve({ ok: true, status: 200, text: () => 'OK' }),
26
- );
27
-
28
- describe('csp-report.js', () => {
29
- beforeEach(() => {
30
- vi.clearAllMocks();
31
- });
32
-
33
- it('should handle a valid CSP report', async () => {
34
- const req = new Request('http://localhost/api/csp-report', {
35
- method: 'POST',
36
- headers: { 'Content-Type': 'application/json' },
37
- body: JSON.stringify({
38
- 'csp-report': {
39
- 'document-uri': 'https://example.com',
40
- 'violated-directive': 'script-src',
41
- 'blocked-uri': 'https://malicious.site',
42
- },
43
- }),
44
- });
45
-
46
- const res = await handler(req, {});
47
- expect(res.status).toBe(204);
48
- });
49
-
50
- it('should reject non-POST requests', async () => {
51
- const req = new Request('http://localhost/api/csp-report', {
52
- method: 'GET',
53
- });
54
-
55
- const res = await handler(req, {});
56
- const text = await res.text();
57
- expect(res.status).toBe(405);
58
- expect(text).toContain('Method Not Allowed');
59
- });
60
-
61
- it('should handle malformed JSON', async () => {
62
- const badJson = '{ invalid json }';
63
- const req = new Request('http://localhost/api/csp-report', {
64
- method: 'POST',
65
- headers: { 'Content-Type': 'application/json' },
66
- body: badJson,
67
- });
68
-
69
- const res = await handler(req, {});
70
- expect(res.status).toBe(204); // The current handler swallows errors silently
71
- });
72
-
73
- it('should handle missing body', async () => {
74
- const req = new Request('http://localhost/api/csp-report', {
75
- method: 'POST',
76
- });
77
-
78
- const res = await handler(req, {});
79
- expect(res.status).toBe(204); // No body is also treated silently
80
- });
81
- });