fix(publishing): normalize media links to https

This commit is contained in:
Tommaso Casaburi
2026-04-21 14:23:52 +07:00
parent 80e0cabf01
commit fb19ee47c8
7 changed files with 97 additions and 13 deletions
+19 -1
View File
@@ -8,7 +8,16 @@ vi.mock('../clipboard-utils', () => ({
copyToClipboard: (text: string) => testState.copyToClipboardMock(text),
}));
import { copyShareLinkToClipboard, getHostname, is5chanLink, isValidCrossboardPattern, isValidURL, transform5chanLinkToInternal } from '../url-utils';
import {
copyShareLinkToClipboard,
getHostname,
is5chanLink,
isValidCrossboardPattern,
isValidPublishURL,
isValidURL,
normalizePublishURL,
transform5chanLinkToInternal,
} from '../url-utils';
describe('url-utils', () => {
beforeEach(() => {
@@ -22,6 +31,15 @@ describe('url-utils', () => {
expect(isValidURL('not-a-url')).toBe(false);
});
it('normalizes publish links to the https URLs accepted by communities', () => {
expect(normalizePublishURL(' http://i.imgur.com/YpB7qfa.jpg ')).toBe('https://i.imgur.com/YpB7qfa.jpg');
expect(normalizePublishURL('https://i.imgur.com/YpB7qfa.jpg')).toBe('https://i.imgur.com/YpB7qfa.jpg');
expect(isValidPublishURL('http://i.imgur.com/YpB7qfa.jpg')).toBe(true);
expect(isValidPublishURL('https://i.imgur.com/YpB7qfa.jpg')).toBe(true);
expect(isValidPublishURL('ftp://example.com/file.jpg')).toBe(false);
expect(isValidPublishURL('not-a-url')).toBe(false);
});
it('copies share links for threads and catalog pages using the production fallback base url', async () => {
await copyShareLinkToClipboard('music.eth', 'thread', 'cid-123');
expect(testState.copyToClipboardMock).toHaveBeenCalledWith('https://5chan.app/#/music.eth/thread/cid-123');
+25 -1
View File
@@ -5,7 +5,7 @@ export const QUOTE_NUMBER_REGEX = /(?<![>/\w])>>(\d+)/g;
export const getHostname = (url: string) => {
try {
return new URL(url).hostname.replace(/^www\./, '');
} catch (e) {
} catch {
return '';
}
};
@@ -19,6 +19,30 @@ export const isValidURL = (url: string) => {
}
};
export const normalizePublishURL = (url: string) => {
const trimmedUrl = url.trim();
try {
const parsedUrl = new URL(trimmedUrl);
if (parsedUrl.protocol === 'http:') {
parsedUrl.protocol = 'https:';
return parsedUrl.toString();
}
} catch {
return trimmedUrl;
}
return trimmedUrl;
};
export const isValidPublishURL = (url: string) => {
try {
return new URL(normalizePublishURL(url)).protocol === 'https:';
} catch {
return false;
}
};
const CHAN_5_HOSTNAMES = ['5chan.app', '5chan.eth.limo', '5chan.eth.link', '5chan.eth.sucks', '5chan.netlify.app'];
function getShareBaseUrl(): string {