fix(#1890): drop the hardcoded og:url so shared links stay on the instance (#1893)

Fixes #1890.

## The problem

`public/index.html:16` shipped this to every deployment:

```html
<meta property="og:url" content="https://analyzer.00id.net">
```

Open Graph consumers — Facebook and Messenger among them — treat
`og:url` as the canonical destination. Clicking the preview of a link
shared from *any* CoreScope instance navigated to that one host. The
direct link text still resolved correctly, which is why this went
unnoticed; the preview card and the surrounding message body did not.

It is the only occurrence in the frontend.

## The change

Remove the tag. `og:url` is optional — with no tag present, consumers
fall back to the URL they crawled, which is correct for every deployment
and needs no configuration.

## Why not the config-driven variant

The issue also proposes deriving the URL from `config.json`. I did not
take that shape, on purpose:

`index.html` is pre-processed **once at startup** — `spaHandler` reads
it and substitutes `__BUST__` (`cmd/server/main.go:565`), then serves
the same byte slice for every request. A correct per-host `og:url`
therefore needs either a new public-URL config key or per-request
templating of the index. Both are decisions about config surface and
request-path cost that belong to you, and neither is needed to stop the
redirect.

Happy to follow up with whichever shape you prefer — this PR is the part
that is unambiguous.

## What is left alone

`og:image` still points at
`raw.githubusercontent.com/Kpa-clawbot/corescope/master/public/og-image.png`.
That is the project's own asset, a shared project resource rather than a
redirect target, so it is correct for every instance to reference it.

## Test

`test-issue-1890-og-url.js`, a static scan, registered in `test-all.sh`:

- no `og:url` meta tag
- no `rel="canonical"` link
- no `00id.net` reference anywhere in `index.html`
- `og:title` / `og:description` / `og:image` still present

That last assertion is deliberate: without it the guard could be
satisfied by deleting the whole embed block. Watched fail first — 2
passed, 2 failed before the change, 4 passed after.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
efiten
2026-09-02 10:28:04 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 647841c990
commit c5a71b34ec
3 changed files with 66 additions and 1 deletions
+4 -1
View File
@@ -13,7 +13,10 @@
<meta property="og:image" content="https://raw.githubusercontent.com/Kpa-clawbot/corescope/master/public/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:url" content="https://analyzer.00id.net">
<!-- No og:url: it is the canonical destination OG consumers navigate to, so a
hardcoded value sends every self-hosted instance's shared links to that one
host (#1890). Omitted, consumers use the URL they crawled — correct for
every deployment, no configuration needed. -->
<meta property="og:type" content="website">
<meta name="theme-color" content="#0a0a0a">
+1
View File
@@ -36,6 +36,7 @@ node test-issue-1648-m2-emoji-scan.js
node test-issue-1648-m3-emoji-scan.js
node test-issue-1648-m6-final-sweep.js
node test-issue-1648-m6-lint-self.js
node test-issue-1890-og-url.js
node test-traces.js
node test-live-multibyte-filter.js
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env node
/* Issue #1890 index.html must not hardcode one instance's URL in its
* Open Graph tags.
*
* `<meta property="og:url" content="https://analyzer.00id.net">` shipped to
* every self-hosted CoreScope. Facebook, Messenger and other OG consumers treat
* og:url as the canonical destination, so clicking a shared preview from ANY
* instance navigated to that one host instead of the instance the link came
* from. With no og:url present, consumers fall back to the URL they crawled,
* which is correct for every deployment without any configuration.
*
* og:image is deliberately NOT covered: it points at the project's own asset on
* raw.githubusercontent.com, which is a shared project resource, not a
* redirect target.
*/
'use strict';
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const INDEX = path.resolve(__dirname, 'public', 'index.html');
const html = fs.readFileSync(INDEX, 'utf8');
let passed = 0, failed = 0;
function test(name, fn) {
try {
fn();
passed++;
console.log(`${name}`);
} catch (e) {
failed++;
console.log(`${name}: ${e.message}`);
}
}
console.log('\n=== #1890: index.html carries no instance-specific canonical URL ===');
test('no og:url meta tag pinning a single instance', () => {
const m = html.match(/<meta[^>]*property=["']og:url["'][^>]*>/i);
assert.ok(!m, `og:url must not be hardcoded; found: ${m && m[0]}`);
});
test('no rel="canonical" pinning a single instance', () => {
const m = html.match(/<link[^>]*rel=["']canonical["'][^>]*>/i);
assert.ok(!m, `canonical link must not be hardcoded; found: ${m && m[0]}`);
});
test('the analyzer.00id.net host appears nowhere in index.html', () => {
assert.ok(!/00id\.net/i.test(html), 'index.html still references 00id.net');
});
test('og:title and og:description are still present', () => {
// The fix removes one tag, not the embed. Guard against over-deletion.
assert.ok(/property=["']og:title["']/i.test(html), 'og:title missing');
assert.ok(/property=["']og:description["']/i.test(html), 'og:description missing');
assert.ok(/property=["']og:image["']/i.test(html), 'og:image missing');
});
console.log(`\n #1890 og:url: ${passed} passed, ${failed} failed\n`);
process.exit(failed ? 1 : 0);