@networkpro/web 1.15.0 → 1.15.2

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,56 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
22
22
 
23
23
  ---
24
24
 
25
+ ## [1.15.2] - 2025-07-12
26
+
27
+ ### Added
28
+
29
+ - Added `Disallow` directives to `static/robots.txt` for stub routes:
30
+ - `/consultation`
31
+ - `/links`
32
+ - `/posts`
33
+
34
+ ### Changed
35
+
36
+ - Updated `README.md` to reflect the updated directory structure after removing the `netlify/` directory.
37
+
38
+ ---
39
+
40
+ ## [1.15.1] - 2025-07-12
41
+
42
+ ### Added
43
+
44
+ - Added `Report-To` header in `src/hooks.server.js` to support modern CSP reporting
45
+
46
+ ### Changed
47
+
48
+ - Bumped project version to `1.15.1`
49
+ - Updated CSP report URL in `src/hooks.server.js` to use external endpoint
50
+ - Updated `sitemap.xml` to reflect latest site structure
51
+ - Updated `.node-version` and `.nvmrc` to `v24.4.0`
52
+ - Cleaned up `netlify.toml`:
53
+ - Removed `[[edge_functions]]` block
54
+ - Confirmed `ENV_MODE` remains for internal tooling
55
+ - Updated to latest versions:
56
+ - `@eslint/js` to `^9.31.0`
57
+ - `@playwright/test` to `^1.54.1`
58
+ - `@sveltejs/kit` to `2.22.5`
59
+ - `@sveltejs/vite-plugin-svelte` to `6.0.0`
60
+ - `eslint` to `^9.31.0`
61
+ - `eslint-plugin-jsdoc` to `^51.3.4`
62
+ - `playwright` to `^1.54.1`
63
+ - `posthog-js` to `^1.257.0`
64
+ - `stylelint` to `^16.21.1`
65
+ - `svelte` to `5.35.6`
66
+ - `vite` to `7.0.4`
67
+
68
+ ### Removed
69
+
70
+ - Deleted `/netlify/edge-functions/` and `csp-report.js` (CSP report handling is now in its own project)
71
+ - Removed `tests/unit/server/csp-report.test.js` from project, as CSP endpoint has been relocated
72
+
73
+ ---
74
+
25
75
  ## [1.15.0] - 2025-07-01
26
76
 
27
77
  ### Added
@@ -615,7 +665,9 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
615
665
 
616
666
  <!-- Link references -->
617
667
 
618
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.15.0...HEAD
668
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.15.2...HEAD
669
+ [1.15.2]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.15.2
670
+ [1.15.1]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.15.1
619
671
  [1.15.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.15.0
620
672
  [1.14.2]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.14.2
621
673
  [1.14.1]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.14.1
package/README.md CHANGED
@@ -71,9 +71,6 @@ This project follows the principles of [Keep a Changelog](https://keepachangelog
71
71
  │ ├── extensions.json # Recommended VS Code / VSCodium extensions
72
72
  │ ├── extensions.jsonc # Commented version of extensions.json
73
73
  │ └── settings.json # Workspace settings
74
- ├── netlify/
75
- │ ├── edge-functions/
76
- │ │ └── csp-report.js # Receives CSP violation reports
77
74
  ├── scripts/ # General-purpose utility scripts
78
75
  ├── src/
79
76
  │ ├── lib/ # Components, utilities, types, styles
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.2",
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
package/static/robots.txt CHANGED
@@ -20,6 +20,9 @@ Disallow: /.lighthouseci/
20
20
  # Disallow stub routes that redirect externally
21
21
  Disallow: /contact
22
22
  Disallow: /privacy-rights
23
+ Disallow: /consultation
24
+ Disallow: /links
25
+ Disallow: /posts
23
26
 
24
27
  # Allow everything else
25
28
  Allow: /
@@ -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
- });