@automattic/calypso-url
Version:
This library provides both generic and Calypso-specific utilities for handling URLs.
76 lines • 2.89 kB
JavaScript
import photon from 'photon';
import { getUrlParts, getUrlFromParts } from '../url-parts';
/**
* Pattern matching URLs to be left unmodified.
*/
let REGEX_EXEMPT_URL;
if (typeof globalThis.location === 'object') {
REGEX_EXEMPT_URL = new RegExp(`^(/(?!/)|data:image/[^;]+;|blob:${globalThis.location.origin}/)`);
}
else {
REGEX_EXEMPT_URL = /^(\/(?!\/)|data:image\/[^;]+;)/;
}
/**
* Pattern matching Automattic-controlled hostnames
*/
const REGEXP_A8C_HOST = /^([-a-zA-Z0-9_]+\.)*(gravatar\.com|wordpress\.com|wp\.com|a8c\.com)$/;
/**
* Query parameters to be treated as image dimensions
*/
const SIZE_PARAMS = ['w', 'h', 'resize', 'fit', 's'];
/**
* Generate a safe version of the provided URL
*
* Images that Calypso uses have to be provided by a trusted TLS host. To do
* this, we check the host of the URL against a list of allowed hosts, and run the image
* through photon if the host name does not match.
*
* NOTE: This function will return `null` for external URLs with query strings,
* because Photon itself does not support this!
*
* @param url The URL to secure
* @returns The secured URL, or `null` if we couldn't make it safe
*/
export function safeImageUrl(url) {
if (typeof url !== 'string') {
return null;
}
if (url.length < 1) {
return null;
}
if (REGEX_EXEMPT_URL.test(url)) {
return url;
}
const parsedUrl = getUrlParts(url);
if (REGEXP_A8C_HOST.test(parsedUrl.hostname)) {
// Safely promote Automattic domains to HTTPS
parsedUrl.protocol = 'https';
return getUrlFromParts(parsedUrl).toString();
}
// If there's a query string, bail out because Photon doesn't support them on external URLs
if (parsedUrl.search && (parsedUrl.host || parsedUrl.hostname || parsedUrl.origin)) {
// If it's just size parameters, let's remove them
SIZE_PARAMS.forEach((param) => parsedUrl.searchParams.delete(param));
// Ditch authuser=0 if we find it - we see this on googleusercontent.com URLs and it doesn't affect the image output
if (parsedUrl.searchParams.get('authuser') === '0') {
parsedUrl.searchParams.delete('authuser');
}
// There are still parameters left, since they might be needed to retrieve the image, bail out
if (Array.from(parsedUrl.searchParams).length) {
return null;
}
// Ensure we're creating a new URL without the size parameters
parsedUrl.search = '';
// Force https since if there's a missing protocol it'll throw an error
if (!parsedUrl?.protocol) {
parsedUrl.protocol = 'https';
}
url = getUrlFromParts(parsedUrl).toString();
}
// Photon doesn't support SVGs
if (parsedUrl.pathname.endsWith('.svg')) {
return null;
}
return photon(url);
}
//# sourceMappingURL=index.js.map