@networkpro/web 1.25.6 → 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/CHANGELOG.md CHANGED
@@ -22,6 +22,45 @@ 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
+
25
64
  ## [1.25.6] - 2025-11-04
26
65
 
27
66
  ### Security
@@ -1731,7 +1770,8 @@ This enables analytics filtering and CSP hardening for the audit environment.
1731
1770
 
1732
1771
  <!-- Link references -->
1733
1772
 
1734
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.25.6...HEAD
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
1735
1775
  [1.25.6]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.6
1736
1776
  [1.25.5]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.5
1737
1777
  [1.25.4]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.4
package/cspell.json CHANGED
@@ -69,12 +69,14 @@
69
69
  "precaching",
70
70
  "prefs",
71
71
  "Probely",
72
+ "probelyspdr",
72
73
  "publickey",
73
74
  "reconsent",
74
75
  "sarif",
75
76
  "serv",
76
77
  "shizuku",
77
78
  "SIEM",
79
+ "SPDR",
78
80
  "SPDY",
79
81
  "squircle",
80
82
  "stylelintignore",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.25.6",
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,9 +85,9 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "dompurify": "^3.3.0",
88
- "posthog-js": "^1.285.1",
88
+ "posthog-js": "^1.290.0",
89
89
  "semver": "^7.7.3",
90
- "svelte": "5.43.3"
90
+ "svelte": "5.43.6"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@eslint/compat": "^1.4.1",
@@ -100,8 +100,8 @@
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.21",
104
- "browserslist": "^4.27.0",
103
+ "autoprefixer": "^10.4.22",
104
+ "browserslist": "^4.28.0",
105
105
  "eslint": "^9.39.1",
106
106
  "eslint-config-prettier": "^10.1.8",
107
107
  "eslint-plugin-jsdoc": "^61.1.12",
@@ -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.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.1.12",
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",
@@ -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,6 +14,29 @@ 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);
@@ -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/FullWidthSection.svelte';
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>
@@ -8,7 +8,6 @@ This file is part of Network Pro.
8
8
 
9
9
  <script>
10
10
  import { base } from '$app/paths';
11
- // Import icons for licenses
12
11
  import { bySvg, ccSvg } from '$lib';
13
12
  import { CONSTANTS } from '$lib';
14
13
 
@@ -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={hrStyle} />
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 rel={PAGE.REL} href={privacyLink} target={PAGE.SELF}>Privacy Policy</a>.
231
- For licensing terms and content usage rights, please visit our
232
- <a rel={PAGE.REL} href={licenseLink} target={PAGE.SELF}
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
+ }
@@ -724,3 +724,45 @@ footer .container {
724
724
  .badge--gpl {
725
725
  width: 120px;
726
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{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}
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,7 +7,7 @@ This file is part of Network Pro.
7
7
  ========================================================================== -->
8
8
 
9
9
  <script>
10
- import RedirectPage from '$lib/components/RedirectPage.svelte';
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/RedirectPage.svelte';
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/RedirectPage.svelte';
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: SunDevil311 (Scott Lopez)
4
+ Contact: Scott Lopez (SunDevil311)
5
5
  GitHub: https://github.com/netwk-pro
6
- Email: support@neteng.pro
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@neteng.pro.asc
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
- "Designed for professionals. Hardened for privacy. Built with intent."
18
+ "Locking Down Networks, Unlocking Confidence™"
19
19
 
20
20
  /* LAST UPDATED */
21
- 2025-06-11
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
- # --- Optional: service utilities or PWA
37
+ # --- Service utilities or PWA
38
38
  Disallow: /service-worker
39
39
  Disallow: /service-worker.js
40
40
  Disallow: /service-worker.d.ts
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <!-- Sitemap last updated 2025-11-03 -->
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-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-10-30</lastmod>
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-06-11</lastmod>
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
+ });
@@ -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
- reporters: ['default', 'json'],
29
+ reporter: ['default', 'json'],
29
30
  testTimeout: 10000,
30
31
  outputFile: {
31
32
  json: './reports/server/results.json',