Skip to content

Commit 4d7f52b

Browse files
committed
Derive callback footer link labels from branding constants
The URLs lived in branding.ts while their display text stayed inline in the page template, so a rename would have had to touch both. Add matching label constants and restore the no-external-assets guard to its full strength by stripping the two intentional footer links before asserting no other off-machine URL or network call appears.
1 parent 31117fe commit 4d7f52b

3 files changed

Lines changed: 65 additions & 13 deletions

File tree

src/auth/callback-page.test.ts

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { describe, expect, test } from "bun:test";
22

3+
import {
4+
PRODUCT_GITHUB_LABEL,
5+
PRODUCT_GITHUB_URL,
6+
PRODUCT_SITE_LABEL,
7+
PRODUCT_SITE_URL,
8+
} from "../branding.js";
39
import { callbackPageHtml, humanizeIdentifier } from "./callback-page.js";
410

511
describe("humanizeIdentifier", () => {
@@ -42,19 +48,49 @@ describe("callbackPageHtml", () => {
4248
);
4349
});
4450

45-
test("success footer links to corbits.dev and the GitHub org", () => {
51+
test("the footer links to the product site and the GitHub org", () => {
4652
const html = callbackPageHtml({ subject: "linear" });
47-
expect(html).toContain('href="https://corbits.dev"');
48-
expect(html).toContain('href="https://github.com/corbitsdev"');
49-
expect(html).toContain(">corbits.dev<");
50-
expect(html).toContain(">github.com/corbitsdev<");
53+
const link = (url: string, label: string) =>
54+
`<a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`;
55+
expect(html).toContain(link(PRODUCT_SITE_URL, PRODUCT_SITE_LABEL));
56+
expect(html).toContain(link(PRODUCT_GITHUB_URL, PRODUCT_GITHUB_LABEL));
5157
});
5258

53-
test("the page loads no off-machine assets", () => {
54-
const html = callbackPageHtml({ subject: "linear" });
55-
// Product links in the footer are intentional; nothing else may fetch.
56-
expect(html).not.toMatch(/<(?:link|script)\b[^>]+\bsrc=/i);
57-
expect(html).not.toMatch(/@import\b/);
58-
expect(html).not.toMatch(/url\(\s*["']?https?:/i);
59+
test("each footer label names the destination its URL actually points at", () => {
60+
expect(PRODUCT_SITE_URL).toContain(PRODUCT_SITE_LABEL);
61+
expect(PRODUCT_GITHUB_URL).toContain(PRODUCT_GITHUB_LABEL);
5962
});
63+
64+
// An allowlist rather than a shape match: an unexpected origin fails loudly
65+
// instead of passing because it happened to be wrapped in an anchor tag.
66+
const allowedOrigins = new Set([
67+
PRODUCT_SITE_URL,
68+
PRODUCT_GITHUB_URL,
69+
// The SVG namespace the wordmark declares; a URI, never fetched.
70+
"http://www.w3.org/2000/svg",
71+
]);
72+
73+
const offMachineOrigins = (html: string): readonly string[] => {
74+
// Scheme-qualified and protocol-relative alike, since either would load.
75+
const found =
76+
html.match(
77+
/(?:[a-z][a-z0-9+.-]*:)?\/\/[a-z0-9-]+(?:\.[a-z0-9-]+)+[^"'`)\s<>]*/gi,
78+
) ?? [];
79+
return found.filter(
80+
(ref) => ![...allowedOrigins].some((origin) => ref.startsWith(origin)),
81+
);
82+
};
83+
84+
for (const [outcome, page] of [
85+
["success", { subject: "linear" }],
86+
["failure", { subject: "linear", error: "access_denied" }],
87+
] as const) {
88+
test(`the ${outcome} page names no off-machine origin beyond the footer links`, () => {
89+
const html = callbackPageHtml(page);
90+
expect(offMachineOrigins(html)).toEqual([]);
91+
expect(html).not.toMatch(
92+
/\b(?:fetch|XMLHttpRequest|WebSocket|EventSource|sendBeacon|importScripts)\s*\(/,
93+
);
94+
});
95+
}
6096
});

src/auth/callback-page.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616

1717
import {
18+
PRODUCT_GITHUB_LABEL,
1819
PRODUCT_GITHUB_URL,
1920
PRODUCT_NAME,
21+
PRODUCT_SITE_LABEL,
2022
PRODUCT_SITE_URL,
2123
} from "../branding.js";
2224

@@ -245,6 +247,16 @@ export function humanizeIdentifier(raw: string): string {
245247
return words.charAt(0).toUpperCase() + words.slice(1);
246248
}
247249

250+
/**
251+
* A footer link, preceded by its separator.
252+
*
253+
* Opens in a new tab so the operator keeps the tab telling them the
254+
* authorization finished and this window is safe to close.
255+
*/
256+
function footerLink(url: string, label: string): string {
257+
return `<span class="sep" aria-hidden="true">·</span><a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`;
258+
}
259+
248260
export type CallbackPage = {
249261
/** What was being authorized: an MCP server or provider name. */
250262
readonly subject?: string;
@@ -292,7 +304,7 @@ export function callbackPageHtml(page: CallbackPage = {}): string {
292304
`<h1>${heading}</h1>`,
293305
`<p class="body">${body}</p>`,
294306
"<hr>",
295-
`<footer>${PRODUCT_NAME}<span class="sep" aria-hidden="true">·</span><a href="${PRODUCT_SITE_URL}">corbits.dev</a><span class="sep" aria-hidden="true">·</span><a href="${PRODUCT_GITHUB_URL}">github.com/corbitsdev</a></footer>`,
307+
`<footer>${PRODUCT_NAME}${footerLink(PRODUCT_SITE_URL, PRODUCT_SITE_LABEL)}${footerLink(PRODUCT_GITHUB_URL, PRODUCT_GITHUB_LABEL)}</footer>`,
296308
"</div>",
297309
"</main></body>",
298310
`<script>${SCRIPT}</script>`,

src/branding.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ export const PRODUCT_NAME = "Corbits Code";
1111
// Short attribution form used in compact UI (status lines, footers).
1212
export const PRODUCT_SHORT_NAME = "Corbits";
1313

14-
// Canonical public URLs shown on the OAuth callback page and other brand surfaces.
14+
// Canonical public URLs, each paired with the text shown in its place. The label
15+
// is spelled out rather than stripped from the URL so it can diverge from the
16+
// bare host later without a rendering helper having to special-case it.
1517
export const PRODUCT_SITE_URL = "https://corbits.dev";
18+
export const PRODUCT_SITE_LABEL = "corbits.dev";
1619
export const PRODUCT_GITHUB_URL = "https://github.com/corbitsdev";
20+
export const PRODUCT_GITHUB_LABEL = "github.com/corbitsdev";
1721

1822
export const COMMAND_NAME = "corbits";
1923

0 commit comments

Comments
 (0)