Handle all URL.parse cases with invalid URLs

This commit is contained in:
Lim Chee Aun 2025-03-21 18:23:13 +08:00
parent ffcfc29d8c
commit a3dd8bab46
9 changed files with 388 additions and 380 deletions

View file

@ -236,7 +236,9 @@ function AccountInfo({
const accountInstance = useMemo(() => {
if (!url) return null;
const domain = punycode.toUnicode(URL.parse(url).hostname);
const hostname = URL.parse(url)?.hostname;
if (!hostname) return null;
const domain = punycode.toUnicode(hostname);
return domain;
}, [url]);
@ -1843,6 +1845,7 @@ function lightenRGB([r, g, b]) {
function niceAccountURL(url) {
if (!url) return;
const urlObj = URL.parse(url);
if (!urlObj) return;
const { host, pathname } = urlObj;
const path = pathname.replace(/\/$/, '').replace(/^\//, '');
return (

View file

@ -61,19 +61,21 @@ function AccountSheet({ account, instance: propInstance, onClose }) {
return result.accounts[0];
} else if (/https?:\/\/[^/]+\/@/.test(account)) {
const accountURL = URL.parse(account);
const { hostname, pathname } = accountURL;
const acct =
pathname.replace(/^\//, '').replace(/\/$/, '') +
'@' +
hostname;
const result = await masto.v2.search.fetch({
q: acct,
type: 'accounts',
limit: 1,
resolve: authenticated,
});
if (result.accounts.length) {
return result.accounts[0];
if (accountURL) {
const { hostname, pathname } = accountURL;
const acct =
pathname.replace(/^\//, '').replace(/\/$/, '') +
'@' +
hostname;
const result = await masto.v2.search.fetch({
q: acct,
type: 'accounts',
limit: 1,
resolve: authenticated,
});
if (result.accounts.length) {
return result.accounts[0];
}
}
}
}

View file

@ -46,6 +46,7 @@ import emojifyText from '../utils/emojify-text';
import enhanceContent from '../utils/enhance-content';
import FilterContext from '../utils/filter-context';
import { isFiltered } from '../utils/filters';
import getDomain from '../utils/get-domain';
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
import getHTMLText from '../utils/getHTMLText';
import handleContentLinks from '../utils/handle-content-links';
@ -2695,14 +2696,6 @@ function MediaFirstContainer(props) {
);
}
function getDomain(url) {
return punycode.toUnicode(
URL.parse(url)
.hostname.replace(/^www\./, '')
.replace(/\/$/, ''),
);
}
// "Post": Quote post + card link preview combo
// Assume all links from these domains are "posts"
// Mastodon links are "posts" too but they are converted to real quote posts and there's too many domains to check
@ -3520,6 +3513,7 @@ const StatusButton = forwardRef((props, ref) => {
function nicePostURL(url) {
if (!url) return;
const urlObj = URL.parse(url);
if (!urlObj) return;
const { host, pathname } = urlObj;
const path = pathname.replace(/\/$/, '');
// split only first slash

692
src/locales/en.po generated

File diff suppressed because it is too large Load diff

View file

@ -467,7 +467,7 @@ function AccountStatuses() {
const accountInstance = useMemo(() => {
if (!account?.url) return null;
const domain = URL.parse(account.url).hostname;
const domain = URL.parse(account.url)?.hostname;
return domain;
}, [account]);
const sameInstance = instance === accountInstance;

View file

@ -35,6 +35,7 @@ import { oklab2rgb, rgb2oklab } from '../utils/color-utils';
import db from '../utils/db';
import emojifyText from '../utils/emojify-text';
import { isFiltered } from '../utils/filters';
import getDomain from '../utils/get-domain';
import htmlContentLength from '../utils/html-content-length';
import mem from '../utils/mem';
import niceDateTime from '../utils/nice-date-time';
@ -1171,11 +1172,7 @@ function Catchup() {
height,
publishedAt,
} = card;
const domain = punycode.toUnicode(
URL.parse(url)
.hostname.replace(/^www\./, '')
.replace(/\/$/, ''),
);
const domain = getDomain(url);
let accentColor;
if (blurhash) {
const averageColor = getBlurHashAverageColor(blurhash);

View file

@ -19,6 +19,7 @@ import Timeline from '../components/timeline';
import { api } from '../utils/api';
import { oklab2rgb, rgb2oklab } from '../utils/color-utils';
import { filteredItems } from '../utils/filters';
import getDomain from '../utils/get-domain';
import pmem from '../utils/pmem';
import shortenNumber from '../utils/shorten-number';
import states, { saveStatus } from '../utils/states';
@ -252,11 +253,7 @@ function Trending({ columnMode, ...props }) {
: null;
const isShortTitle = title.length < 30;
const hasAuthor = !!(authorName || author);
const domain = punycode.toUnicode(
URL.parse(url)
.hostname.replace(/^www\./, '')
.replace(/\/$/, ''),
);
const domain = getDomain(url);
let accentColor;
if (blurhash) {
const averageColor = getBlurHashAverageColor(blurhash);

13
src/utils/get-domain.js Normal file
View file

@ -0,0 +1,13 @@
import punycode from 'punycode/';
export default function getDomain(url) {
try {
return punycode.toUnicode(
URL.parse(url)
.hostname.replace(/^www\./, '')
.replace(/\/$/, ''),
);
} catch (e) {
return ''; // just give up
}
}

View file

@ -12,7 +12,9 @@ const statusPostRegexes = [
export function getInstanceStatusObject(url) {
// Regex /:username/:id, where username = @username or @username@domain, id = anything
const { hostname, pathname } = URL.parse(url);
const theURL = URL.parse(url);
if (!theURL) return {};
const { hostname, pathname } = theURL;
// const [, username, domain, id] = pathname.match(statusRegex) || [];
for (const regex of statusPostRegexes) {
const [, id] = pathname.match(regex) || [];