Skip to content

Instantly share code, notes, and snippets.

@eligrey
Created May 7, 2024 19:47
Show Gist options
  • Save eligrey/1a2b8fdba1c403a21d24cdde4d829200 to your computer and use it in GitHub Desktop.
Save eligrey/1a2b8fdba1c403a21d24cdde4d829200 to your computer and use it in GitHub Desktop.
matchCSPEntry screenshot
/**
* Determine if a URL matches a CSP entry data flow, using native browser CSP
* capabilities.
*
* @param cspEntry - CSP entry data flow string
* @param url - A URL to check
* @returns True if the URL matches the data flow, otherwise false
*/
export const matchCSPEntry = (cspEntry: string, url: URL): Promise<boolean> =>
new Promise((resolve) => {
if (typeof document === 'undefined') {
throw new Error('CSP entry data flow matching requires the DOM API');
}
const HTML = 'http://www.w3.org/1999/xhtml';
const frame = (document.documentElement || document).appendChild(
document.createElementNS(HTML, 'iframe') as HTMLIFrameElement,
);
frame.style.display = 'none';
// eslint-disable-next-line no-multi-assign
frame.width = frame.height = '0';
const doc = frame.contentDocument!;
let resolved = false;
const resolveTest = (status: boolean): void => {
if (!resolved) {
resolved = true;
img.removeAttribute('src');
img.remove();
frame.remove();
resolve(status);
}
};
const isFirefox =
typeof navigator !== 'undefined' &&
navigator.userAgent.includes('Firefox/');
// Detect CSP violation
(isFirefox // Firefox doesn't send CSP violation events to iframe doc
? document
: doc
).addEventListener(
'securitypolicyviolation',
() => {
resolveTest(false);
},
{ once: true },
);
const meta = doc.createElementNS(HTML, 'meta') as HTMLMetaElement;
meta.httpEquiv = 'Content-Security-Policy';
meta.content = `default-src ${cspEntry};`;
doc.head.appendChild(meta).remove();
const img = doc.createElementNS(HTML, 'img') as HTMLImageElement;
doc.body.appendChild(img);
img.src = url.href;
// Resolve successfully if no CSP violations in ≥20ms
setTimeout(() => {
resolveTest(true);
}, 20);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment