@networkpro/web 1.12.9 → 1.13.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/CHANGELOG.md +26 -1
- package/README.md +8 -8
- package/eslint.config.mjs +48 -48
- package/netlify/edge-functions/csp-report.js +31 -31
- package/package.json +1 -1
- package/playwright.config.js +14 -14
- package/postcss.config.mjs +1 -1
- package/scripts/auditScripts.js +16 -16
- package/scripts/bundleCss.js +5 -5
- package/scripts/checkEnv.js +6 -6
- package/scripts/checkNode.js +10 -10
- package/scripts/checkVersions.js +6 -6
- package/scripts/flattenHeaders.js +13 -13
- package/scripts/generateTest.js +5 -5
- package/scripts/openReport.js +3 -3
- package/scripts/validateHeaders.js +13 -13
- package/src/hooks.client.ts +1 -1
- package/src/hooks.server.js +31 -31
- package/src/lib/components/Badges.svelte +9 -9
- package/src/lib/components/CodeBlock.svelte +1 -1
- package/src/lib/components/ContainerSection.svelte +1 -1
- package/src/lib/components/FullWidthSection.svelte +3 -3
- package/src/lib/components/LegalNav.svelte +6 -6
- package/src/lib/components/Logo.svelte +9 -9
- package/src/lib/components/MetaTags.svelte +3 -3
- package/src/lib/components/PWAInstallButton.svelte +4 -4
- package/src/lib/components/RedirectPage.svelte +4 -4
- package/src/lib/components/SocialMedia.svelte +16 -16
- package/src/lib/components/foss/FossItemContent.svelte +18 -18
- package/src/lib/components/layout/Footer.svelte +17 -17
- package/src/lib/components/layout/HeaderDefault.svelte +16 -16
- package/src/lib/components/layout/HeaderHome.svelte +14 -14
- package/src/lib/images.js +34 -34
- package/src/lib/index.js +15 -15
- package/src/lib/meta.js +29 -29
- package/src/lib/pages/AboutContent.svelte +24 -24
- package/src/lib/pages/FossContent.svelte +12 -12
- package/src/lib/pages/HomeContent.svelte +6 -6
- package/src/lib/pages/LicenseContent.svelte +38 -38
- package/src/lib/pages/PGPContent.svelte +23 -23
- package/src/lib/pages/PrivacyContent.svelte +39 -39
- package/src/lib/pages/PrivacyDashboard.svelte +12 -12
- package/src/lib/pages/TermsConditionsContent.svelte +28 -28
- package/src/lib/pages/TermsUseContent.svelte +26 -26
- package/src/lib/registerServiceWorker.js +25 -25
- package/src/lib/stores/posthog.js +13 -13
- package/src/lib/stores/trackingPreferences.js +19 -19
- package/src/lib/unregisterServiceWorker.js +1 -1
- package/src/lib/utils/purify.js +4 -4
- package/src/lib/utils/utm.js +2 -2
- package/src/routes/+error.svelte +4 -4
- package/src/routes/+layout.js +6 -6
- package/src/routes/+layout.svelte +29 -29
- package/src/routes/+page.server.js +2 -2
- package/src/routes/+page.svelte +9 -9
- package/src/routes/about/+page.server.js +2 -2
- package/src/routes/about/+page.svelte +7 -7
- package/src/routes/api/mock-csp/+server.js +3 -3
- package/src/routes/consultation/+page.svelte +5 -5
- package/src/routes/contact/+page.svelte +5 -5
- package/src/routes/foss-spotlight/+page.server.js +2 -2
- package/src/routes/foss-spotlight/+page.svelte +7 -7
- package/src/routes/license/+page.server.js +2 -2
- package/src/routes/license/+page.svelte +7 -7
- package/src/routes/pgp/+page.server.js +2 -2
- package/src/routes/pgp/+page.svelte +7 -7
- package/src/routes/pgp/[key]/+server.js +9 -9
- package/src/routes/privacy/+page.server.js +2 -2
- package/src/routes/privacy/+page.svelte +7 -7
- package/src/routes/privacy-dashboard/+page.server.js +2 -2
- package/src/routes/privacy-dashboard/+page.svelte +8 -8
- package/src/routes/privacy-rights/+page.svelte +5 -5
- package/src/routes/status/+page.server.js +2 -2
- package/src/routes/terms-conditions/+page.server.js +2 -2
- package/src/routes/terms-conditions/+page.svelte +7 -7
- package/src/routes/terms-of-use/+page.server.js +2 -2
- package/src/routes/terms-of-use/+page.svelte +7 -7
- package/src/service-worker.js +86 -86
- package/static/disableSw.js +2 -2
- package/static/offline.html +7 -7
- package/stylelint.config.js +56 -56
- package/svelte.config.js +6 -6
- package/tests/e2e/app.spec.js +25 -25
- package/tests/e2e/mobile.spec.js +18 -18
- package/tests/e2e/shared/helpers.js +4 -4
- package/tests/internal/auditCoverage.test.js +24 -24
- package/tests/unit/checkEnv.test.js +10 -10
- package/tests/unit/checkVersions.test.js +4 -4
- package/tests/unit/csp-report.test.js +24 -24
- package/tests/unit/demo.test.js +3 -3
- package/tests/unit/lib/utils/purify.test.js +12 -12
- package/tests/unit/routes/page.svelte.test.js +10 -10
- package/tests/unit/unregisterServiceWorker.test.js +5 -5
- package/tests/unit/utm.test.js +13 -13
- package/vite.config.js +5 -5
- package/vitest-setup-client.js +4 -4
- package/vitest.config.client.js +15 -15
- package/vitest.config.server.js +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,30 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
## [1.13.0] - 2025-06-11
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Introduced `/pgp` route to publish OpenPGP contact information, download links, and QR codes
|
|
30
|
+
- Added `.well-known/humans.txt` to document project authorship
|
|
31
|
+
- Added `.well-known/security.txt` to define the official security contact and vulnerability disclosure policy
|
|
32
|
+
- Linked OpenPGP keys to external directories for validation (e.g. keys.openpgp.org)
|
|
33
|
+
- Added new GitHub Actions workflow: `check-security-txt-expiry.yml` to monitor `security.txt` expiration
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Enforced `"singleQuote": true` in `.prettierrc` and formatted the codebase using Prettier
|
|
38
|
+
- Updated `src/service-worker.js` to exclude `security.txt.asc` from caching
|
|
39
|
+
- CSP policy updated to allow `clipboard-write` for improved UX on PGP fingerprint buttons
|
|
40
|
+
- Clarified that addresses under the `s.neteng.pro` domain are powered by Proton Mail and support native E2EE
|
|
41
|
+
- Revised `SECURITY.md` and `security.txt` with accurate Proton Mail usage notes and PGP policy references
|
|
42
|
+
|
|
43
|
+
### Removed
|
|
44
|
+
|
|
45
|
+
- Legacy reference to a "coming soon" PGP section in `SECURITY.md` (now live and linked)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
25
49
|
## [1.12.9] - 2025-06-11
|
|
26
50
|
|
|
27
51
|
### Added
|
|
@@ -286,7 +310,8 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
|
|
|
286
310
|
|
|
287
311
|
<!-- Link references -->
|
|
288
312
|
|
|
289
|
-
[Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.
|
|
313
|
+
[Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.13.0...HEAD
|
|
314
|
+
[1.13.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.13.0
|
|
290
315
|
[1.12.9]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.9
|
|
291
316
|
[1.12.8]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.8
|
|
292
317
|
[1.12.7]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.7
|
package/README.md
CHANGED
|
@@ -221,12 +221,12 @@ This script runs `scripts/checkNode.js`, which compares your current Node.js and
|
|
|
221
221
|
**_Node Version Check (snippet from `scripts/checkNode.js`)_**
|
|
222
222
|
|
|
223
223
|
```javascript
|
|
224
|
-
const semver = require(
|
|
225
|
-
const { engines } = require(
|
|
224
|
+
const semver = require('semver');
|
|
225
|
+
const { engines } = require('../package.json');
|
|
226
226
|
|
|
227
227
|
const requiredNode = engines.node;
|
|
228
228
|
const requiredNpm = engines.npm;
|
|
229
|
-
const isPostInstall = process.env.npm_lifecycle_event ===
|
|
229
|
+
const isPostInstall = process.env.npm_lifecycle_event === 'postinstall';
|
|
230
230
|
|
|
231
231
|
let hasError = false;
|
|
232
232
|
|
|
@@ -236,8 +236,8 @@ if (!semver.satisfies(process.version, requiredNode)) {
|
|
|
236
236
|
if (!isPostInstall) hasError = true;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
const npmVersion = require(
|
|
240
|
-
.execSync(
|
|
239
|
+
const npmVersion = require('child_process')
|
|
240
|
+
.execSync('npm -v')
|
|
241
241
|
.toString()
|
|
242
242
|
.trim();
|
|
243
243
|
|
|
@@ -248,7 +248,7 @@ if (!semver.satisfies(npmVersion, requiredNpm)) {
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
if (!hasError) {
|
|
251
|
-
console.log(
|
|
251
|
+
console.log('✅ Node and npm versions are valid.');
|
|
252
252
|
} else {
|
|
253
253
|
process.exit(1);
|
|
254
254
|
}
|
|
@@ -343,7 +343,7 @@ It unregisters **all active service worker registrations** and logs the result.
|
|
|
343
343
|
Located at `static/disableSw.js`, this file sets a global flag if the URL contains the `?nosw` query parameter:
|
|
344
344
|
|
|
345
345
|
```js
|
|
346
|
-
if (location.search.includes(
|
|
346
|
+
if (location.search.includes('nosw')) {
|
|
347
347
|
window.__DISABLE_SW__ = true;
|
|
348
348
|
}
|
|
349
349
|
```
|
|
@@ -365,7 +365,7 @@ https://netwk.pro/?nosw
|
|
|
365
365
|
To register the service worker conditionally, call the function from client code:
|
|
366
366
|
|
|
367
367
|
```js
|
|
368
|
-
import { registerServiceWorker } from
|
|
368
|
+
import { registerServiceWorker } from '$lib/registerServiceWorker.js';
|
|
369
369
|
|
|
370
370
|
registerServiceWorker();
|
|
371
371
|
```
|
package/eslint.config.mjs
CHANGED
|
@@ -6,57 +6,57 @@ SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
|
6
6
|
This file is part of Network Pro.
|
|
7
7
|
========================================================================= */
|
|
8
8
|
|
|
9
|
-
import js from
|
|
10
|
-
import eslintConfigPrettier from
|
|
11
|
-
import jsdocPlugin from
|
|
12
|
-
import sveltePlugin from
|
|
13
|
-
import globals from
|
|
14
|
-
import svelteParser from
|
|
9
|
+
import js from '@eslint/js'; // Provides ESLint core rules and recommended config
|
|
10
|
+
import eslintConfigPrettier from 'eslint-config-prettier'; // Prettier config to disable conflicting ESLint rules
|
|
11
|
+
import jsdocPlugin from 'eslint-plugin-jsdoc'; // JSDoc plugin
|
|
12
|
+
import sveltePlugin from 'eslint-plugin-svelte'; // Svelte plugin
|
|
13
|
+
import globals from 'globals';
|
|
14
|
+
import svelteParser from 'svelte-eslint-parser'; // Svelte parser
|
|
15
15
|
|
|
16
16
|
const GLOBALS = {
|
|
17
17
|
...globals.browser,
|
|
18
18
|
...globals.node,
|
|
19
|
-
self:
|
|
20
|
-
location:
|
|
21
|
-
indexedDB:
|
|
19
|
+
self: 'readonly',
|
|
20
|
+
location: 'readonly',
|
|
21
|
+
indexedDB: 'readonly',
|
|
22
22
|
...globals.vitest, // Add Vitest globals for test functions like afterEach, describe, etc.
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
// Define general ESLint rules (non-Svelte-specific)
|
|
26
26
|
const ESLINT_RULES = {
|
|
27
|
-
indent:
|
|
28
|
-
quotes:
|
|
29
|
-
semi:
|
|
27
|
+
indent: 'off', // Turn off the 'indent' rule, managed by Prettier
|
|
28
|
+
quotes: 'off', // Turn off the 'quotes' rule, managed by Prettier
|
|
29
|
+
semi: 'off', // Turn off the 'semi' rule, managed by Prettier
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export default [
|
|
33
33
|
// Global ignores
|
|
34
34
|
{
|
|
35
35
|
ignores: [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
'.*', // Hidden files
|
|
37
|
+
'*.xml', // XML files
|
|
38
|
+
'**/.cache/**', // Cache directories
|
|
39
|
+
'**/.vscode/**', // VSCode-specific files
|
|
40
|
+
'**/coverage/**', // Coverage reports
|
|
41
|
+
'**/build/**', // Distribution files
|
|
42
|
+
'package.json', // NPM package manifest
|
|
43
|
+
'package-lock.json', // NPM lockfile
|
|
44
|
+
'**/playwright-report/**', // Playwright report files
|
|
45
|
+
'node_modules/', // Node.js dependencies
|
|
46
|
+
'**/test-results/**', // Test results
|
|
47
|
+
'.vite/', // Vite-specific cache directory
|
|
48
|
+
'*.lock', // Lock files
|
|
49
|
+
'.env*', // Environment files
|
|
50
50
|
],
|
|
51
51
|
},
|
|
52
52
|
|
|
53
53
|
// General JavaScript/Node.js configuration
|
|
54
54
|
{
|
|
55
|
-
files: [
|
|
55
|
+
files: ['**/*.mjs', '**/*.js'],
|
|
56
56
|
languageOptions: {
|
|
57
57
|
globals: GLOBALS,
|
|
58
|
-
ecmaVersion:
|
|
59
|
-
sourceType:
|
|
58
|
+
ecmaVersion: 'latest',
|
|
59
|
+
sourceType: 'module',
|
|
60
60
|
},
|
|
61
61
|
plugins: {
|
|
62
62
|
jsdoc: jsdocPlugin, // Include JSDoc plugin
|
|
@@ -65,21 +65,21 @@ export default [
|
|
|
65
65
|
...js.configs.recommended.rules, // ESLint's core recommended rules (scoped)
|
|
66
66
|
...eslintConfigPrettier.rules, // Prettier config to disable conflicting ESLint rules (scoped)
|
|
67
67
|
...ESLINT_RULES, // Additional custom rules
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // Ignore unused variables starting with an underscore
|
|
69
|
+
'jsdoc/check-alignment': 'warn', // Ensure JSDoc block tags are aligned
|
|
70
|
+
'jsdoc/check-param-names': 'warn', // Checks parameter names in JSDoc
|
|
71
71
|
// Updated rule to allow the @updated tag
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
'jsdoc/check-tag-names': [
|
|
73
|
+
'warn',
|
|
74
74
|
{
|
|
75
|
-
definedTags: [
|
|
75
|
+
definedTags: ['updated'],
|
|
76
76
|
},
|
|
77
77
|
],
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
'jsdoc/check-types': 'warn', // Checks if types in JSDoc are defined correctly
|
|
79
|
+
'jsdoc/require-param': 'warn', // Requires @param in JSDoc
|
|
80
|
+
'jsdoc/require-returns': 'warn', // Requires @returns in JSDoc
|
|
81
|
+
'jsdoc/require-jsdoc': [
|
|
82
|
+
'warn',
|
|
83
83
|
{
|
|
84
84
|
publicOnly: true,
|
|
85
85
|
require: {
|
|
@@ -94,33 +94,33 @@ export default [
|
|
|
94
94
|
|
|
95
95
|
// Svelte-specific configuration
|
|
96
96
|
{
|
|
97
|
-
files: [
|
|
97
|
+
files: ['**/*.svelte'],
|
|
98
98
|
plugins: { svelte: sveltePlugin }, // Use imported Svelte plugin
|
|
99
99
|
languageOptions: {
|
|
100
100
|
parser: svelteParser, // Use imported Svelte parser
|
|
101
101
|
globals: GLOBALS, // Your global variables
|
|
102
|
-
ecmaVersion:
|
|
103
|
-
sourceType:
|
|
102
|
+
ecmaVersion: 'latest', // Use "latest" for Svelte to leverage modern features
|
|
103
|
+
sourceType: 'module',
|
|
104
104
|
},
|
|
105
105
|
rules: {
|
|
106
106
|
...sveltePlugin.configs.recommended.rules, // Svelte recommended rules
|
|
107
107
|
...sveltePlugin.configs.prettier.rules, // Prettier compatibility for Svelte
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
'svelte/no-at-html-tags': 'warn', // Warn on use of @html (security risk)
|
|
109
|
+
'svelte/require-optimized-style-attribute': 'warn', // Recommend optimized style attributes
|
|
110
110
|
},
|
|
111
111
|
},
|
|
112
112
|
|
|
113
113
|
// Vitest-specific configuration
|
|
114
114
|
{
|
|
115
|
-
files: [
|
|
115
|
+
files: ['**/*.test.js', '**/*.spec.js', '**/vitest-setup-client.js'], // Test-related files
|
|
116
116
|
languageOptions: {
|
|
117
117
|
globals: {
|
|
118
118
|
...GLOBALS,
|
|
119
|
-
afterEach:
|
|
119
|
+
afterEach: 'readonly', // Explicitly declare afterEach as a global
|
|
120
120
|
},
|
|
121
121
|
},
|
|
122
122
|
rules: {
|
|
123
|
-
|
|
123
|
+
'no-undef': 'off', // Turn off no-undef for test globals
|
|
124
124
|
},
|
|
125
125
|
},
|
|
126
126
|
];
|
|
@@ -27,29 +27,29 @@ This file is part of Network Pro.
|
|
|
27
27
|
* @returns {Promise<Response>} HTTP Response with status 204 or 405
|
|
28
28
|
*/
|
|
29
29
|
export default async (request, _context) => {
|
|
30
|
-
if (request.method !==
|
|
31
|
-
return new Response(
|
|
30
|
+
if (request.method !== 'POST') {
|
|
31
|
+
return new Response('Method Not Allowed', { status: 405 });
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
try {
|
|
35
35
|
const body = await request.json();
|
|
36
|
-
const report = body[
|
|
36
|
+
const report = body['csp-report'];
|
|
37
37
|
|
|
38
38
|
// Ignore if report is missing or malformed
|
|
39
|
-
if (!report || typeof report !==
|
|
39
|
+
if (!report || typeof report !== 'object') {
|
|
40
40
|
return new Response(null, { status: 204 });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const violated = report[
|
|
44
|
-
const blockedUri = report[
|
|
43
|
+
const violated = report['violated-directive'] ?? '';
|
|
44
|
+
const blockedUri = report['blocked-uri'] ?? '';
|
|
45
45
|
|
|
46
46
|
// Filter: Skip img-src violations and empty URIs
|
|
47
47
|
const ignored = [
|
|
48
|
-
violated.startsWith(
|
|
49
|
-
blockedUri ===
|
|
50
|
-
blockedUri ===
|
|
51
|
-
blockedUri.startsWith(
|
|
52
|
-
blockedUri.startsWith(
|
|
48
|
+
violated.startsWith('img-src'),
|
|
49
|
+
blockedUri === '',
|
|
50
|
+
blockedUri === 'about',
|
|
51
|
+
blockedUri.startsWith('chrome-extension://'),
|
|
52
|
+
blockedUri.startsWith('moz-extension://'),
|
|
53
53
|
].some(Boolean);
|
|
54
54
|
|
|
55
55
|
if (ignored) {
|
|
@@ -60,15 +60,15 @@ export default async (request, _context) => {
|
|
|
60
60
|
await sendToNtfy(violated, blockedUri, report);
|
|
61
61
|
|
|
62
62
|
// Log useful violations
|
|
63
|
-
console.log(
|
|
63
|
+
console.log('[CSP-Edge] Violation:', {
|
|
64
64
|
directive: violated,
|
|
65
65
|
uri: blockedUri,
|
|
66
|
-
referrer: report[
|
|
67
|
-
source: report[
|
|
68
|
-
line: report[
|
|
66
|
+
referrer: report['referrer'],
|
|
67
|
+
source: report['source-file'],
|
|
68
|
+
line: report['line-number'],
|
|
69
69
|
});
|
|
70
70
|
} catch (err) {
|
|
71
|
-
console.warn(
|
|
71
|
+
console.warn('[CSP-Edge] Failed to parse CSP report:', err.message);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
return new Response(null, { status: 204 });
|
|
@@ -87,13 +87,13 @@ const VIOLATION_TTL_MS = 60_000;
|
|
|
87
87
|
*/
|
|
88
88
|
async function sendToNtfy(violated, blockedUri, report) {
|
|
89
89
|
const highRiskDirectives = [
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
'script-src',
|
|
91
|
+
'form-action',
|
|
92
|
+
'frame-ancestors',
|
|
93
|
+
'base-uri',
|
|
94
94
|
];
|
|
95
95
|
|
|
96
|
-
const directiveKey = violated.split(
|
|
96
|
+
const directiveKey = violated.split(' ')[0]; // strip fallback values or sources
|
|
97
97
|
const isHighRisk = highRiskDirectives.includes(directiveKey);
|
|
98
98
|
console.log(`[CSP-Edge] Checking directive: ${directiveKey}`);
|
|
99
99
|
if (!isHighRisk) return;
|
|
@@ -120,23 +120,23 @@ async function sendToNtfy(violated, blockedUri, report) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const topicUrl =
|
|
123
|
+
const topicUrl = 'https://ntfy.neteng.pro/csp-alerts';
|
|
124
124
|
|
|
125
125
|
const message = [
|
|
126
126
|
`🚨 CSP Violation Detected`,
|
|
127
127
|
`Directive: ${violated}`,
|
|
128
128
|
`Blocked URI: ${blockedUri}`,
|
|
129
|
-
`Referrer: ${report.referrer ||
|
|
130
|
-
`Source: ${report[
|
|
131
|
-
`Line: ${report[
|
|
132
|
-
].join(
|
|
129
|
+
`Referrer: ${report.referrer || 'N/A'}`,
|
|
130
|
+
`Source: ${report['source-file'] || 'N/A'}`,
|
|
131
|
+
`Line: ${report['line-number'] || 'N/A'}`,
|
|
132
|
+
].join('\n');
|
|
133
133
|
|
|
134
134
|
await fetch(topicUrl, {
|
|
135
|
-
method:
|
|
135
|
+
method: 'POST',
|
|
136
136
|
headers: {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
'Content-Type': 'text/plain',
|
|
138
|
+
'X-Title': 'High-Risk CSP Violation',
|
|
139
|
+
'X-Priority': '5',
|
|
140
140
|
},
|
|
141
141
|
body: message,
|
|
142
142
|
});
|
|
@@ -147,5 +147,5 @@ async function sendToNtfy(violated, blockedUri, report) {
|
|
|
147
147
|
* This sets the endpoint route to /api/csp-report
|
|
148
148
|
*/
|
|
149
149
|
export const config = {
|
|
150
|
-
path:
|
|
150
|
+
path: '/api/csp-report',
|
|
151
151
|
};
|
package/package.json
CHANGED
package/playwright.config.js
CHANGED
|
@@ -7,14 +7,14 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== */
|
|
8
8
|
|
|
9
9
|
// @ts-check
|
|
10
|
-
import { defineConfig, devices } from
|
|
10
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @see https://playwright.dev/docs/test-configuration
|
|
14
14
|
*/
|
|
15
15
|
export default defineConfig({
|
|
16
|
-
testDir:
|
|
17
|
-
testMatch:
|
|
16
|
+
testDir: './tests/e2e',
|
|
17
|
+
testMatch: '*.spec.js',
|
|
18
18
|
|
|
19
19
|
/* Run tests in files in parallel */
|
|
20
20
|
fullyParallel: true,
|
|
@@ -29,12 +29,12 @@ export default defineConfig({
|
|
|
29
29
|
workers: process.env.CI ? 1 : undefined,
|
|
30
30
|
|
|
31
31
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
32
|
-
reporter:
|
|
32
|
+
reporter: 'html',
|
|
33
33
|
|
|
34
34
|
/* Shared settings for all projects */
|
|
35
35
|
use: {
|
|
36
|
-
baseURL:
|
|
37
|
-
trace:
|
|
36
|
+
baseURL: 'http://localhost:4173?nosw', // Update to use preview server URL
|
|
37
|
+
trace: 'on-first-retry',
|
|
38
38
|
timeout: 60000, // Default action timeout of 60 seconds for each step
|
|
39
39
|
navigationTimeout: 60000, // Timeout for navigation operations
|
|
40
40
|
},
|
|
@@ -43,16 +43,16 @@ export default defineConfig({
|
|
|
43
43
|
projects: [
|
|
44
44
|
// Desktop Browsers
|
|
45
45
|
{
|
|
46
|
-
name:
|
|
46
|
+
name: 'chromium',
|
|
47
47
|
use: {
|
|
48
|
-
browserName:
|
|
48
|
+
browserName: 'chromium', // Use Chromium browser
|
|
49
49
|
headless: true, // Enable true headless mode
|
|
50
50
|
},
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
name:
|
|
53
|
+
name: 'firefox',
|
|
54
54
|
use: {
|
|
55
|
-
...devices[
|
|
55
|
+
...devices['Desktop Firefox'], // Use default Firefox settings
|
|
56
56
|
},
|
|
57
57
|
},
|
|
58
58
|
// FIXME: Webkit and Safari consistently failing, disabled for now
|
|
@@ -65,9 +65,9 @@ export default defineConfig({
|
|
|
65
65
|
|
|
66
66
|
// Mobile Browsers
|
|
67
67
|
{
|
|
68
|
-
name:
|
|
68
|
+
name: 'Mobile Chrome',
|
|
69
69
|
use: {
|
|
70
|
-
...devices[
|
|
70
|
+
...devices['Galaxy S9+'], // Use the Galaxy S9+ device profile
|
|
71
71
|
headless: true, // Enable true headless mode
|
|
72
72
|
},
|
|
73
73
|
},
|
|
@@ -82,8 +82,8 @@ export default defineConfig({
|
|
|
82
82
|
|
|
83
83
|
/* Run your local preview server before starting the tests */
|
|
84
84
|
webServer: {
|
|
85
|
-
command:
|
|
86
|
-
url:
|
|
85
|
+
command: 'npm run preview', // Use preview server
|
|
86
|
+
url: 'http://localhost:4173?nosw', // Match the preview server URL
|
|
87
87
|
reuseExistingServer: !process.env.CI,
|
|
88
88
|
timeout: 60 * 1000, // wait up to 60 seconds for preview to be ready
|
|
89
89
|
},
|
package/postcss.config.mjs
CHANGED
|
@@ -6,7 +6,7 @@ SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
|
6
6
|
This file is part of Network Pro.
|
|
7
7
|
========================================================================== */
|
|
8
8
|
|
|
9
|
-
import autoprefixer from
|
|
9
|
+
import autoprefixer from 'autoprefixer';
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
plugins: [
|
package/scripts/auditScripts.js
CHANGED
|
@@ -15,16 +15,16 @@ This file is part of Network Pro.
|
|
|
15
15
|
* @updated 2025-05-21
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import fs from
|
|
19
|
-
import path from
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
20
|
|
|
21
|
-
const scriptsDir = path.resolve(
|
|
22
|
-
const testsDir = path.resolve(
|
|
21
|
+
const scriptsDir = path.resolve('./scripts');
|
|
22
|
+
const testsDir = path.resolve('./tests');
|
|
23
23
|
|
|
24
24
|
// Scripts intentionally excluded from test coverage
|
|
25
25
|
const allowList = new Set([
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
'checkNode.js',
|
|
27
|
+
'auditScripts.js', // itself
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
30
|
// Recursively gather all test files
|
|
@@ -38,10 +38,10 @@ function getAllTestFiles(dir) {
|
|
|
38
38
|
files.push(...getAllTestFiles(fullPath));
|
|
39
39
|
} else if (
|
|
40
40
|
entry.isFile() &&
|
|
41
|
-
(entry.name.endsWith(
|
|
42
|
-
entry.name.endsWith(
|
|
43
|
-
entry.name.endsWith(
|
|
44
|
-
entry.name.endsWith(
|
|
41
|
+
(entry.name.endsWith('.test.js') ||
|
|
42
|
+
entry.name.endsWith('.spec.js') ||
|
|
43
|
+
entry.name.endsWith('.test.mjs') ||
|
|
44
|
+
entry.name.endsWith('.spec.mjs'))
|
|
45
45
|
) {
|
|
46
46
|
files.push(fullPath);
|
|
47
47
|
}
|
|
@@ -56,17 +56,17 @@ const testedModules = new Set(
|
|
|
56
56
|
testFiles.map((filePath) =>
|
|
57
57
|
path
|
|
58
58
|
.basename(filePath)
|
|
59
|
-
.replace(/\.test\.js$|\.spec\.js$|\.test\.mjs$|\.spec\.mjs$/,
|
|
59
|
+
.replace(/\.test\.js$|\.spec\.js$|\.test\.mjs$|\.spec\.mjs$/, ''),
|
|
60
60
|
),
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
// Gather all scripts (.js and .mjs)
|
|
64
64
|
const scriptFiles = fs
|
|
65
65
|
.readdirSync(scriptsDir)
|
|
66
|
-
.filter((file) => file.endsWith(
|
|
66
|
+
.filter((file) => file.endsWith('.js') || file.endsWith('.mjs'));
|
|
67
67
|
|
|
68
68
|
const untested = scriptFiles.filter((file) => {
|
|
69
|
-
const base = file.replace(/\.(js|mjs)$/,
|
|
69
|
+
const base = file.replace(/\.(js|mjs)$/, '');
|
|
70
70
|
return !allowList.has(file) && !testedModules.has(base);
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -75,7 +75,7 @@ const pathRelative = (file) =>
|
|
|
75
75
|
|
|
76
76
|
// Output results
|
|
77
77
|
if (untested.length) {
|
|
78
|
-
console.warn(
|
|
78
|
+
console.warn('\n⚠ Untested script files detected:\n');
|
|
79
79
|
|
|
80
80
|
untested.forEach((file) => {
|
|
81
81
|
const filePath = pathRelative(file);
|
|
@@ -87,9 +87,9 @@ if (untested.length) {
|
|
|
87
87
|
console.warn(
|
|
88
88
|
`\nAdd a corresponding test file in /tests (e.g., ${untested[0].replace(
|
|
89
89
|
/\.(js|mjs)$/,
|
|
90
|
-
|
|
90
|
+
'.test.js',
|
|
91
91
|
)})`,
|
|
92
92
|
);
|
|
93
93
|
} else {
|
|
94
|
-
console.log(
|
|
94
|
+
console.log('✅ All script files have corresponding tests.');
|
|
95
95
|
}
|
package/scripts/bundleCss.js
CHANGED
|
@@ -15,15 +15,15 @@ This file is part of Network Pro.
|
|
|
15
15
|
* @updated 2025-05-16
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import fs from
|
|
19
|
-
import { bundle } from
|
|
20
|
-
import path from
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import { bundle } from 'lightningcss';
|
|
20
|
+
import path from 'path';
|
|
21
21
|
|
|
22
22
|
// Define the path to your input CSS file
|
|
23
|
-
const inputFilePath = path.resolve(
|
|
23
|
+
const inputFilePath = path.resolve('src/lib/styles/css/global.css');
|
|
24
24
|
|
|
25
25
|
// Define the path for the output CSS file
|
|
26
|
-
const outputFilePath = path.resolve(
|
|
26
|
+
const outputFilePath = path.resolve('src/lib/styles/css/global.min.css');
|
|
27
27
|
|
|
28
28
|
// Bundle and minify the CSS
|
|
29
29
|
const { code, map } = bundle({
|
package/scripts/checkEnv.js
CHANGED
|
@@ -15,10 +15,10 @@ This file is part of Network Pro.
|
|
|
15
15
|
* @updated 2025-05-21
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { basename } from
|
|
19
|
-
import { fileURLToPath } from
|
|
18
|
+
import { basename } from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
20
|
|
|
21
|
-
const validEnvs = new Set([
|
|
21
|
+
const validEnvs = new Set(['dev', 'test', 'ci', 'prod', 'preview']);
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Checks and returns validation for ENV_MODE
|
|
@@ -36,7 +36,7 @@ export function checkEnv() {
|
|
|
36
36
|
let wasDefaulted = false;
|
|
37
37
|
|
|
38
38
|
if (!mode) {
|
|
39
|
-
mode =
|
|
39
|
+
mode = 'dev';
|
|
40
40
|
process.env.ENV_MODE = mode;
|
|
41
41
|
wasDefaulted = true;
|
|
42
42
|
console.warn("⚠️ ENV_MODE not set. Defaulting to 'dev'.");
|
|
@@ -45,11 +45,11 @@ export function checkEnv() {
|
|
|
45
45
|
valid = validEnvs.has(mode);
|
|
46
46
|
|
|
47
47
|
if (valid) {
|
|
48
|
-
const tag = wasDefaulted ?
|
|
48
|
+
const tag = wasDefaulted ? '[info]' : '[ok]';
|
|
49
49
|
console.log(`${tag} ENV_MODE is set to: "${mode}"`);
|
|
50
50
|
} else {
|
|
51
51
|
console.error(
|
|
52
|
-
`❌ Invalid ENV_MODE "${mode}". Must be one of: ${[...validEnvs].join(
|
|
52
|
+
`❌ Invalid ENV_MODE "${mode}". Must be one of: ${[...validEnvs].join(', ')}`,
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|