A pasted social URL is untrusted input. Before a backend tries to retrieve media, it should extract a small, well-defined identifier and discard everything else. This article implements that boundary for public X post URLs in JavaScript. I maintain Twitter Viewer; the parser below is an example of input handling, not a claim that these snippets reproduce its backend.
Parse the URL before matching the path
Matching a full URL with a loose regular expression tends to accept misleading hosts. A string can contain x.com in a username, query parameter, or an attacker-controlled subdomain. Let the URL parser separate those components first.
export function parsePostUrl(raw) {
let url;
try {
url = new URL(raw.trim());
} catch {
throw new Error('Enter an absolute post URL');
}
if (url.protocol !== 'https:') throw new Error('HTTPS required');
if (url.username || url.password) throw new Error('Credentials rejected');
if (url.port && url.port !== '443') throw new Error('Unexpected port');
const host = url.hostname.toLowerCase();
const allowed = new Set(['x.com', 'www.x.com', 'twitter.com', 'www.twitter.com']);
if (!allowed.has(host)) throw new Error('Unsupported host');
const match = url.pathname.match(/^\/([A-Za-z0-9_]{1,15})\/status\/([0-9]{1,20})(?:\/(?:video|photo)\/[1-9][0-9]*)?\/?$/);
if (!match) throw new Error('Expected a post URL');
return {
author: match[1],
id: match[2],
canonicalUrl: `https://x.com/${match[1]}/status/${match[2]}`
};
}
This intentionally accepts a narrow set of common web links. It does not promise support for every historical Twitter route. Mobile hosts, share wrappers, and links without a handle can be added as explicit cases after they have tests. A rejected unfamiliar route should produce a useful message rather than silently falling through to arbitrary fetching.
Keep the post ID as a string. Large decimal identifiers can exceed JavaScript's safe integer range; converting one to Number may change its value before the request even reaches the server. The handle is useful for a human-readable link but should not be treated as an immutable account identity.
Test deceptive hosts as well as normal links
Save the parser as post-url.mjs, then create post-url.test.mjs:
import test from 'node:test';
import assert from 'node:assert/strict';
import { parsePostUrl } from './post-url.mjs';
test('drops share parameters and keeps the ID exact', () => {
const result = parsePostUrl('https://twitter.com/example/status/18446744073709551615?s=20');
assert.equal(result.id, '18446744073709551615');
assert.equal(result.canonicalUrl, 'https://x.com/example/status/18446744073709551615');
});
test('rejects URLs that merely contain a trusted hostname', () => {
for (const url of [
'https://x.com.example.org/example/status/123',
'https://x.com@other.example/example/status/123',
'https://other.example/?next=https://x.com/example/status/123',
'http://x.com/example/status/123'
]) assert.throws(() => parsePostUrl(url));
});
test('accepts a media-view suffix but removes it', () => {
assert.equal(parsePostUrl('https://x.com/example/status/123/video/1').id, '123');
});
Run node --test post-url.test.mjs. These tests do not need an X account or network access. They describe the input contract, so upstream changes cannot turn a basic parser test into an intermittent integration failure.
A valid URL does not imply downloadable media
After parsing, there are still independent outcomes: a deleted post, a private account, a post with no native video, an upstream timeout, and a successful lookup with several variants. Keep these separate in the response model. Returning “invalid URL” for every outcome teaches users to keep editing a perfectly valid link.
For a manual workflow, my twitter video downloader accepts public tweet links and offers available MP4 variants. A third-party embedded player is a different media source; the fact that it appears inside a post does not make it a native X video. Saving a file also does not grant permission to republish it.
Revalidate the boundary on the server
Client validation improves feedback, but a caller can skip the client. Apply the same host and path policy on the server. Prefer passing the extracted ID into a constrained lookup rather than fetching the original pasted URL. If a backend follows redirects or later fetches an upstream media URL, that fetch needs its own destination and redirect policy; validating the initial social URL does not validate a later destination.
Top comments (0)