Closed Devhercule closed 7 years ago
Hey,
What do you want to do with it? Test the network requests of your app?
Yess, I want to use a MITM proxy to listen requests and display them (display all requests sent by my electron app) with possibility to change them also (add headers...) I want to do this usin a MITM proxy outside the browser..
Use in any Node.js based environment should be identical to use in... Node.js. :) Is something in the "Using" example list not working under Electron?
I was inspired by your example to integrate MITM proxy in my electron app
here is the code:
const electron = require('electron')
const {app, BrowserWindow, session, ipcMain} = require('electron')
const path = require('path')
const url = require('url')
const { URL } = require('url');
const protocol = electron.protocol
var Mitm = require("mitm")
var mitm = Mitm()
var Http = require('http');
let win
function createWindow () {
var screenElectron = electron.screen;
var mainScreen = screenElectron.getPrimaryDisplay();
var dimensions = mainScreen.size;
// Create the browser window.
win = new BrowserWindow({width: dimensions.width, height: dimensions.height})
//clear cache
win.webContents.session.clearCache(function(){});
win.webContents.clearHistory();
mitm.on('request', function(req, res) {
console.log('----------------------------------------------------------------------------')
console.log(req)
})
session.defaultSession.webRequest.onSendHeaders({urls: ['<all_urls>']}, (details) => {
Http.get(details.url)
})
// Open the DevTools.
win.webContents.openDevTools()
win.loadURL('http://www.rtl.fr/')
// Emitted when the window is closed.
win.on('closed', () => {
win = null
})
}
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (win === null) {
createWindow()
}
})
here is a little part of the result :
----------------------------------------------------------------------------
IncomingMessage {
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: false,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: true,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
socket:
Socket {
connecting: false,
_hadError: false,
_handle:
InternalSocket {
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: true,
remote: [Object],
owner: [Circular],
onread: [Function: onread],
reading: true },
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: [Object],
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: false,
endEmitted: false,
reading: false,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
drain: [Object],
timeout: [Function: bound socketOnTimeout],
data: [Function: bound socketOnData],
error: [Function: bound socketOnError],
close: [Object],
resume: [Function: onSocketResume],
pause: [Function: onSocketPause] },
_eventsCount: 10,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 0,
_sockname: null,
_writev: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser:
HTTPParser {
'0': [Function: parserOnHeaders],
'1': [Function: parserOnHeadersComplete],
'2': [Function: parserOnBody],
'3': [Function: parserOnMessageComplete],
'4': [Function: bound onParserExecute],
_headers: [],
_url: '',
_consumed: false,
socket: [Circular],
incoming: [Circular],
outgoing: null,
maxHeaderPairs: 2000,
onIncoming: [Function: bound parserOnIncoming] },
on: [Function: socketOnWrap],
_paused: false,
read: [Function],
_consuming: true,
_httpMessage:
ServerResponse {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: false,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedHeader: {},
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket: [Circular],
connection: [Circular],
_header: null,
_headers: null,
_headerNames: {},
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: [Circular] } },
connection:
Socket {
connecting: false,
_hadError: false,
_handle:
InternalSocket {
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: true,
remote: [Object],
owner: [Circular],
onread: [Function: onread],
reading: true },
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: [Object],
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: false,
endEmitted: false,
reading: false,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
drain: [Object],
timeout: [Function: bound socketOnTimeout],
data: [Function: bound socketOnData],
error: [Function: bound socketOnError],
close: [Object],
resume: [Function: onSocketResume],
pause: [Function: onSocketPause] },
_eventsCount: 10,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 0,
_sockname: null,
_writev: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser:
HTTPParser {
'0': [Function: parserOnHeaders],
'1': [Function: parserOnHeadersComplete],
'2': [Function: parserOnBody],
'3': [Function: parserOnMessageComplete],
'4': [Function: bound onParserExecute],
_headers: [],
_url: '',
_consumed: false,
socket: [Circular],
incoming: [Circular],
outgoing: null,
maxHeaderPairs: 2000,
onIncoming: [Function: bound parserOnIncoming] },
on: [Function: socketOnWrap],
_paused: false,
read: [Function],
_consuming: true,
_httpMessage:
ServerResponse {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: false,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedHeader: {},
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket: [Circular],
connection: [Circular],
_header: null,
_headers: null,
_headerNames: {},
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: [Circular] } },
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: false,
headers: { host: 'media.rtl.fr', connection: 'close' },
rawHeaders: [ 'Host', 'media.rtl.fr', 'Connection', 'close' ],
trailers: {},
rawTrailers: [],
upgrade: false,
url: '/cache/MtB7C_urPiSdugbi27RYQQ/280v187-2/online/image/2017/0704/7789207694_les-membres-du-conseil-economique-social-et-environnemental-le-mediateur-de-la-republique-sont-reunis-en-assemblee-pleniere
-le-16-novembre-2010-a-paris.jpg',
method: 'GET',
statusCode: null,
statusMessage: null,
client:
Socket {
connecting: false,
_hadError: false,
_handle:
InternalSocket {
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: true,
remote: [Object],
owner: [Circular],
onread: [Function: onread],
reading: true },
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: [Object],
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: false,
endEmitted: false,
reading: false,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
drain: [Object],
timeout: [Function: bound socketOnTimeout],
data: [Function: bound socketOnData],
error: [Function: bound socketOnError],
close: [Object],
resume: [Function: onSocketResume],
pause: [Function: onSocketPause] },
_eventsCount: 10,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 0,
_sockname: null,
_writev: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser:
HTTPParser {
'0': [Function: parserOnHeaders],
'1': [Function: parserOnHeadersComplete],
'2': [Function: parserOnBody],
'3': [Function: parserOnMessageComplete],
'4': [Function: bound onParserExecute],
_headers: [],
_url: '',
_consumed: false,
socket: [Circular],
incoming: [Circular],
outgoing: null,
maxHeaderPairs: 2000,
onIncoming: [Function: bound parserOnIncoming] },
on: [Function: socketOnWrap],
_paused: false,
read: [Function],
_consuming: true,
_httpMessage:
ServerResponse {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: false,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedHeader: {},
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket: [Circular],
connection: [Circular],
_header: null,
_headers: null,
_headerNames: {},
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: [Circular] } },
_consuming: false,
_dumped: false,
res:
ServerResponse {
domain: null,
_events: { finish: [Function: bound resOnFinish] },
_eventsCount: 1,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: false,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedHeader: {},
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
socket:
Socket {
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: null,
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 10,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 0,
_sockname: null,
_writev: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: [Object],
on: [Function: socketOnWrap],
_paused: false,
read: [Function],
_consuming: true,
_httpMessage: [Circular] },
connection:
Socket {
connecting: false,
_hadError: false,
_handle: [Object],
_parent: null,
_host: null,
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 10,
_maxListeners: undefined,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
destroyed: false,
_bytesDispatched: 0,
_sockname: null,
_writev: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: [Object],
on: [Function: socketOnWrap],
_paused: false,
read: [Function],
_consuming: true,
_httpMessage: [Circular] },
_header: null,
_headers: null,
_headerNames: {},
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req: [Circular] } }
----------------------------------------------------------------------------
IncomingMessage {
_readableState:
ReadableState {
objectMode: false,
Questions :
1/ The method I used, is it the right one to use your module with Electron?
2/ How can I display the whole URL sent by the browser? (including scheme, domain...) I dont want to display all parameters displayed in my console.
3/ How can i Send original request Headers set by the browser with http.get?? because actually, only the url in sent.
Thank you
You're using it right. However, in your exact example you seem to control the code that makes the HTTP request (by hooking into something like session.defaultSession.webRequest.onSendHeaders
). If you wanted to add headers to that request, you could just add those headers before the call to Http.get
. Or is that callback in Electron not used for all requests the browser-y window makes? I've never used Electron.
As for getting the URL out of that request, it'd be:
(req.connection.encrypted ? "https" : "http") + "://" + req.headers.host + req.url
But maybe you can solve your entire wish to intercept Electron requests by finding a callback Electron already has for that purpose and adding your headers before calling Http.get
. That'd be a far better solution that using this testing library for it. :)
Thank you for your reply
I tried to use Http.request instead of Http.get, but nothing is displayed !!!
https://nodejs.org/api/http.html#http_http_request_options_callback
Can this help me sending headers to proxy?
There is another big problem with this... The same request is sent two times (one by session.defaultSession.webRequest.onSendHeaders and another one by Http.get) The goal is to send the request only one time (only via the MITM proxy) Is that possible???
Is there a possibility to intercept requests without Http.get? to avoid multiple request send
I guess you could try not sending the request through onSendHeaders
. :) You sure that Electron API is meant for you to intercept those requests and not just inspect their headers? Try removing that onSendHeaders
entirely and if Mitm.js doesn't intercept any requests, you'll have to go inspect how Electron does its requests. Maybe they don't go through Node.js at all by default.
after removing onSendHeaders, no request is intercepted
This is my code, nothing is diplayed, requests are not intercepted by mitm proxy !!!! Yet the website is well displayed
const electron = require('electron')
const {app, BrowserWindow, session, ipcMain} = require('electron')
const path = require('path')
const url = require('url')
const { URL } = require('url');
const protocol = electron.protocol
var Mitm = require("mitm")
var mitm = Mitm()
var Http = require('http');
let win
function createWindow () {
var screenElectron = electron.screen;
var mainScreen = screenElectron.getPrimaryDisplay();
var dimensions = mainScreen.size;
// Create the browser window.
win = new BrowserWindow({width: dimensions.width, height: dimensions.height})
//clear cache
win.webContents.session.clearCache(function(){});
win.webContents.clearHistory();
mitm.on('request', function(req, res) {
console.log('----------------------------------------------------------------------------')
console.log(req)
})
// Open the DevTools.
win.webContents.openDevTools()
win.loadURL('http://www.rtl.fr/')
// Emitted when the window is closed.
win.on('closed', () => {
win = null
})
}
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (win === null) {
createWindow()
}
})
Can you tell me how can i intercept the requests!!
Known that Electron use "loadURL" to load urls
Sadly I can't. I have no experience with Electron. You might want to scour their documentation. Perhaps they have an easy way for you to intercept web requests they make, akin to you finding the onHeaders
callback. Suffice to say that if Mitm.js doesn't pick them up in your code above, then they do not go through Node.js as regular Http.get
-style requests do.
thank you anyway :)
You're welcome. I'll close this issue as there's nothing actionable for me right now, but feel free to continue chatting. ;)
Hi moll,
I have a question about your method to get url (req.connection.encrypted ? "https" : "http") + "://" + req.headers.host + req.url
Can I change the scheme of an URL, I want to change "https" by "http", How can i do this?
Known that i want also to modifi host, it is possible via req.headers.host.
Thank you
At that moment in code whatever changes you do to req
have no effect on the actual request — the original request will never go through, after all. If you possibly want to mutate something, you could look at the mitm.on("connect")
callback. Then you at least have a chance of the request actually hitting the Node internal Http
module.
Thank you
Hi, I'm developing an Electron application,
How can i use your MITM with my application, Have you any example?
Thank you