This commit is contained in:
Samuel Attard 2024-08-31 01:01:39 -07:00
Родитель d7ff2bf7b7
Коммит 8bf80ccdb8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 1B5816524359D045
2 изменённых файлов: 317 добавлений и 3 удалений

Просмотреть файл

@ -35,7 +35,7 @@ Session.prototype.setPermissionHandlers = function (handlers) {
});
this._setPermissionRequestHandler((_, permission, callback, details, effectiveOrigin) => {
handlers.onRequest(permission, effectiveOrigin, details)
Promise.resolve(handlers.onRequest(permission, effectiveOrigin, details))
.then((result) => callback(result.status === 'granted'))
.catch((err) => {
this.emit('error', err);

Просмотреть файл

@ -1358,6 +1358,320 @@ describe('session module', () => {
});
});
describe('ses.setPermissionHandlers(handlers)', () => {
describe('onRequest', () => {
afterEach(closeAllWindows);
// These tests are done on an http server because navigator.userAgentData
// requires a secure context.
let server: http.Server;
let serverUrl: string;
before(async () => {
server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.end('');
});
serverUrl = (await listen(server)).url;
});
after(() => {
server.close();
});
it('cancels any pending requests when cleared', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler',
nodeIntegration: true,
contextIsolation: false
}
});
const ses = w.webContents.session;
ses.setPermissionHandlers({
onRequest: () => ses.setPermissionHandlers(null) as any,
isGranted: () => ({ status: 'ask' })
});
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb(`<html><script>(${remote})()</script></html>`);
});
const result = once(require('electron').ipcMain, 'message');
function remote () {
(navigator as any).requestMIDIAccess({ sysex: true }).then(() => {}, (err: any) => {
require('electron').ipcRenderer.send('message', err.name);
});
}
w.loadURL('https://myfakesite');
const [, name] = await result;
expect(name).to.deep.equal('SecurityError');
});
it('cancels any requests when resolved with invalid status', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler',
nodeIntegration: true,
contextIsolation: false
}
});
const ses = w.webContents.session;
ses.setPermissionHandlers({
onRequest: async () => ({ status: 'nope?' as any }),
isGranted: () => ({ status: 'ask' })
});
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb(`<html><script>(${remote})()</script></html>`);
});
const result = once(require('electron').ipcMain, 'message');
function remote () {
(navigator as any).requestMIDIAccess({ sysex: true }).then(() => {}, (err: any) => {
require('electron').ipcRenderer.send('message', err.name);
});
}
w.loadURL('https://myfakesite');
const [, name] = await result;
expect(name).to.deep.equal('SecurityError');
});
it('successfully resolves when calling legacy getUserMedia', async () => {
const ses = session.fromPartition('' + Math.random());
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'granted' }),
isGranted: () => ({ status: 'ask' })
}
);
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
await w.loadURL(serverUrl);
const { ok, message } = await w.webContents.executeJavaScript(`
new Promise((resolve, reject) => navigator.getUserMedia({
video: true,
audio: true,
}, x => resolve({ok: x instanceof MediaStream}), e => reject({ok: false, message: e.message})))
`);
expect(ok).to.be.true(message);
});
it('successfully rejects when calling legacy getUserMedia', async () => {
const ses = session.fromPartition('' + Math.random());
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'ask' })
}
);
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
await w.loadURL(serverUrl);
await expect(w.webContents.executeJavaScript(`
new Promise((resolve, reject) => navigator.getUserMedia({
video: true,
audio: true,
}, x => resolve({ok: x instanceof MediaStream}), e => reject({ok: false, message: e.message})))
`)).to.eventually.be.rejectedWith('Permission denied');
});
});
describe('isGranted', () => {
afterEach(closeAllWindows);
it('provides valid effectiveOrigin for main frame requests', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
let effectiveOrigin: string = '';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: (permission, origin) => {
effectiveOrigin = origin;
return { status: 'granted' };
}
}
);
const readClipboardPermission: any = () => {
return w.webContents.executeJavaScript(`
navigator.permissions.query({name: 'clipboard-read'})
.then(permission => permission.state).catch(err => err.message);
`, true);
};
await w.loadURL(loadUrl);
const state = await readClipboardPermission();
expect(state).to.equal('granted');
expect(effectiveOrigin).to.equal('https://myfakesite');
});
it('provides valid effectiveOrigin for cross origin subframes', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/foo';
let effectiveOrigin: string = '';
let handlerDetails: Electron.PermissionCheckDetails;
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: (permission, origin, details) => {
effectiveOrigin = origin;
handlerDetails = details;
return { status: 'granted' };
}
}
);
const readClipboardPermission: any = (frame: WebFrameMain) => {
return frame.executeJavaScript(`
navigator.permissions.query({name: 'clipboard-read'})
.then(permission => permission.state).catch(err => err.message);
`, true);
};
await w.loadFile(path.join(fixtures, 'api', 'blank.html'));
w.webContents.executeJavaScript(`
var iframe = document.createElement('iframe');
iframe.src = '${loadUrl}';
iframe.allow = 'clipboard-read';
document.body.appendChild(iframe);
null;
`);
const [,, frameProcessId, frameRoutingId] = await once(w.webContents, 'did-frame-finish-load');
const state = await readClipboardPermission(webFrameMain.fromId(frameProcessId, frameRoutingId));
expect(state).to.equal('granted');
expect(effectiveOrigin).to.equal('https://myfakesite');
expect(handlerDetails!.isMainFrame).to.be.false();
expect(handlerDetails!.embeddingOrigin).to.equal('file:///');
});
it('allows providing "default" / "ask" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'ask' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('default');
});
it('allows providing "granted" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'granted' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('granted');
});
it('allows providing "denied" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'denied' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('denied');
});
});
});
describe('ses.setPermissionRequestHandler(handler)', () => {
afterEach(closeAllWindows);
// These tests are done on an http server because navigator.userAgentData
@ -1448,7 +1762,7 @@ describe('session module', () => {
describe('ses.setPermissionCheckHandler(handler)', () => {
afterEach(closeAllWindows);
it('details provides requestingURL for mainFrame', async () => {
it.skip('details provides requestingURL for mainFrame', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
@ -1484,7 +1798,7 @@ describe('session module', () => {
expect(handlerDetails!.requestingUrl).to.equal(loadUrl);
});
it('details provides requestingURL for cross origin subFrame', async () => {
it.skip('details provides requestingURL for cross origin subFrame', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {