Files
electron/spec/parse-features-string-spec.ts
trop[bot] fe2e7d0073 fix: restrict window.open features to allowlisted BrowserWindow options (#50948)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Sam Attard <sattard@anthropic.com>
2026-04-11 19:04:40 -07:00

65 lines
2.5 KiB
TypeScript

import { expect } from 'chai';
import { parseCommaSeparatedKeyValue, parseFeatures } from '../lib/browser/parse-features-string';
describe('feature-string parsing', () => {
it('is indifferent to whitespace around keys and values', () => {
const checkParse = (string: string, parsed: Record<string, string | boolean>) => {
const features = parseCommaSeparatedKeyValue(string);
expect(features).to.deep.equal(parsed);
};
checkParse('a=yes,c=d', { a: true, c: 'd' });
checkParse('a=yes ,c=d', { a: true, c: 'd' });
checkParse('a=yes, c=d', { a: true, c: 'd' });
checkParse('a=yes , c=d', { a: true, c: 'd' });
checkParse(' a=yes , c=d', { a: true, c: 'd' });
checkParse(' a= yes , c=d', { a: true, c: 'd' });
checkParse(' a = yes , c=d', { a: true, c: 'd' });
checkParse(' a = yes , c =d', { a: true, c: 'd' });
checkParse(' a = yes , c = d', { a: true, c: 'd' });
checkParse(' a = yes , c = d ', { a: true, c: 'd' });
});
describe('parseFeatures allowlist', () => {
it('passes through allowlisted presentational options', () => {
const { options } = parseFeatures('width=400,height=300,show=no,frame=no,title=hi,backgroundColor=#fff,left=10,top=20');
expect(options).to.deep.equal({
width: 400,
height: 300,
show: false,
frame: false,
title: 'hi',
backgroundColor: '#fff',
left: 10,
top: 20,
x: 10,
y: 20
});
});
it('drops non-allowlisted options that would be unsafe to pass to BrowserWindow', () => {
const { options } = parseFeatures('icon=/etc/passwd,width=400');
expect(options).to.deep.equal({ width: 400 });
expect(options).to.not.have.property('icon');
});
it('drops non-allowlisted options even when paired with UNC paths', () => {
const { options } = parseFeatures('icon=\\\\attacker.example\\share\\x.png,show=no');
expect(options).to.deep.equal({ show: false });
expect(options).to.not.have.property('icon');
});
it('drops unknown options', () => {
const { options } = parseFeatures('something-unknown=foo,width=400');
expect(options).to.deep.equal({ width: 400 });
expect(options).to.not.have.property('something-unknown');
});
it('still extracts allowlisted webPreferences', () => {
const { options, webPreferences } = parseFeatures('icon=/etc/passwd,nodeIntegration=no,width=400');
expect(options).to.deep.equal({ width: 400 });
expect(webPreferences).to.deep.equal({ nodeIntegration: false });
});
});
});