mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-08-27 23:34:14 +00:00
## Problem The **Copy URL** and **Copy short URL** buttons on the node detail page produced URLs like: ``` https://analyzer.00id.net#/nodes/abcdef… ``` The `/` between the authority and the fragment is missing. RFC 3986 allows that form, but several mobile browsers (and some link-detection heuristics) reject or mis-parse it. ## Fix Three sites in `public/nodes.js` concatenated `location.origin` with a literal that started with `'#/'`. Prepend `/`: - `public/nodes.js:772` — full Copy URL (full pubkey) - `public/nodes.js:783` — Copy short URL (8-char prefix) - `public/nodes.js:1580` — side-pane Copy URL All three now build `https://analyzer.00id.net/#/nodes/…`, which every browser accepts. ## Tests `test-issue-1753-copy-url-slash.js` — extracts every `location.origin + '<literal>'` site from `public/nodes.js` and asserts the literal starts with `/`. Wired into `.github/workflows/deploy.yml`. - **Red commit** `b4df2786` — test added; CI fails on assertion (3 of 4 cases) because the literals still start with `'#/'`. - **Green commit** `2c59f7c0` — three literals fixed to `'/#/nodes/'`; test passes (4/4). ## Verification ``` $ node test-issue-1753-copy-url-slash.js issue-1753 copy-URL slash regression ✅ found at least 3 location.origin + literal sites in public/nodes.js ✅ public/nodes.js:772 literal starts with "/#/" (got "/#/nodes/") ✅ public/nodes.js:783 literal starts with "/#/" (got "/#/nodes/") ✅ public/nodes.js:1580 literal starts with "/#/" (got "/#/nodes/") 4 passed, 0 failed ``` `bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh origin/master` → clean (all gates + warnings green). Fixes #1753 --------- Co-authored-by: openclaw-bot <bot@openclaw.dev>
This commit is contained in:
co-authored by
openclaw-bot
parent
f780fe7d0b
commit
db5520f70f
@@ -147,6 +147,7 @@ jobs:
|
||||
node test-preflight-xss-gate.js
|
||||
node test-traces.js
|
||||
node test-issue-1648-m4-emoji-scan.js
|
||||
node test-issue-1753-copy-url-slash.js
|
||||
node test-issue-1668-m3-typography.js
|
||||
node test-mqtt-status-panel.js
|
||||
node test-issue-1697-mqtt-mobile-e2e.js
|
||||
|
||||
+3
-3
@@ -769,7 +769,7 @@
|
||||
}
|
||||
|
||||
// Copy URL
|
||||
const nodeUrl = location.origin + '#/nodes/' + encodeURIComponent(n.public_key);
|
||||
const nodeUrl = location.origin + '/#/nodes/' + encodeURIComponent(n.public_key);
|
||||
document.getElementById('copyUrlBtn')?.addEventListener('click', () => {
|
||||
const btn = document.getElementById('copyUrlBtn');
|
||||
window.copyToClipboard(nodeUrl, () => {
|
||||
@@ -780,7 +780,7 @@
|
||||
|
||||
// Copy short URL — issue #772. Uses an 8-char pubkey prefix; the
|
||||
// backend resolves it to the canonical pubkey when unambiguous.
|
||||
const shortUrl = location.origin + '#/nodes/' + n.public_key.slice(0, 8);
|
||||
const shortUrl = location.origin + '/#/nodes/' + n.public_key.slice(0, 8);
|
||||
document.getElementById('copyShortUrlBtn')?.addEventListener('click', () => {
|
||||
const btn = document.getElementById('copyShortUrlBtn');
|
||||
window.copyToClipboard(shortUrl, () => {
|
||||
@@ -1577,7 +1577,7 @@
|
||||
const observers = h.observers || [];
|
||||
const recent = h.recentPackets || [];
|
||||
const hasLoc = n.lat != null && n.lon != null;
|
||||
const nodeUrl = location.origin + '#/nodes/' + encodeURIComponent(n.public_key);
|
||||
const nodeUrl = location.origin + '/#/nodes/' + encodeURIComponent(n.public_key);
|
||||
|
||||
// Status calculation via shared helper
|
||||
const lastHeard = stats.lastHeard;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/* test-issue-1753-copy-url-slash.js — regression test for issue #1753.
|
||||
*
|
||||
* Bug: Copy URL / Copy short URL buttons on the node detail page built URLs as
|
||||
* location.origin + '#/nodes/...' -> https://analyzer.00id.net#/nodes/...
|
||||
* That's a malformed URL (missing the '/' between authority and fragment).
|
||||
* Some mobile browsers reject it.
|
||||
*
|
||||
* Strategy: behavioral source-level check. The three URL-construction sites
|
||||
* in public/nodes.js are simple string concatenations of `location.origin`
|
||||
* with a hardcoded literal. The "real" assertion is on the literal itself —
|
||||
* it MUST start with '/#/' (not '#/'). The test extracts every
|
||||
* location.origin + '<literal>'
|
||||
* occurrence in public/nodes.js and asserts each literal begins with '/#/'.
|
||||
* Reverting the fix (dropping the leading '/') re-introduces the failure.
|
||||
*/
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
let passed = 0, failed = 0;
|
||||
function test(name, fn) {
|
||||
try { fn(); passed++; console.log(' ✅ ' + name); }
|
||||
catch (e) { failed++; console.log(' ❌ ' + name + ': ' + e.message); }
|
||||
}
|
||||
|
||||
const src = fs.readFileSync(path.join(__dirname, 'public/nodes.js'), 'utf8');
|
||||
|
||||
// Match: location.origin + '<literal>' (single or double quotes)
|
||||
const re = /location\.origin\s*\+\s*(['"])([^'"]*)\1/g;
|
||||
const sites = [];
|
||||
let m;
|
||||
while ((m = re.exec(src)) !== null) {
|
||||
const lineNo = src.slice(0, m.index).split('\n').length;
|
||||
sites.push({ literal: m[2], lineNo });
|
||||
}
|
||||
|
||||
console.log('issue-1753 copy-URL slash regression');
|
||||
|
||||
test('found at least 3 location.origin + literal sites in public/nodes.js', () => {
|
||||
assert.ok(sites.length >= 3,
|
||||
'expected >=3 sites, found ' + sites.length + ': ' + JSON.stringify(sites));
|
||||
});
|
||||
|
||||
for (const s of sites) {
|
||||
test('public/nodes.js:' + s.lineNo + ' literal starts with "/#/" (got ' + JSON.stringify(s.literal) + ')', () => {
|
||||
assert.ok(
|
||||
s.literal.startsWith('/#/') || s.literal.startsWith('/'),
|
||||
'location.origin + ' + JSON.stringify(s.literal) +
|
||||
' produces malformed URL (missing leading "/"). See issue #1753.'
|
||||
);
|
||||
// Specifically forbid '#/' as the literal start — that's the bug.
|
||||
assert.ok(
|
||||
!s.literal.startsWith('#/'),
|
||||
'literal begins with "#/" — concatenating with location.origin yields ' +
|
||||
'"<origin>#/..." which is malformed. Fix: prepend "/". See issue #1753.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n ' + passed + ' passed, ' + failed + ' failed');
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
Reference in New Issue
Block a user