fix: validate response in protocol.handle()
(#38587)
fix: validate response in protocol.handle()
This commit is contained in:
parent
5931f69f18
commit
86824c070e
2 changed files with 61 additions and 4 deletions
|
@ -60,6 +60,26 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque
|
||||||
}) as RequestInit['body'];
|
}) as RequestInit['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(codebytere): Use Object.hasOwn() once we update to ECMAScript 2022.
|
||||||
|
function validateResponse (res: Response) {
|
||||||
|
if (!res || typeof res !== 'object') return false;
|
||||||
|
|
||||||
|
if (res.type === 'error') return true;
|
||||||
|
|
||||||
|
const exists = (key: string) => Object.prototype.hasOwnProperty.call(res, key);
|
||||||
|
|
||||||
|
if (exists('status') && typeof res.status !== 'number') return false;
|
||||||
|
if (exists('statusText') && typeof res.statusText !== 'string') return false;
|
||||||
|
if (exists('headers') && typeof res.headers !== 'object') return false;
|
||||||
|
|
||||||
|
if (exists('body')) {
|
||||||
|
if (typeof res.body !== 'object') return false;
|
||||||
|
if (res.body !== null && !(res.body instanceof ReadableStream)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, handler: (req: Request) => Response | Promise<Response>) {
|
Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, handler: (req: Request) => Response | Promise<Response>) {
|
||||||
const register = isBuiltInScheme(scheme) ? this.interceptProtocol : this.registerProtocol;
|
const register = isBuiltInScheme(scheme) ? this.interceptProtocol : this.registerProtocol;
|
||||||
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
|
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
|
||||||
|
@ -73,13 +93,14 @@ Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, h
|
||||||
duplex: body instanceof ReadableStream ? 'half' : undefined
|
duplex: body instanceof ReadableStream ? 'half' : undefined
|
||||||
} as any);
|
} as any);
|
||||||
const res = await handler(req);
|
const res = await handler(req);
|
||||||
if (!res || typeof res !== 'object') {
|
if (!validateResponse(res)) {
|
||||||
return cb({ error: ERR_UNEXPECTED });
|
return cb({ error: ERR_UNEXPECTED });
|
||||||
}
|
} else if (res.type === 'error') {
|
||||||
if (res.type === 'error') { cb({ error: ERR_FAILED }); } else {
|
cb({ error: ERR_FAILED });
|
||||||
|
} else {
|
||||||
cb({
|
cb({
|
||||||
data: res.body ? Readable.fromWeb(res.body as ReadableStream<ArrayBufferView>) : null,
|
data: res.body ? Readable.fromWeb(res.body as ReadableStream<ArrayBufferView>) : null,
|
||||||
headers: Object.fromEntries(res.headers),
|
headers: res.headers ? Object.fromEntries(res.headers) : {},
|
||||||
statusCode: res.status,
|
statusCode: res.status,
|
||||||
statusText: res.statusText,
|
statusText: res.statusText,
|
||||||
mimeType: (res as any).__original_resp?._responseHead?.mimeType
|
mimeType: (res as any).__original_resp?._responseHead?.mimeType
|
||||||
|
|
|
@ -1211,6 +1211,42 @@ describe('protocol module', () => {
|
||||||
await expect(net.fetch('test-scheme://foo')).to.eventually.be.rejectedWith('net::ERR_FAILED');
|
await expect(net.fetch('test-scheme://foo')).to.eventually.be.rejectedWith('net::ERR_FAILED');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles invalid protocol response status', async () => {
|
||||||
|
protocol.handle('test-scheme', () => {
|
||||||
|
return { status: [] } as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
defer(() => { protocol.unhandle('test-scheme'); });
|
||||||
|
await expect(net.fetch('test-scheme://foo')).to.be.rejectedWith('net::ERR_UNEXPECTED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles invalid protocol response statusText', async () => {
|
||||||
|
protocol.handle('test-scheme', () => {
|
||||||
|
return { statusText: false } as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
defer(() => { protocol.unhandle('test-scheme'); });
|
||||||
|
await expect(net.fetch('test-scheme://foo')).to.be.rejectedWith('net::ERR_UNEXPECTED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles invalid protocol response header parameters', async () => {
|
||||||
|
protocol.handle('test-scheme', () => {
|
||||||
|
return { headers: false } as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
defer(() => { protocol.unhandle('test-scheme'); });
|
||||||
|
await expect(net.fetch('test-scheme://foo')).to.be.rejectedWith('net::ERR_UNEXPECTED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles invalid protocol response body parameters', async () => {
|
||||||
|
protocol.handle('test-scheme', () => {
|
||||||
|
return { body: false } as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
defer(() => { protocol.unhandle('test-scheme'); });
|
||||||
|
await expect(net.fetch('test-scheme://foo')).to.be.rejectedWith('net::ERR_UNEXPECTED');
|
||||||
|
});
|
||||||
|
|
||||||
it('handles a synchronous error in the handler', async () => {
|
it('handles a synchronous error in the handler', async () => {
|
||||||
protocol.handle('test-scheme', () => { throw new Error('test'); });
|
protocol.handle('test-scheme', () => { throw new Error('test'); });
|
||||||
defer(() => { protocol.unhandle('test-scheme'); });
|
defer(() => { protocol.unhandle('test-scheme'); });
|
||||||
|
|
Loading…
Reference in a new issue