@networkpro/web 1.25.5 β 1.25.7
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/.github/workflows/probely-scan.yml +35 -15
- package/.vscode/settings.json +1 -36
- package/CHANGELOG.md +71 -1
- package/README.md +43 -11
- package/cspell.json +2 -0
- package/package.json +10 -10
- package/src/hooks.server.js +45 -19
- package/src/lib/components/Badges.svelte +3 -8
- package/src/lib/components/Logo.svelte +8 -19
- package/src/lib/components/PWAInstallButton.svelte +1 -30
- package/src/lib/components/RedirectPage.svelte +1 -1
- package/src/lib/components/foss/FossFeatures.svelte +1 -14
- package/src/lib/components/layout/Footer.svelte +0 -1
- package/src/lib/pages/AboutContent.svelte +1 -7
- package/src/lib/pages/TermsConditionsContent.svelte +1 -1
- package/src/lib/pages/TermsUseContent.svelte +6 -7
- package/src/lib/security/probely.js +47 -0
- package/src/lib/styles/css/default.css +57 -0
- package/src/lib/styles/global.min.css +1 -1
- package/src/routes/+layout.svelte +2 -4
- package/src/routes/api/mock-csp/+server.js +20 -4
- package/src/routes/contact/+page.svelte +1 -1
- package/src/routes/posts/+page.svelte +1 -1
- package/src/routes/privacy-rights/+page.svelte +1 -1
- package/static/.well-known/humans.txt +5 -5
- package/static/robots.txt +2 -2
- package/static/sitemap.xml +12 -12
- package/tests/unit/server/lib/security/probely.test.js +50 -0
- package/vitest.config.server.js +2 -1
|
@@ -21,31 +21,50 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
env:
|
|
23
23
|
PROBELY_API_KEY: ${{ secrets.PROBELY_API_KEY }}
|
|
24
|
-
TARGET_ID:
|
|
25
|
-
API_BASE: https://api.probely.com
|
|
24
|
+
TARGET_ID: ${{ secrets.PROBELY_TARGET_ID }}
|
|
25
|
+
API_BASE: https://api.probely.com
|
|
26
26
|
MAX_WAIT_MINUTES: 60 # configurable
|
|
27
27
|
|
|
28
28
|
steps:
|
|
29
29
|
- name: Start Probely Scan
|
|
30
30
|
id: start-scan
|
|
31
31
|
run: |
|
|
32
|
+
curl_retry() {
|
|
33
|
+
curl --fail-with-body --retry 3 --retry-delay 5 --retry-max-time 30 "$@"
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
echo "π§ͺ Triggering Probely scan for target $TARGET_ID ..."
|
|
33
|
-
|
|
37
|
+
|
|
38
|
+
response_file=$(mktemp)
|
|
39
|
+
http_code=$(curl_retry -s -w "%{http_code}" -o "$response_file" -X POST "$API_BASE/targets/$TARGET_ID/scan_now/" \
|
|
34
40
|
-H "Authorization: JWT $PROBELY_API_KEY" \
|
|
35
41
|
-H "Content-Type: application/json" \
|
|
36
42
|
-d '{}')
|
|
37
43
|
|
|
38
|
-
echo "
|
|
39
|
-
echo "
|
|
44
|
+
echo "π HTTP status: $http_code"
|
|
45
|
+
echo "π Raw API response:"
|
|
46
|
+
cat "$response_file"
|
|
47
|
+
|
|
48
|
+
if [ "$http_code" -ne 201 ]; then
|
|
49
|
+
echo "::error ::Unexpected HTTP response from Probely API: $http_code"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if ! jq . "$response_file" >/dev/null 2>&1; then
|
|
54
|
+
echo "::error ::Invalid JSON response from Probely API."
|
|
55
|
+
cat "$response_file"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
40
58
|
|
|
41
|
-
|
|
59
|
+
jq . "$response_file"
|
|
60
|
+
scan_id=$(jq -r '.id // empty' "$response_file")
|
|
42
61
|
|
|
43
62
|
if [ -z "$scan_id" ]; then
|
|
44
|
-
echo "::error ::
|
|
63
|
+
echo "::error ::Scan ID not found in response. Check API key, target ID, or base URL."
|
|
45
64
|
exit 1
|
|
46
65
|
fi
|
|
47
66
|
|
|
48
|
-
echo "scan_id=$scan_id" >> $GITHUB_ENV
|
|
67
|
+
echo "scan_id=$scan_id" >> "$GITHUB_ENV"
|
|
49
68
|
echo "β
Scan started with ID: $scan_id"
|
|
50
69
|
|
|
51
70
|
- name: Wait for Scan Completion
|
|
@@ -53,7 +72,7 @@ jobs:
|
|
|
53
72
|
echo "β³ Waiting for scan $scan_id to complete..."
|
|
54
73
|
elapsed=0
|
|
55
74
|
while [ $elapsed -lt $((MAX_WAIT_MINUTES * 60)) ]; do
|
|
56
|
-
status=$(curl -s "$API_BASE/scans/$scan_id/" \
|
|
75
|
+
status=$(curl --fail-with-body -s "$API_BASE/targets/$TARGET_ID/scans/$scan_id/" \
|
|
57
76
|
-H "Authorization: JWT $PROBELY_API_KEY" | jq -r '.status // empty')
|
|
58
77
|
|
|
59
78
|
echo "β±οΈ Status: $status (elapsed $elapsed sec)"
|
|
@@ -78,18 +97,19 @@ jobs:
|
|
|
78
97
|
- name: Download Probely HTML Report
|
|
79
98
|
run: |
|
|
80
99
|
echo "π₯ Downloading report for scan $scan_id ..."
|
|
81
|
-
curl -s "$API_BASE/scans/$scan_id/
|
|
100
|
+
curl -s "$API_BASE/targets/$TARGET_ID/scans/$scan_id/endpoints/" \
|
|
82
101
|
-H "Authorization: JWT $PROBELY_API_KEY" \
|
|
83
|
-
-o probely-
|
|
102
|
+
-o probely-scan-coverage.csv
|
|
84
103
|
|
|
85
|
-
if [ ! -s probely-
|
|
104
|
+
if [ ! -s probely-scan-coverage.csv ]; then
|
|
86
105
|
echo "::error ::Report file is empty or missing."
|
|
87
106
|
exit 1
|
|
88
107
|
fi
|
|
89
|
-
echo "β
Report saved as probely-
|
|
108
|
+
echo "β
Report saved as probely-scan-coverage.csv"
|
|
90
109
|
|
|
91
110
|
- name: Upload report artifact
|
|
92
111
|
uses: actions/upload-artifact@v5
|
|
93
112
|
with:
|
|
94
|
-
name: probely-
|
|
95
|
-
path: probely-
|
|
113
|
+
name: probely-scan-coverage
|
|
114
|
+
path: probely-scan-coverage.csv
|
|
115
|
+
# cspell:ignore mktemp
|
package/.vscode/settings.json
CHANGED
|
@@ -41,40 +41,5 @@
|
|
|
41
41
|
"css.customData": [
|
|
42
42
|
".vscode/customData.json" // Path to your custom data file
|
|
43
43
|
],
|
|
44
|
-
"markdown.validate.enabled": false
|
|
45
|
-
"markdown.validate.ignoredLinks": [
|
|
46
|
-
"#bugs",
|
|
47
|
-
"#features",
|
|
48
|
-
"#top",
|
|
49
|
-
"#ownership",
|
|
50
|
-
"#trademark",
|
|
51
|
-
"#branding",
|
|
52
|
-
"#licensed-material",
|
|
53
|
-
"#licenses",
|
|
54
|
-
"#dlnotes",
|
|
55
|
-
"#cc-by",
|
|
56
|
-
"#gnu-gpl",
|
|
57
|
-
"#third-party",
|
|
58
|
-
"#prohibited-uses",
|
|
59
|
-
"#disclaimer",
|
|
60
|
-
"#contact",
|
|
61
|
-
"#revisions",
|
|
62
|
-
"#pledge",
|
|
63
|
-
"#standards",
|
|
64
|
-
"#response",
|
|
65
|
-
"#enforce",
|
|
66
|
-
"#attribute",
|
|
67
|
-
"#version",
|
|
68
|
-
"#structure",
|
|
69
|
-
"#getting-started",
|
|
70
|
-
"#configuration",
|
|
71
|
-
"#sw-utilities",
|
|
72
|
-
"#cspreport",
|
|
73
|
-
"#testing",
|
|
74
|
-
"#toolchain",
|
|
75
|
-
"#toolconfig",
|
|
76
|
-
"#scripts",
|
|
77
|
-
"#license",
|
|
78
|
-
"#questions"
|
|
79
|
-
]
|
|
44
|
+
"markdown.validate.enabled": false
|
|
80
45
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,74 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
## [1.25.7] - 2025-11-11
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Introduced `src/lib/security/probely.js` helper module to detect Probely vulnerability scanner requests via normalized IP and User-Agent matching.
|
|
30
|
+
- Supports case-insensitive substring matching for known Probely UA fragments (`ProbelySPDR/`, etc.).
|
|
31
|
+
- IP allowlisting based on published ranges: <https://help.probely.com/en/articles/5112461/>
|
|
32
|
+
- Added unit test suite `tests/unit/server/lib/security/probely.test.js` to verify robustness of `isProbelyScanner()` logic against UA/IP variations and edge cases.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Updated `hooks.server.js` to integrate `isProbelyScanner()` as a drop-in replacement for inline Probely detection logic, improving clarity and testability.
|
|
37
|
+
- Contact details and motto updated in `static/.well-known/humans.txt`.
|
|
38
|
+
- Refreshed last modified dates in `static/sitemap.xml`.
|
|
39
|
+
- Minor cosmetic changes to `static/robots.txt`.
|
|
40
|
+
- Corrected fallback metadata in `+layout.svelte`.
|
|
41
|
+
- Removed inline styles from `src/lib/components/PWAInstallButton.svelte` and `src/lib/components/foss/FossFeatures.svelte`.
|
|
42
|
+
- Moved styles to `src/lib/styles/css/default.css`.
|
|
43
|
+
- Regenerated `global.min.css` bundle with LightningCSS.
|
|
44
|
+
- Minor optimizations and cleanup to several files:
|
|
45
|
+
- `src/lib/components/RedirectPage.svelte`
|
|
46
|
+
- `src/lib/components/layout/Footer.svelte`
|
|
47
|
+
- `src/lib/pages/AboutContent.svelte`
|
|
48
|
+
- `src/lib/pages/TermsConditionsContent.svelte`
|
|
49
|
+
- `src/lib/pages/TermsUseContent.svelte`
|
|
50
|
+
- `src/routes/contact/+page.svelte`
|
|
51
|
+
- `src/routes/posts/+page.svelte`
|
|
52
|
+
- `src/routes/privacy-rights/+page.svelte`
|
|
53
|
+
- Bumped project version to `v1.25.7`.
|
|
54
|
+
- Updated dependencies:
|
|
55
|
+
- `autoprefixer` `^10.4.21` β `^10.4.22`
|
|
56
|
+
- `browserslist` `^4.27.0` β `^4.28.0`
|
|
57
|
+
- `svelte` `5.43.3` β `5.43.6`
|
|
58
|
+
- `svelte-check` `^4.3.3` β `^4.3.4`
|
|
59
|
+
- `posthog-js` `^1.285.1` β `^1.290.0`
|
|
60
|
+
- `vite` `^7.1.12` β `^7.2.2`
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## [1.25.6] - 2025-11-04
|
|
65
|
+
|
|
66
|
+
### Security
|
|
67
|
+
|
|
68
|
+
- Hardened `Content-Security-Policy (CSP)` in `hooks.server.js`:
|
|
69
|
+
- Environment-specific policies for `production`, `audit`, `dev`, and `test`
|
|
70
|
+
- Added real CSP reporting endpoint (`csp.netwk.pro`) in production
|
|
71
|
+
- Report-only mode enabled in non-prod for safer diagnostics
|
|
72
|
+
- Added `/api/mock-csp` endpoint to capture and log CSP violation reports in non-prod environments
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- Updated `README.md` with detailed explanation of the CSP enforcement strategy and future nonce-based roadmap
|
|
77
|
+
- Moved inline styles from `Badges.svelte` and `Logo.svelte` to external stylesheet (`default.css`)
|
|
78
|
+
- Regenerated `global.min.css` using LightningCSS to reflect updated external styles
|
|
79
|
+
- Bumped project version to `v1.25.6`
|
|
80
|
+
- Updated dependencies:
|
|
81
|
+
- `@eslint/js` `^9.39.0` β `^9.39.1`
|
|
82
|
+
- `eslint` `^9.39.0` β `^9.39.1`
|
|
83
|
+
- `eslint-plugin-jsdoc` `^61.1.11` β `^61.1.12`
|
|
84
|
+
- `svelte` `5.43.2` β `5.43.3`
|
|
85
|
+
- `posthog-js` `^1.284.0` β `^1.285.1`
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- Updated `probely-scan.yml` GitHub workflow to utilize the correct API endpoint and cURL requests.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
25
93
|
## [1.25.5] - 2025-11-03
|
|
26
94
|
|
|
27
95
|
### Added
|
|
@@ -1702,7 +1770,9 @@ This enables analytics filtering and CSP hardening for the audit environment.
|
|
|
1702
1770
|
|
|
1703
1771
|
<!-- Link references -->
|
|
1704
1772
|
|
|
1705
|
-
[Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.25.
|
|
1773
|
+
[Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.25.7...HEAD
|
|
1774
|
+
[1.25.7]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.7
|
|
1775
|
+
[1.25.6]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.6
|
|
1706
1776
|
[1.25.5]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.5
|
|
1707
1777
|
[1.25.4]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.4
|
|
1708
1778
|
[1.25.3]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.3
|
package/README.md
CHANGED
|
@@ -173,23 +173,55 @@ This project includes custom runtime configuration files for enhancing security,
|
|
|
173
173
|
|
|
174
174
|
### π `hooks.server.js`
|
|
175
175
|
|
|
176
|
-
Located at `src/hooks.server.js`, this file
|
|
176
|
+
Located at `src/hooks.server.js`, this file dynamically injects security headers depending on the environment. It includes:
|
|
177
|
+
|
|
178
|
+
- A **Content Security Policy (CSP)** with environment-based directives:
|
|
179
|
+
- **Production/Audit**: Enforced, hardened CSP
|
|
180
|
+
- **Test/Dev**: Uses `Content-Security-Policy-Report-Only` for safe diagnostics
|
|
181
|
+
- A **Permissions Policy** that disables nonessential browser APIs
|
|
182
|
+
- Standard HTTP security headers:
|
|
183
|
+
- `X-Content-Type-Options`
|
|
184
|
+
- `X-Frame-Options`
|
|
185
|
+
- `Referrer-Policy`
|
|
186
|
+
- `Strict-Transport-Security` (in non-test environments)
|
|
177
187
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### βοΈ CSP Behavior by Environment
|
|
191
|
+
|
|
192
|
+
| Environment | Header | Analytics Enabled | CSP Reporting |
|
|
193
|
+
| ------------ | ------------------------------------- | ----------------- | ------------- |
|
|
194
|
+
| `production` | `Content-Security-Policy` | β
Yes | β
Yes |
|
|
195
|
+
| `audit` | `Content-Security-Policy` | β No | β No |
|
|
196
|
+
| `dev` | `Content-Security-Policy-Report-Only` | β No | β
Yes (mock) |
|
|
197
|
+
| `test` | `Content-Security-Policy-Report-Only` | β No | β
Yes (mock) |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### π§ͺ Reporting & Debugging
|
|
181
202
|
|
|
182
|
-
|
|
203
|
+
- In **non-production environments**, CSP headers are set to `report-only` mode.
|
|
204
|
+
- Violations are POSTed to `/api/mock-csp`, which logs reports to the console.
|
|
205
|
+
- In **production**, violations are sent to a real CSP collection endpoint (`https://csp.netwk.pro/.netlify/functions/csp-report`).
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### β οΈ Current Trade-Off
|
|
210
|
+
|
|
211
|
+
> Due to limitations in PostHog and certain SvelteKit internals, the current policy allows `'unsafe-inline'` for scripts and styles. A strict CSP using nonces was previously attempted but blocked critical functionality.
|
|
212
|
+
|
|
213
|
+
---
|
|
183
214
|
|
|
184
|
-
|
|
215
|
+
### π Future Improvements (Strict CSP Plan)
|
|
185
216
|
|
|
186
|
-
To
|
|
217
|
+
To move toward a strict, nonce-based CSP:
|
|
187
218
|
|
|
188
|
-
1.
|
|
189
|
-
2.
|
|
190
|
-
3.
|
|
219
|
+
1. Ensure **all inline scripts** are updated to include injected nonces (`nonce="%nonce%"`)
|
|
220
|
+
2. Confirm **PostHog** or future analytics platforms support nonced or external scripts/stylesheets
|
|
221
|
+
3. Review and refactor any components that rely on dynamic `style=` or `<style>` blocks without support for CSP nonces
|
|
222
|
+
4. Move third-party scripts out of inline `<script>` tags where possible
|
|
191
223
|
|
|
192
|
-
|
|
224
|
+
> βΉοΈ Nonce-based CSP is the most secure long-term path but requires cooperation from all dependencies β and possibly upstream fixes to analytics tooling or SvelteKit itself.
|
|
193
225
|
|
|
194
226
|
|
|
195
227
|
|
package/cspell.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@networkpro/web",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.25.
|
|
4
|
+
"version": "1.25.7",
|
|
5
5
|
"description": "Locking Down Networks, Unlocking Confidenceβ’ | Security, Networking, Privacy β Network Pro Strategies",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"advisory",
|
|
@@ -85,13 +85,13 @@
|
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"dompurify": "^3.3.0",
|
|
88
|
-
"posthog-js": "^1.
|
|
88
|
+
"posthog-js": "^1.290.0",
|
|
89
89
|
"semver": "^7.7.3",
|
|
90
|
-
"svelte": "5.43.
|
|
90
|
+
"svelte": "5.43.6"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@eslint/compat": "^1.4.1",
|
|
94
|
-
"@eslint/js": "^9.39.
|
|
94
|
+
"@eslint/js": "^9.39.1",
|
|
95
95
|
"@lhci/cli": "^0.15.1",
|
|
96
96
|
"@playwright/test": "^1.56.1",
|
|
97
97
|
"@sveltejs/adapter-vercel": "^6.1.1",
|
|
@@ -100,11 +100,11 @@
|
|
|
100
100
|
"@testing-library/jest-dom": "^6.9.1",
|
|
101
101
|
"@testing-library/svelte": "^5.2.8",
|
|
102
102
|
"@vitest/coverage-v8": "3.2.4",
|
|
103
|
-
"autoprefixer": "^10.4.
|
|
104
|
-
"browserslist": "^4.
|
|
105
|
-
"eslint": "^9.39.
|
|
103
|
+
"autoprefixer": "^10.4.22",
|
|
104
|
+
"browserslist": "^4.28.0",
|
|
105
|
+
"eslint": "^9.39.1",
|
|
106
106
|
"eslint-config-prettier": "^10.1.8",
|
|
107
|
-
"eslint-plugin-jsdoc": "^61.1.
|
|
107
|
+
"eslint-plugin-jsdoc": "^61.1.12",
|
|
108
108
|
"eslint-plugin-svelte": "^3.13.0",
|
|
109
109
|
"globals": "^16.5.0",
|
|
110
110
|
"jsdom": "26.1.0",
|
|
@@ -121,11 +121,11 @@
|
|
|
121
121
|
"stylelint-config-html": "^1.1.0",
|
|
122
122
|
"stylelint-config-recommended": "^17.0.0",
|
|
123
123
|
"stylelint-order": "^7.0.0",
|
|
124
|
-
"svelte-check": "^4.3.
|
|
124
|
+
"svelte-check": "^4.3.4",
|
|
125
125
|
"svelte-eslint-parser": "^1.4.0",
|
|
126
126
|
"svelte-preprocess": "^6.0.3",
|
|
127
127
|
"typescript": "^5.9.3",
|
|
128
|
-
"vite": "^7.
|
|
128
|
+
"vite": "^7.2.2",
|
|
129
129
|
"vite-plugin-devtools-json": "^1.0.0",
|
|
130
130
|
"vite-plugin-lightningcss": "^0.0.5",
|
|
131
131
|
"vite-tsconfig-paths": "^5.1.4",
|
package/src/hooks.server.js
CHANGED
|
@@ -6,6 +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 { isProbelyScanner } from '$lib/security/probely.js';
|
|
9
10
|
import { detectEnvironment } from '$lib/utils/env.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -13,30 +14,41 @@ import { detectEnvironment } from '$lib/utils/env.js';
|
|
|
13
14
|
* @type {import('@sveltejs/kit').Handle}
|
|
14
15
|
*/
|
|
15
16
|
export async function handle({ event, resolve }) {
|
|
17
|
+
/**
|
|
18
|
+
* π Probely scanner allowlisting
|
|
19
|
+
* - Robust UA check (caseβinsensitive)
|
|
20
|
+
* - Normalized XβForwardedβFor parsing
|
|
21
|
+
* - Avoids false positives
|
|
22
|
+
* @see https://help.probely.com/en/articles/5112461/
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** @type {string} */
|
|
26
|
+
const userAgent = event.request.headers.get('user-agent') || '';
|
|
27
|
+
|
|
28
|
+
/** @type {string} */
|
|
29
|
+
const remoteIp =
|
|
30
|
+
event.request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '';
|
|
31
|
+
|
|
32
|
+
const isProbely = isProbelyScanner({ ua: userAgent, ip: remoteIp });
|
|
33
|
+
|
|
34
|
+
if (isProbely) {
|
|
35
|
+
console.info('[Probely Bypass] Matched scanner request:', {
|
|
36
|
+
ip: remoteIp,
|
|
37
|
+
ua: userAgent,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
16
40
|
const response = await resolve(event);
|
|
17
41
|
|
|
18
42
|
const env = detectEnvironment(event.url.hostname);
|
|
19
|
-
const { isAudit, isDebug, isTest, isProd
|
|
20
|
-
|
|
21
|
-
// Show logs in dev only
|
|
22
|
-
if (isDebug) {
|
|
23
|
-
console.log('[CSP Debug ENV]', {
|
|
24
|
-
mode,
|
|
25
|
-
effective,
|
|
26
|
-
hostname: event.url.hostname,
|
|
27
|
-
isAudit,
|
|
28
|
-
isTest,
|
|
29
|
-
isProd,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
43
|
+
const { isAudit, isDebug, isTest, isProd } = env;
|
|
32
44
|
|
|
33
|
-
// Determine report URI
|
|
34
45
|
const reportUri =
|
|
35
46
|
isProd && !isTest && !isAudit
|
|
36
47
|
? 'https://csp.netwk.pro/.netlify/functions/csp-report'
|
|
37
48
|
: '/api/mock-csp';
|
|
38
49
|
|
|
39
|
-
|
|
50
|
+
console.log('[CSP] Report URI set to:', reportUri);
|
|
51
|
+
|
|
40
52
|
const cspDirectives = [
|
|
41
53
|
"default-src 'self';",
|
|
42
54
|
"script-src 'self' 'unsafe-inline' https://us.i.posthog.com https://us-assets.i.posthog.com;",
|
|
@@ -69,8 +81,10 @@ export async function handle({ event, resolve }) {
|
|
|
69
81
|
cspDirectives[4] = "connect-src 'self';";
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
// π
|
|
73
|
-
|
|
84
|
+
// π Add reporting for environments that support it
|
|
85
|
+
const shouldReport = !isAudit && !isTest;
|
|
86
|
+
|
|
87
|
+
if (shouldReport) {
|
|
74
88
|
cspDirectives.push(`report-uri ${reportUri};`, 'report-to csp-endpoint;');
|
|
75
89
|
|
|
76
90
|
response.headers.set(
|
|
@@ -84,8 +98,20 @@ export async function handle({ event, resolve }) {
|
|
|
84
98
|
);
|
|
85
99
|
}
|
|
86
100
|
|
|
87
|
-
// β
Apply
|
|
88
|
-
|
|
101
|
+
// β
Apply CSP β enforce in prod or audit, report-only in dev/test
|
|
102
|
+
const cspHeader =
|
|
103
|
+
(isProd || isAudit) && !isTest
|
|
104
|
+
? 'Content-Security-Policy'
|
|
105
|
+
: 'Content-Security-Policy-Report-Only';
|
|
106
|
+
|
|
107
|
+
response.headers.set(cspHeader, cspDirectives.join(' '));
|
|
108
|
+
|
|
109
|
+
// Log applied CSP headers in debug/audit/test
|
|
110
|
+
if (isDebug || isAudit) {
|
|
111
|
+
console.info(`[CSP] Applied header: ${cspHeader}`);
|
|
112
|
+
console.info(`[CSP] Policy:`, cspDirectives.join(' '));
|
|
113
|
+
console.info(`[CSP] Reporting to: ${reportUri}`);
|
|
114
|
+
}
|
|
89
115
|
|
|
90
116
|
// Standard security headers
|
|
91
117
|
response.headers.set(
|
|
@@ -29,8 +29,6 @@ This file is part of Network Pro.
|
|
|
29
29
|
* @property {string} src - The source URL of the badge image.
|
|
30
30
|
* @property {string} alt - The alt text for the badge image.
|
|
31
31
|
* @property {string} [class] - The CSS class for styling the badge (optional).
|
|
32
|
-
* @property {string} width - The width of the badge (CSS value).
|
|
33
|
-
* @property {string} height - The height of the badge (CSS value).
|
|
34
32
|
*/
|
|
35
33
|
|
|
36
34
|
/**
|
|
@@ -42,15 +40,13 @@ This file is part of Network Pro.
|
|
|
42
40
|
href: ccbyLink,
|
|
43
41
|
src: ccBadge,
|
|
44
42
|
alt: 'Creative Commons BY',
|
|
45
|
-
|
|
46
|
-
height: '24px',
|
|
43
|
+
class: 'badge badge--cc',
|
|
47
44
|
},
|
|
48
45
|
{
|
|
49
46
|
href: gplLink,
|
|
50
47
|
src: gplBadge,
|
|
51
48
|
alt: 'GPL 3.0 or Later',
|
|
52
|
-
|
|
53
|
-
height: '24px',
|
|
49
|
+
class: 'badge badge--gpl',
|
|
54
50
|
},
|
|
55
51
|
];
|
|
56
52
|
</script>
|
|
@@ -68,8 +64,7 @@ This file is part of Network Pro.
|
|
|
68
64
|
loading="lazy"
|
|
69
65
|
src={badge.src}
|
|
70
66
|
alt={badge.alt}
|
|
71
|
-
|
|
72
|
-
style:height={badge.height} />
|
|
67
|
+
class={badge.class} />
|
|
73
68
|
</a>
|
|
74
69
|
</td>
|
|
75
70
|
{/each}
|
|
@@ -7,9 +7,12 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== -->
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
|
+
import { CONSTANTS } from '$lib';
|
|
10
11
|
// Import logo images
|
|
11
12
|
import { logoPng, logoWbp } from '$lib';
|
|
12
13
|
|
|
14
|
+
const { COMPANY_INFO } = CONSTANTS;
|
|
15
|
+
|
|
13
16
|
/**
|
|
14
17
|
* Decoding mode for the image.
|
|
15
18
|
* @type {"sync" | "async" | "auto"}
|
|
@@ -23,16 +26,16 @@ This file is part of Network Pro.
|
|
|
23
26
|
export let loading = 'eager';
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
|
-
* CSS
|
|
29
|
+
* Optional extra CSS classes for the logo image.
|
|
27
30
|
* @type {string}
|
|
28
31
|
*/
|
|
29
|
-
export let className = '
|
|
32
|
+
export let className = '';
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
35
|
* Alt text for the logo image.
|
|
33
36
|
* @type {string}
|
|
34
37
|
*/
|
|
35
|
-
export let alt =
|
|
38
|
+
export let alt = COMPANY_INFO.NAME;
|
|
36
39
|
|
|
37
40
|
/**
|
|
38
41
|
* First part of the company slogan.
|
|
@@ -58,18 +61,6 @@ This file is part of Network Pro.
|
|
|
58
61
|
*/
|
|
59
62
|
export let showTagline = true;
|
|
60
63
|
|
|
61
|
-
/**
|
|
62
|
-
* Width of the logo in pixels.
|
|
63
|
-
* @type {string}
|
|
64
|
-
*/
|
|
65
|
-
export let width = '250px';
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Height of the logo in pixels.
|
|
69
|
-
* @type {string}
|
|
70
|
-
*/
|
|
71
|
-
export let height = '250px';
|
|
72
|
-
|
|
73
64
|
/**
|
|
74
65
|
* Fetch priority for the logo image.
|
|
75
66
|
* @type {"high" | "low" | "auto"}
|
|
@@ -83,12 +74,10 @@ This file is part of Network Pro.
|
|
|
83
74
|
<img
|
|
84
75
|
{decoding}
|
|
85
76
|
{loading}
|
|
86
|
-
class={className}
|
|
77
|
+
class={`logo${className ? ` ${className}` : ''}`}
|
|
87
78
|
src={logoPng}
|
|
88
79
|
{alt}
|
|
89
|
-
{fetchpriority}
|
|
90
|
-
style:width
|
|
91
|
-
style:height />
|
|
80
|
+
{fetchpriority} />
|
|
92
81
|
</picture>
|
|
93
82
|
|
|
94
83
|
{#if showSlogan}
|
|
@@ -48,38 +48,9 @@ This file is part of Network Pro.
|
|
|
48
48
|
{#if show}
|
|
49
49
|
<button
|
|
50
50
|
id="pwa-install"
|
|
51
|
-
class="install-button"
|
|
51
|
+
class="pwa-install-button"
|
|
52
52
|
on:click={promptInstall}
|
|
53
53
|
transition:fade={{ duration: 600 }}>
|
|
54
54
|
Install App
|
|
55
55
|
</button>
|
|
56
56
|
{/if}
|
|
57
|
-
|
|
58
|
-
<style>
|
|
59
|
-
.install-button {
|
|
60
|
-
display: block;
|
|
61
|
-
padding: 0.5rem 1rem;
|
|
62
|
-
border: none;
|
|
63
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
64
|
-
font-size: 1rem;
|
|
65
|
-
font-weight: bold;
|
|
66
|
-
color: #000;
|
|
67
|
-
background-color: #ffc627;
|
|
68
|
-
transition: background-color 0.2s ease-in-out;
|
|
69
|
-
border-radius: 6px;
|
|
70
|
-
cursor: pointer;
|
|
71
|
-
font-family: inherit;
|
|
72
|
-
margin-left: auto;
|
|
73
|
-
margin-right: auto;
|
|
74
|
-
margin-top: 1rem;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.install-button:hover {
|
|
78
|
-
background-color: #e6b300;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.install-button:focus {
|
|
82
|
-
outline: 2px solid #000;
|
|
83
|
-
outline-offset: 2px;
|
|
84
|
-
}
|
|
85
|
-
</style>
|
|
@@ -9,7 +9,7 @@ This file is part of Network Pro.
|
|
|
9
9
|
<script>
|
|
10
10
|
import { onMount } from 'svelte';
|
|
11
11
|
import { redirectWithBrowserAwareness } from '$lib/utils/redirect.js';
|
|
12
|
-
import FullWidthSection from '$lib/components
|
|
12
|
+
import { FullWidthSection } from '$lib/components';
|
|
13
13
|
|
|
14
14
|
export let to;
|
|
15
15
|
export let rel = ''; // Accepts optional rel value
|
|
@@ -16,7 +16,7 @@ This file is part of Network Pro.
|
|
|
16
16
|
|
|
17
17
|
<!-- BEGIN FOSS FEATURES -->
|
|
18
18
|
{#if features && features.length > 0}
|
|
19
|
-
<ul>
|
|
19
|
+
<ul class="foss-features">
|
|
20
20
|
{#each features as feature, index}
|
|
21
21
|
<li class="emoji">
|
|
22
22
|
{#if index === 0}
|
|
@@ -40,16 +40,3 @@ This file is part of Network Pro.
|
|
|
40
40
|
{/if}
|
|
41
41
|
|
|
42
42
|
<!-- END FOSS FEATURES -->
|
|
43
|
-
|
|
44
|
-
<style>
|
|
45
|
-
ul {
|
|
46
|
-
margin: 0;
|
|
47
|
-
list-style-type: none;
|
|
48
|
-
padding-left: 0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
ul li {
|
|
52
|
-
font-weight: 600;
|
|
53
|
-
margin-bottom: 0.5em;
|
|
54
|
-
}
|
|
55
|
-
</style>
|
|
@@ -56,12 +56,6 @@ This file is part of Network Pro.
|
|
|
56
56
|
*/
|
|
57
57
|
const loading = 'lazy';
|
|
58
58
|
|
|
59
|
-
/**
|
|
60
|
-
* CSS class for styled horizontal rule
|
|
61
|
-
* @type {string}
|
|
62
|
-
*/
|
|
63
|
-
const hrStyle = 'hr-styled';
|
|
64
|
-
|
|
65
59
|
/**
|
|
66
60
|
* Navigation links for the page
|
|
67
61
|
* @type {Array<{
|
|
@@ -241,7 +235,7 @@ This file is part of Network Pro.
|
|
|
241
235
|
|
|
242
236
|
<div class="spacer"></div>
|
|
243
237
|
|
|
244
|
-
<hr class=
|
|
238
|
+
<hr class="hr-styled" />
|
|
245
239
|
|
|
246
240
|
<div class="spacer"></div>
|
|
247
241
|
|
|
@@ -21,7 +21,7 @@ This file is part of Network Pro.
|
|
|
21
21
|
* URL to Terms of Use page, using the base path
|
|
22
22
|
* @type {string}
|
|
23
23
|
*/
|
|
24
|
-
const termsLink = `${base}/terms-of-use
|
|
24
|
+
const termsLink = `${base}/terms-of-use`;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Markdown version of the Terms and Conditions document
|
|
@@ -6,8 +6,6 @@ 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
|
-
<!-- cspell:ignore tandc -->
|
|
10
|
-
|
|
11
9
|
<script>
|
|
12
10
|
import { base } from '$app/paths';
|
|
13
11
|
import { CONSTANTS } from '$lib';
|
|
@@ -15,7 +13,7 @@ This file is part of Network Pro.
|
|
|
15
13
|
// Log the base path to verify its value
|
|
16
14
|
//console.log("Base path:", base);
|
|
17
15
|
|
|
18
|
-
console.log(CONSTANTS.COMPANY_INFO.APP_NAME);
|
|
16
|
+
//console.log(CONSTANTS.COMPANY_INFO.APP_NAME);
|
|
19
17
|
|
|
20
18
|
const { COMPANY_INFO, PAGE, NAV } = CONSTANTS;
|
|
21
19
|
|
|
@@ -227,11 +225,12 @@ This file is part of Network Pro.
|
|
|
227
225
|
<p class="bquote">
|
|
228
226
|
<strong>Note:</strong> For more details regarding our privacy practices,
|
|
229
227
|
refer to our
|
|
230
|
-
<a
|
|
231
|
-
|
|
232
|
-
<a
|
|
233
|
-
>Legal, Copyright, and Licensing</a>
|
|
228
|
+
<a href={privacyLink} target={PAGE.SELF}>Privacy Policy</a>. For licensing
|
|
229
|
+
terms and content usage rights, please visit our
|
|
230
|
+
<a href={licenseLink} target={PAGE.SELF}>Legal, Copyright, and Licensing</a>
|
|
234
231
|
page.
|
|
235
232
|
</p>
|
|
236
233
|
</section>
|
|
237
234
|
<!-- END TERMS OF USE -->
|
|
235
|
+
|
|
236
|
+
<!-- cspell:ignore tandc -->
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
src/lib/security/probely.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 probely.js
|
|
11
|
+
* @description Determines whether a request originates from the Probely
|
|
12
|
+
* security scanner, based on its User-Agent string or known source IP address.
|
|
13
|
+
* @module tests/security
|
|
14
|
+
* @author Scott Lopez
|
|
15
|
+
* @updated 2025-11-11
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** @typedef {{ ua: string, ip: string }} ScannerInput */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if a request is likely from Probely.
|
|
22
|
+
* @param {ScannerInput} input
|
|
23
|
+
* @returns {boolean} - True if the request matches Probelyβs fingerprint.
|
|
24
|
+
*/
|
|
25
|
+
export function isProbelyScanner({ ua, ip }) {
|
|
26
|
+
const PROBELY_UA_FRAGMENT = 'probelyspdr/';
|
|
27
|
+
const PROBELY_IPS = [
|
|
28
|
+
'18.235.241.170',
|
|
29
|
+
'52.65.214.19',
|
|
30
|
+
'13.237.213.25',
|
|
31
|
+
'52.19.40.38',
|
|
32
|
+
'44.205.45.120',
|
|
33
|
+
'3.104.172.219',
|
|
34
|
+
'13.211.189.220',
|
|
35
|
+
'52.16.191.244',
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
if (!ua && !ip) return false;
|
|
39
|
+
|
|
40
|
+
const normalizedUA = ua?.toLowerCase() ?? '';
|
|
41
|
+
const normalizedIP = ip?.trim() ?? '';
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
normalizedUA.includes(PROBELY_UA_FRAGMENT) ||
|
|
45
|
+
PROBELY_IPS.includes(normalizedIP)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -396,6 +396,8 @@ footer .container {
|
|
|
396
396
|
|
|
397
397
|
.logo {
|
|
398
398
|
display: block;
|
|
399
|
+
width: var(--logo-width, 250px);
|
|
400
|
+
height: var(--logo-height, 250px);
|
|
399
401
|
margin-left: auto;
|
|
400
402
|
margin-right: auto;
|
|
401
403
|
}
|
|
@@ -709,3 +711,58 @@ footer .container {
|
|
|
709
711
|
#toc a:hover {
|
|
710
712
|
text-decoration: underline;
|
|
711
713
|
}
|
|
714
|
+
|
|
715
|
+
.badge {
|
|
716
|
+
display: inline-block;
|
|
717
|
+
height: 24px;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.badge--cc {
|
|
721
|
+
width: 160px;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.badge--gpl {
|
|
725
|
+
width: 120px;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/* From PWAInstallButton.svelte */
|
|
729
|
+
|
|
730
|
+
.pwa-install-button {
|
|
731
|
+
display: block;
|
|
732
|
+
padding: 0.5rem 1rem;
|
|
733
|
+
border: none;
|
|
734
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
735
|
+
font-size: 1rem;
|
|
736
|
+
font-weight: bold;
|
|
737
|
+
color: #000;
|
|
738
|
+
background-color: #ffc627;
|
|
739
|
+
transition: background-color 0.2s ease-in-out;
|
|
740
|
+
border-radius: 6px;
|
|
741
|
+
cursor: pointer;
|
|
742
|
+
font-family: inherit;
|
|
743
|
+
margin-left: auto;
|
|
744
|
+
margin-right: auto;
|
|
745
|
+
margin-top: 1rem;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.pwa-install-button:hover {
|
|
749
|
+
background-color: #e6b300;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.pwa-install-button:focus {
|
|
753
|
+
outline: 2px solid #000;
|
|
754
|
+
outline-offset: 2px;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/* From FossFeatures.svelte */
|
|
758
|
+
|
|
759
|
+
.foss-features {
|
|
760
|
+
margin: 0;
|
|
761
|
+
list-style-type: none;
|
|
762
|
+
padding-left: 0;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.foss-features li {
|
|
766
|
+
font-weight: 600;
|
|
767
|
+
margin-bottom: 0.5em;
|
|
768
|
+
}
|
|
@@ -3,4 +3,4 @@ Copyright Β© 2025 Network Pro Strategies (Network Proβ’)
|
|
|
3
3
|
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
4
4
|
This file is part of Network Pro.
|
|
5
5
|
========================================================================== */
|
|
6
|
-
html{-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{margin:.67em 0;font-size:2em}hr{box-sizing:content-box}pre{font-family:monospace;font-size:1em}a{background-color:#0000}abbr[title]{border-bottom:none;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted buttontext}fieldset{padding:.35em .75em .625em}legend{color:inherit;box-sizing:border-box;white-space:normal;max-width:100%;padding:0;display:table}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}details{display:block}summary{display:list-item}template{display:none}html{color:#222;scroll-behavior:smooth;font-size:1em;line-height:1.4}::-moz-selection{text-shadow:none;background:#191919}::selection{text-shadow:none;background:#191919}hr{border:0;border-top:1px solid #ccc;height:1px;margin:1em 0;padding:0;display:block;overflow:visible}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}body{color:#fafafa;background-color:#191919;margin:10px;font-family:Arial,Helvetica,sans-serif}a{text-decoration:none}a:link{color:#ffc627}a:hover,a:active{color:#ffc627;text-decoration:underline}a:focus{color:#111;background-color:#ffc627}a:visited,a:visited:hover{color:#cba557}a:visited:focus,a:visited:focus-visible{color:#111!important}.hidden,[hidden]{display:none!important}.visually-hidden{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visually-hidden.focusable:active,.visually-hidden.focusable:focus{clip:auto;width:auto;height:auto;white-space:inherit;margin:0;position:static;overflow:visible}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}@media print{*,:before,:after{color:#000!important;box-shadow:none!important;text-shadow:none!important;background:#fff!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^=\#]:after,a[href^=javascript\:]:after{content:""}pre{white-space:pre-wrap!important}pre,blockquote{break-inside:avoid;border:1px solid #999}tr,img{break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{break-after:avoid}}.full-width-section{background-position:50%;background-size:cover;width:100%;max-width:1920px;margin:0 auto}.container{max-width:1200px;margin:0 auto;padding:0 12px}.readable{max-width:900px;margin:0 auto}header,footer{width:100%}header .container,footer .container{max-width:1200px;margin:0 auto;padding:20px 12px}.gh{border-collapse:collapse;border-spacing:0;margin:0 auto}.gh td,.gh th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.gh .gh-tcell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.gh,.gh col{width:auto!important}.gh-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.soc{border-collapse:collapse;border-spacing:0;margin:0 auto}.soc td,.soc th{border-collapse:collapse;word-break:normal;padding:8px;overflow:hidden}.soc .soc-fa{text-align:center;vertical-align:middle}@media screen and (width<=767px){.soc,.soc col{width:auto!important}.soc-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.foss{border-collapse:collapse;border-spacing:0}.foss td,.foss th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.foss .foss-cell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.foss,.foss col{width:auto!important}.foss-wrap{-webkit-overflow-scrolling:touch;overflow-x:auto}}.bnav{text-align:center;border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav td,.bnav th{text-align:center;vertical-align:middle;word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav .bnav-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav,.bnav col{width:auto!important}.bnav-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.bnav2{border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav2 td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav2 th{word-break:normal;border-style:none;padding:12px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.bnav2 .bnav2-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav2,.bnav2 col{width:auto!important}.bnav2-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.pgp{border-collapse:collapse;border-spacing:0;margin:0 auto}.pgp td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp th{word-break:normal;border:1px solid #000;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp .pgp-col1{text-align:right;vertical-align:middle;padding-right:1rem}.pgp .pgp-col2{text-align:left;vertical-align:middle;padding-left:1rem}@media screen and (width<=767px){.pgp,.pgp col{width:auto!important}.pgp-wrap{-webkit-overflow-scrolling:touch;margin:2rem 0 auto;overflow-x:auto}}#service-summary{color:#e6e6e6;margin-top:2rem;margin-bottom:2.5rem}.service-table{color:#e6e6e6;border-collapse:collapse;background-color:#191919;width:100%;font-size:.95rem}.service-table th,.service-table td{text-align:left;vertical-align:top;border-bottom:1px solid #333;padding:.75rem 1rem}.service-table th{color:#ffc627;text-transform:uppercase;background-color:#222;font-size:.85rem;font-weight:600}.service-table a{color:#ffc627;font-weight:500;text-decoration:none}.service-table a:hover{text-decoration:underline}.service-table tr:hover{background-color:#222;transition:background-color .3s,box-shadow .3s;box-shadow:0 0 10px 2px #ffc62740}.service-table tr.selected{background-color:#222;border-left:4px solid #ffc627;transition:background-color .3s,border-left-color .3s}.service-table tr.selected:hover{background-color:#252525;box-shadow:0 0 12px 3px #ffc62759}@media (width<=768px){.service-table{font-size:.9rem}.service-table th,.service-table td{padding:.5rem}}.logo{margin-left:auto;margin-right:auto;display:block}.index-title1{text-align:center;font-style:italic;font-weight:700}.index-title2{letter-spacing:-.015em;text-align:center;font-variant:small-caps;font-size:1.25rem;line-height:1.625rem}.index1{letter-spacing:-.035em;text-align:center;font-style:italic;font-weight:700;line-height:2.125rem}.index2{letter-spacing:-.035em;text-align:center;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.index3{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem}.index4{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem;text-decoration:underline}.subhead{letter-spacing:-.035em;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.bold{font-weight:700}.emphasis{font-style:italic}.uline{text-decoration:underline}.bolditalic{font-style:italic;font-weight:700}.bquote{border-left:3px solid #9e9e9e;margin-left:30px;padding-left:10px;font-style:italic}.small-text{font-size:.75rem;line-height:1.125rem}.large-text-center{text-align:center;font-size:1.25rem;line-height:1.75rem}.prewrap{white-space:pre-wrap;display:block}.hr-styled{width:75%;margin:auto}.center-text{text-align:center}.copyright{text-align:center;font-size:.75rem;line-height:1.125rem}.gold{color:#ffc627}.visited{color:#cba557}.goldseparator{color:#ffc627;margin:0 .5rem}.center-nav{text-align:center;padding:5px;font-size:1rem;line-height:1.5rem}.block{overflow-wrap:break-word;resize:none;white-space:normal;word-break:normal;background:0 0;border:none;border-radius:0;outline:none;width:100%;font-family:monospace;font-size:.875rem;line-height:1.125rem}.full-width-section.centered{flex-direction:column;justify-content:center;min-height:80vh;display:flex}.fingerprint{white-space:pre-line;font-family:monospace;display:block}.pgp-image{width:150px;height:150px}.spacer{margin:2rem 0}.separator{margin:0 .5rem}.emoji{margin-right:8px}.headline{margin-bottom:4px;font-style:italic;font-weight:700;display:block}.label{font-family:inherit;font-weight:700}.description{font-family:inherit;font-style:normal;font-weight:400;display:inline}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.pgp-entry{flex-wrap:wrap;align-items:center;gap:2rem;margin-bottom:2rem;display:flex}.pgp-text{flex:2;min-width:250px}.pgp-qr{flex:1;min-width:150px}.obtainium-direct-label{margin:.25rem 0 .75rem;font-weight:700}.obtainium-manual-label{margin-top:.75rem;font-weight:700}.obtainium-img{width:185px;height:55px;margin-bottom:.25rem}.obtainium-margin{margin-left:4px}.obtainium-fa-down{color:#ffc627;margin-left:4px}.obtainium-icon{width:50px;height:50px}.proton-img{width:168px;height:24px}.redirect-text{text-align:center;margin-top:4rem}.redirect-content{text-align:center;margin-top:2rem;font-family:system-ui,sans-serif}.loading-spinner{border:4px solid #ddd;border-top-color:#ffc627;border-radius:50%;width:48px;height:48px;margin:2rem auto;animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.cc-link{text-decoration:none}.cc-img{vertical-align:text-bottom;margin-left:3px;display:inline-block;height:18px!important}#toc ul{padding-left:1.5rem;list-style-type:disc}#toc a{color:var(--color-primary,#ffc627);text-decoration:none}#toc a:hover{text-decoration:underline}
|
|
6
|
+
html{-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{margin:.67em 0;font-size:2em}hr{box-sizing:content-box}pre{font-family:monospace;font-size:1em}a{background-color:#0000}abbr[title]{border-bottom:none;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted buttontext}fieldset{padding:.35em .75em .625em}legend{color:inherit;box-sizing:border-box;white-space:normal;max-width:100%;padding:0;display:table}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}details{display:block}summary{display:list-item}template{display:none}html{color:#222;scroll-behavior:smooth;font-size:1em;line-height:1.4}::-moz-selection{text-shadow:none;background:#191919}::selection{text-shadow:none;background:#191919}hr{border:0;border-top:1px solid #ccc;height:1px;margin:1em 0;padding:0;display:block;overflow:visible}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}body{color:#fafafa;background-color:#191919;margin:10px;font-family:Arial,Helvetica,sans-serif}a{text-decoration:none}a:link{color:#ffc627}a:hover,a:active{color:#ffc627;text-decoration:underline}a:focus{color:#111;background-color:#ffc627}a:visited,a:visited:hover{color:#cba557}a:visited:focus,a:visited:focus-visible{color:#111!important}.hidden,[hidden]{display:none!important}.visually-hidden{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visually-hidden.focusable:active,.visually-hidden.focusable:focus{clip:auto;width:auto;height:auto;white-space:inherit;margin:0;position:static;overflow:visible}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}@media print{*,:before,:after{color:#000!important;box-shadow:none!important;text-shadow:none!important;background:#fff!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^=\#]:after,a[href^=javascript\:]:after{content:""}pre{white-space:pre-wrap!important}pre,blockquote{break-inside:avoid;border:1px solid #999}tr,img{break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{break-after:avoid}}.full-width-section{background-position:50%;background-size:cover;width:100%;max-width:1920px;margin:0 auto}.container{max-width:1200px;margin:0 auto;padding:0 12px}.readable{max-width:900px;margin:0 auto}header,footer{width:100%}header .container,footer .container{max-width:1200px;margin:0 auto;padding:20px 12px}.gh{border-collapse:collapse;border-spacing:0;margin:0 auto}.gh td,.gh th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.gh .gh-tcell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.gh,.gh col{width:auto!important}.gh-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.soc{border-collapse:collapse;border-spacing:0;margin:0 auto}.soc td,.soc th{border-collapse:collapse;word-break:normal;padding:8px;overflow:hidden}.soc .soc-fa{text-align:center;vertical-align:middle}@media screen and (width<=767px){.soc,.soc col{width:auto!important}.soc-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.foss{border-collapse:collapse;border-spacing:0}.foss td,.foss th{border-collapse:collapse;word-break:normal;padding:10px 5px;overflow:hidden}.foss .foss-cell{text-align:center;vertical-align:middle}@media screen and (width<=767px){.foss,.foss col{width:auto!important}.foss-wrap{-webkit-overflow-scrolling:touch;overflow-x:auto}}.bnav{text-align:center;border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav td,.bnav th{text-align:center;vertical-align:middle;word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav .bnav-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav,.bnav col{width:auto!important}.bnav-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.bnav2{border-collapse:collapse;border-spacing:0;margin:0 auto}.bnav2 td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;font-weight:700;line-height:1.125rem;overflow:hidden}.bnav2 th{word-break:normal;border-style:none;padding:12px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.bnav2 .bnav2-cell{text-align:center;vertical-align:middle;align-content:center}@media screen and (width<=767px){.bnav2,.bnav2 col{width:auto!important}.bnav2-wrap{-webkit-overflow-scrolling:touch;margin:auto 0;overflow-x:auto}}.pgp{border-collapse:collapse;border-spacing:0;margin:0 auto}.pgp td{word-break:normal;border-style:none;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp th{word-break:normal;border:1px solid #000;padding:10px;font-size:.875rem;line-height:1.125rem;overflow:hidden}.pgp .pgp-col1{text-align:right;vertical-align:middle;padding-right:1rem}.pgp .pgp-col2{text-align:left;vertical-align:middle;padding-left:1rem}@media screen and (width<=767px){.pgp,.pgp col{width:auto!important}.pgp-wrap{-webkit-overflow-scrolling:touch;margin:2rem 0 auto;overflow-x:auto}}#service-summary{color:#e6e6e6;margin-top:2rem;margin-bottom:2.5rem}.service-table{color:#e6e6e6;border-collapse:collapse;background-color:#191919;width:100%;font-size:.95rem}.service-table th,.service-table td{text-align:left;vertical-align:top;border-bottom:1px solid #333;padding:.75rem 1rem}.service-table th{color:#ffc627;text-transform:uppercase;background-color:#222;font-size:.85rem;font-weight:600}.service-table a{color:#ffc627;font-weight:500;text-decoration:none}.service-table a:hover{text-decoration:underline}.service-table tr:hover{background-color:#222;transition:background-color .3s,box-shadow .3s;box-shadow:0 0 10px 2px #ffc62740}.service-table tr.selected{background-color:#222;border-left:4px solid #ffc627;transition:background-color .3s,border-left-color .3s}.service-table tr.selected:hover{background-color:#252525;box-shadow:0 0 12px 3px #ffc62759}@media (width<=768px){.service-table{font-size:.9rem}.service-table th,.service-table td{padding:.5rem}}.logo{width:var(--logo-width,250px);height:var(--logo-height,250px);margin-left:auto;margin-right:auto;display:block}.index-title1{text-align:center;font-style:italic;font-weight:700}.index-title2{letter-spacing:-.015em;text-align:center;font-variant:small-caps;font-size:1.25rem;line-height:1.625rem}.index1{letter-spacing:-.035em;text-align:center;font-style:italic;font-weight:700;line-height:2.125rem}.index2{letter-spacing:-.035em;text-align:center;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.index3{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem}.index4{letter-spacing:-.035em;text-align:center;font-size:1.5rem;line-height:1.75rem;text-decoration:underline}.subhead{letter-spacing:-.035em;font-variant:small-caps;font-size:1.5rem;line-height:1.75rem}.bold{font-weight:700}.emphasis{font-style:italic}.uline{text-decoration:underline}.bolditalic{font-style:italic;font-weight:700}.bquote{border-left:3px solid #9e9e9e;margin-left:30px;padding-left:10px;font-style:italic}.small-text{font-size:.75rem;line-height:1.125rem}.large-text-center{text-align:center;font-size:1.25rem;line-height:1.75rem}.prewrap{white-space:pre-wrap;display:block}.hr-styled{width:75%;margin:auto}.center-text{text-align:center}.copyright{text-align:center;font-size:.75rem;line-height:1.125rem}.gold{color:#ffc627}.visited{color:#cba557}.goldseparator{color:#ffc627;margin:0 .5rem}.center-nav{text-align:center;padding:5px;font-size:1rem;line-height:1.5rem}.block{overflow-wrap:break-word;resize:none;white-space:normal;word-break:normal;background:0 0;border:none;border-radius:0;outline:none;width:100%;font-family:monospace;font-size:.875rem;line-height:1.125rem}.full-width-section.centered{flex-direction:column;justify-content:center;min-height:80vh;display:flex}.fingerprint{white-space:pre-line;font-family:monospace;display:block}.pgp-image{width:150px;height:150px}.spacer{margin:2rem 0}.separator{margin:0 .5rem}.emoji{margin-right:8px}.headline{margin-bottom:4px;font-style:italic;font-weight:700;display:block}.label{font-family:inherit;font-weight:700}.description{font-family:inherit;font-style:normal;font-weight:400;display:inline}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.pgp-entry{flex-wrap:wrap;align-items:center;gap:2rem;margin-bottom:2rem;display:flex}.pgp-text{flex:2;min-width:250px}.pgp-qr{flex:1;min-width:150px}.obtainium-direct-label{margin:.25rem 0 .75rem;font-weight:700}.obtainium-manual-label{margin-top:.75rem;font-weight:700}.obtainium-img{width:185px;height:55px;margin-bottom:.25rem}.obtainium-margin{margin-left:4px}.obtainium-fa-down{color:#ffc627;margin-left:4px}.obtainium-icon{width:50px;height:50px}.proton-img{width:168px;height:24px}.redirect-text{text-align:center;margin-top:4rem}.redirect-content{text-align:center;margin-top:2rem;font-family:system-ui,sans-serif}.loading-spinner{border:4px solid #ddd;border-top-color:#ffc627;border-radius:50%;width:48px;height:48px;margin:2rem auto;animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.cc-link{text-decoration:none}.cc-img{vertical-align:text-bottom;margin-left:3px;display:inline-block;height:18px!important}#toc ul{padding-left:1.5rem;list-style-type:disc}#toc a{color:var(--color-primary,#ffc627);text-decoration:none}#toc a:hover{text-decoration:underline}.badge{height:24px;display:inline-block}.badge--cc{width:160px}.badge--gpl{width:120px}.pwa-install-button{color:#000;cursor:pointer;background-color:#ffc627;border:none;border-radius:6px;margin-top:1rem;margin-left:auto;margin-right:auto;padding:.5rem 1rem;font-family:inherit;font-size:1rem;font-weight:700;transition:background-color .2s ease-in-out;display:block;box-shadow:0 2px 4px #0003}.pwa-install-button:hover{background-color:#e6b300}.pwa-install-button:focus{outline-offset:2px;outline:2px solid #000}.foss-features{margin:0;padding-left:0;list-style-type:none}.foss-features li{margin-bottom:.5em;font-weight:600}
|
|
@@ -30,11 +30,9 @@ This file is part of Network Pro.
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
// fallback values if data.meta not set
|
|
33
|
-
const metaTitle =
|
|
34
|
-
data?.meta?.title || 'Security, Networking, Privacy β Network Proβ’';
|
|
33
|
+
const metaTitle = data?.meta?.title || 'Security, Networking, Privacy';
|
|
35
34
|
const metaDescription =
|
|
36
|
-
data?.meta?.description ||
|
|
37
|
-
'Locking Down Networks, Unlocking Confidenceβ’ | Security, Networking, Privacy β Network Pro Strategies';
|
|
35
|
+
data?.meta?.description || 'Locking Down Networks, Unlocking Confidenceβ’';
|
|
38
36
|
</script>
|
|
39
37
|
|
|
40
38
|
<!-- Injects proper <title> and <meta> tags -->
|
|
@@ -7,10 +7,19 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== */
|
|
8
8
|
|
|
9
9
|
/** @type {import('@sveltejs/kit').RequestHandler} */
|
|
10
|
-
export async function
|
|
11
|
-
|
|
10
|
+
export async function OPTIONS() {
|
|
11
|
+
return new Response(null, {
|
|
12
|
+
status: 204,
|
|
13
|
+
headers: {
|
|
14
|
+
'Access-Control-Allow-Origin': '*',
|
|
15
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
16
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
/** @type {import('@sveltejs/kit').RequestHandler} */
|
|
22
|
+
export async function POST({ request }) {
|
|
14
23
|
try {
|
|
15
24
|
const data = await request.json();
|
|
16
25
|
console.log('πΆ [Mock CSP] Payload:', data);
|
|
@@ -18,5 +27,12 @@ export async function POST({ request }) {
|
|
|
18
27
|
console.warn('β οΈ [Mock CSP] No JSON body provided.');
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
return new Response(null, {
|
|
30
|
+
return new Response(null, {
|
|
31
|
+
status: 204,
|
|
32
|
+
headers: {
|
|
33
|
+
'Access-Control-Allow-Origin': '*',
|
|
34
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
35
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
22
38
|
}
|
|
@@ -7,7 +7,7 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== -->
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
|
-
import RedirectPage from '$lib/components
|
|
10
|
+
import { RedirectPage } from '$lib/components';
|
|
11
11
|
import { appendUTM } from '$lib/utils/utm.js';
|
|
12
12
|
import { getUTMParams } from '$lib/utils/getUTMParams.js';
|
|
13
13
|
import { trackingEnabled } from '$lib/stores/trackingPreferences';
|
|
@@ -7,7 +7,7 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== -->
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
|
-
import RedirectPage from '$lib/components
|
|
10
|
+
import { RedirectPage } from '$lib/components';
|
|
11
11
|
import { appendUTM } from '$lib/utils/utm.js';
|
|
12
12
|
import { getUTMParams } from '$lib/utils/getUTMParams.js';
|
|
13
13
|
import { trackingEnabled } from '$lib/stores/trackingPreferences';
|
|
@@ -7,7 +7,7 @@ This file is part of Network Pro.
|
|
|
7
7
|
========================================================================== -->
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
|
-
import RedirectPage from '$lib/components
|
|
10
|
+
import { RedirectPage } from '$lib/components';
|
|
11
11
|
import { appendUTM } from '$lib/utils/utm.js';
|
|
12
12
|
import { getUTMParams } from '$lib/utils/getUTMParams.js';
|
|
13
13
|
import { trackingEnabled } from '$lib/stores/trackingPreferences';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* TEAM */
|
|
2
2
|
Organization: Network Pro Strategies (Network Proβ’)
|
|
3
3
|
URL: https://netwk.pro
|
|
4
|
-
Contact:
|
|
4
|
+
Contact: Scott Lopez (SunDevil311)
|
|
5
5
|
GitHub: https://github.com/netwk-pro
|
|
6
|
-
Email: support@
|
|
6
|
+
Email: support@netwk.pro
|
|
7
7
|
|
|
8
8
|
/* PGP */
|
|
9
9
|
PGP Fingerprint: 6590 B992 E2E3 EFF1 2738 7BCE 2AF0 93E9 DEC6 1BA0
|
|
10
|
-
PGP Key: https://netwk.pro/pgp/support@
|
|
10
|
+
PGP Key: https://netwk.pro/pgp/support@netwk.pro.asc
|
|
11
11
|
|
|
12
12
|
/* SITE */
|
|
13
13
|
Standards: HTML5, CSS3, SvelteKit, Markdown
|
|
@@ -15,7 +15,7 @@ Tools: GitHub, Material for MkDocs, Proton Mail
|
|
|
15
15
|
Hosting: Decentralized / CDN-backed static infrastructure
|
|
16
16
|
|
|
17
17
|
/* MOTTO */
|
|
18
|
-
"
|
|
18
|
+
"Locking Down Networks, Unlocking Confidenceβ’"
|
|
19
19
|
|
|
20
20
|
/* LAST UPDATED */
|
|
21
|
-
2025-
|
|
21
|
+
2025-11-09
|
package/static/robots.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
User-agent: *
|
|
10
10
|
|
|
11
|
-
# Disallow dev and CI/CD artifacts
|
|
11
|
+
# --- Disallow dev and CI/CD artifacts
|
|
12
12
|
Disallow: /tests/
|
|
13
13
|
Disallow: /scripts/
|
|
14
14
|
Disallow: /playwright-report/
|
|
@@ -34,7 +34,7 @@ Disallow: /privacy-rights
|
|
|
34
34
|
Disallow: /..404
|
|
35
35
|
Disallow: /status
|
|
36
36
|
|
|
37
|
-
# ---
|
|
37
|
+
# --- Service utilities or PWA
|
|
38
38
|
Disallow: /service-worker
|
|
39
39
|
Disallow: /service-worker.js
|
|
40
40
|
Disallow: /service-worker.d.ts
|
package/static/sitemap.xml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!-- Sitemap last updated 2025-11-
|
|
2
|
+
<!-- Sitemap last updated 2025-11-09 -->
|
|
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-
|
|
10
|
+
<lastmod>2025-11-09</lastmod>
|
|
11
11
|
|
|
12
12
|
<changefreq>weekly</changefreq>
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<loc>https://netwk.pro/services</loc>
|
|
21
21
|
|
|
22
|
-
<lastmod>2025-
|
|
22
|
+
<lastmod>2025-11-09</lastmod>
|
|
23
23
|
|
|
24
24
|
<changefreq>monthly</changefreq>
|
|
25
25
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
<loc>https://netwk.pro/foss</loc>
|
|
33
33
|
|
|
34
|
-
<lastmod>2025-
|
|
34
|
+
<lastmod>2025-11-09</lastmod>
|
|
35
35
|
|
|
36
36
|
<changefreq>monthly</changefreq>
|
|
37
37
|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
<loc>https://netwk.pro/about</loc>
|
|
45
45
|
|
|
46
|
-
<lastmod>2025-
|
|
46
|
+
<lastmod>2025-11-09</lastmod>
|
|
47
47
|
|
|
48
48
|
<changefreq>monthly</changefreq>
|
|
49
49
|
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
<loc>https://netwk.pro/privacy-dashboard</loc>
|
|
57
57
|
|
|
58
|
-
<lastmod>2025-
|
|
58
|
+
<lastmod>2025-11-09</lastmod>
|
|
59
59
|
|
|
60
60
|
<changefreq>monthly</changefreq>
|
|
61
61
|
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
|
|
68
68
|
<loc>https://netwk.pro/privacy</loc>
|
|
69
69
|
|
|
70
|
-
<lastmod>2025-
|
|
70
|
+
<lastmod>2025-11-09</lastmod>
|
|
71
71
|
|
|
72
72
|
<changefreq>monthly</changefreq>
|
|
73
73
|
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
<loc>https://netwk.pro/legal</loc>
|
|
81
81
|
|
|
82
|
-
<lastmod>2025-
|
|
82
|
+
<lastmod>2025-11-09</lastmod>
|
|
83
83
|
|
|
84
84
|
<changefreq>monthly</changefreq>
|
|
85
85
|
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
<loc>https://netwk.pro/terms-of-use</loc>
|
|
93
93
|
|
|
94
|
-
<lastmod>2025-
|
|
94
|
+
<lastmod>2025-11-09</lastmod>
|
|
95
95
|
|
|
96
96
|
<changefreq>monthly</changefreq>
|
|
97
97
|
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
|
|
104
104
|
<loc>https://netwk.pro/terms-conditions</loc>
|
|
105
105
|
|
|
106
|
-
<lastmod>2025-
|
|
106
|
+
<lastmod>2025-11-09</lastmod>
|
|
107
107
|
|
|
108
108
|
<changefreq>monthly</changefreq>
|
|
109
109
|
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
|
|
116
116
|
<loc>https://netwk.pro/pgp</loc>
|
|
117
117
|
|
|
118
|
-
<lastmod>2025-
|
|
118
|
+
<lastmod>2025-11-09</lastmod>
|
|
119
119
|
|
|
120
120
|
<changefreq>monthly</changefreq>
|
|
121
121
|
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
|
|
188
188
|
<loc>https://netwk.pro/.well-known/humans.txt</loc>
|
|
189
189
|
|
|
190
|
-
<lastmod>2025-
|
|
190
|
+
<lastmod>2025-11-09</lastmod>
|
|
191
191
|
|
|
192
192
|
<changefreq>yearly</changefreq>
|
|
193
193
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
tests/unit/server/security/probely.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
|
+
* @file probely.test.js
|
|
11
|
+
* @description Unit tests for the isProbelyRequest helper.
|
|
12
|
+
* Validates detection logic for identifying known Probely scanner traffic
|
|
13
|
+
* based on User-Agent and IP address heuristics.
|
|
14
|
+
* @module tests/unit/server/security
|
|
15
|
+
* @author Scott Lopez
|
|
16
|
+
* @updated 2025-11-11
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { isProbelyScanner } from '$lib/security/probely.js';
|
|
20
|
+
|
|
21
|
+
describe('isProbelyScanner', () => {
|
|
22
|
+
it('detects known user-agent', () => {
|
|
23
|
+
const ua =
|
|
24
|
+
'Mozilla/5.0 (compatible; +https://probely.com/sos) AppleWebKit/537.36 Chrome/104.0.0.0 Safari/537.36 ProbelySPDR/0.2.0';
|
|
25
|
+
expect(isProbelyScanner({ ua, ip: '' })).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('detects known IP', () => {
|
|
29
|
+
expect(isProbelyScanner({ ua: '', ip: '18.235.241.170' })).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('handles lowercase and spacing in IP', () => {
|
|
33
|
+
expect(
|
|
34
|
+
isProbelyScanner({ ua: 'probelyspdr/1.0', ip: ' 18.235.241.170 ' }),
|
|
35
|
+
).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns false for unrelated UA and IP', () => {
|
|
39
|
+
expect(
|
|
40
|
+
isProbelyScanner({
|
|
41
|
+
ua: 'Mozilla/5.0 (Linux x86_64)',
|
|
42
|
+
ip: '8.8.8.8',
|
|
43
|
+
}),
|
|
44
|
+
).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('handles missing headers safely', () => {
|
|
48
|
+
expect(isProbelyScanner({ ua: '', ip: '' })).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
package/vitest.config.server.js
CHANGED
|
@@ -22,10 +22,11 @@ export default defineConfig({
|
|
|
22
22
|
],
|
|
23
23
|
test: {
|
|
24
24
|
name: 'server',
|
|
25
|
+
globals: true,
|
|
25
26
|
environment: 'node',
|
|
26
27
|
include: ['tests/unit/server/**/*.test.{js,mjs}'],
|
|
27
28
|
exclude: ['tests/unit/**/*.svelte.test.{js,mjs}'],
|
|
28
|
-
|
|
29
|
+
reporter: ['default', 'json'],
|
|
29
30
|
testTimeout: 10000,
|
|
30
31
|
outputFile: {
|
|
31
32
|
json: './reports/server/results.json',
|