Add SpoofedNodeHttpImpl
Session spoofing is needed for making authenticated requests.master
parent
d47d77bb5e
commit
65ab92f701
|
@ -98,9 +98,10 @@ module.exports = Class( 'DataApiManager' )
|
|||
'private _apis': {},
|
||||
|
||||
|
||||
__construct: function( api_factory )
|
||||
__construct: function( api_factory, apis )
|
||||
{
|
||||
this._dataApiFactory = api_factory;
|
||||
this.setApis( apis || {} );
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -47,5 +47,9 @@ module.exports = Interface( 'HttpImpl',
|
|||
*
|
||||
* @return {HttpImpl} self
|
||||
*/
|
||||
'public requestData': [ 'url', 'method', 'data', 'callback' ]
|
||||
'public requestData': [ 'url', 'method', 'data', 'callback' ],
|
||||
|
||||
// TODO: temporary to work around class extension bug; see
|
||||
// SpoofedNodeHttpImpl
|
||||
'public setOptions': [],
|
||||
} );
|
||||
|
|
|
@ -98,7 +98,7 @@ module.exports = Class( 'NodeHttpImpl' )
|
|||
throw Error( `No handler for ${protocol}` );
|
||||
}
|
||||
|
||||
this._setOptions( options, method, data );
|
||||
this.setOptions( options, method, data );
|
||||
|
||||
let forbid_end = false;
|
||||
|
||||
|
@ -152,13 +152,16 @@ module.exports = Class( 'NodeHttpImpl' )
|
|||
/**
|
||||
* Set request options
|
||||
*
|
||||
* TODO: public to work around a class extension trait bug; make
|
||||
* protected once fixed
|
||||
*
|
||||
* @param {Object} options request options
|
||||
* @param {string} method HTTP method
|
||||
* @param {string} data request data
|
||||
*
|
||||
* @return {Object} request headers
|
||||
*/
|
||||
'private _setOptions'( options, method, data )
|
||||
'virtual public setOptions'( options, method, data )
|
||||
{
|
||||
const { headers = {} } = options;
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Node-based HTTP client with session spoofing
|
||||
*
|
||||
* Copyright (C) 2017 R-T Specialty, LLC.
|
||||
*
|
||||
* This file is part of the Liza Data Collection Framework.
|
||||
*
|
||||
* liza is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Trait } = require( 'easejs' );
|
||||
const HttpImpl = require( './HttpImpl' );
|
||||
|
||||
|
||||
/**
|
||||
* Spoof user session during request
|
||||
*
|
||||
* TODO: Implementing HttpImpl instead of overriding NodeHttpImpl to work
|
||||
* around a class extension bug; change once fixed.
|
||||
*/
|
||||
module.exports = Trait( 'SpoofedNodeHttpImpl' )
|
||||
.implement( HttpImpl )
|
||||
.extend(
|
||||
{
|
||||
/**
|
||||
* Session to spoof
|
||||
* @type {UserSession}
|
||||
*/
|
||||
'private _request': null,
|
||||
|
||||
|
||||
/**
|
||||
* Use session for spoofing requests
|
||||
*
|
||||
* @param {UserSession} session session to spoof
|
||||
*/
|
||||
__mixin( session )
|
||||
{
|
||||
this._request = session;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Set request options to spoof session
|
||||
*
|
||||
* @param {Object} options request options
|
||||
* @param {string} method HTTP method
|
||||
* @param {string} data request data
|
||||
*
|
||||
* @return {Object} request headers
|
||||
*/
|
||||
'virtual abstract override public setOptions'( options, method, data )
|
||||
{
|
||||
const cookie = this._request.getSessionIdName() + '=' +
|
||||
this._request.getSessionId();
|
||||
|
||||
options.headers = {
|
||||
'User-Agent': this._request.getUserAgent(),
|
||||
'X-Forwarded-For': this._request.getRemoteAddr(),
|
||||
'Cookie': cookie,
|
||||
};
|
||||
|
||||
return this.__super( options, method, data );
|
||||
}
|
||||
} );
|
|
@ -279,5 +279,11 @@ module.exports = Class( 'XhrHttpImpl' )
|
|||
e.status = req.status;
|
||||
|
||||
callback( e, req.responseText );
|
||||
},
|
||||
|
||||
|
||||
'public setOptions'()
|
||||
{
|
||||
// TOOD: remove (see HttpImpl)
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -27,7 +27,11 @@ var dapi = require( '../../../' ).dapi,
|
|||
dummy_url = 'http://foo',
|
||||
dummy_impl = Class
|
||||
.implement( dapi.http.HttpImpl )
|
||||
.extend( { requestData: function( _, __, ___, ____ ) {} } )(),
|
||||
.extend(
|
||||
{
|
||||
requestData: function( _, __, ___, ____ ) {},
|
||||
setOptions() {},
|
||||
} )(),
|
||||
|
||||
dummy_sut = Sut( dummy_url, 'GET', dummy_impl );
|
||||
|
||||
|
@ -86,7 +90,9 @@ describe( 'HttpDataApi', function()
|
|||
{
|
||||
this.provided = arguments;
|
||||
c( this.err, this.data );
|
||||
}
|
||||
},
|
||||
|
||||
setOptions() {},
|
||||
} )();
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Tests Node-based HTTP client with session spoofing
|
||||
*
|
||||
* Copyright (C) 2017 R-T Specialty, LLC.
|
||||
*
|
||||
* This file is part of the Liza Data Collection Framework.
|
||||
*
|
||||
* liza is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { expect } = require( 'chai' );
|
||||
const {
|
||||
SpoofedNodeHttpImpl: Sut,
|
||||
NodeHttpImpl,
|
||||
} = require( '../../../' ).dapi.http;
|
||||
|
||||
|
||||
describe( 'SpoofNodeHttpImpl', () =>
|
||||
{
|
||||
it( "adds session headers", done =>
|
||||
{
|
||||
const user_agent = 'Agent Foo';
|
||||
const forward_for = '::1';
|
||||
const sessname = 'FOOSESSID';
|
||||
const sessid = '12345';
|
||||
|
||||
const protos = {
|
||||
http: {
|
||||
request( given )
|
||||
{
|
||||
expect( given.headers[ 'User-Agent' ] )
|
||||
.to.equal( user_agent );
|
||||
expect( given.headers[ 'X-Forwarded-For' ] )
|
||||
.to.equal( forward_for );
|
||||
|
||||
expect( given.headers.Cookie )
|
||||
.to.contain( sessname + '=' + sessid );
|
||||
|
||||
done();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const url = {
|
||||
parse: () => ( {
|
||||
protocol: 'http',
|
||||
} )
|
||||
};
|
||||
|
||||
const session = getStubSession( {
|
||||
agent: user_agent,
|
||||
forward_for: forward_for,
|
||||
sessname: sessname,
|
||||
sessid: sessid,
|
||||
} );
|
||||
|
||||
const given = NodeHttpImpl.use( Sut( session ) )( protos, url )
|
||||
.requestData( '', '', {}, ()=>{} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
function getStubSession( { agent, forward_for, sessname, sessid } )
|
||||
{
|
||||
return {
|
||||
getUserAgent: () => agent,
|
||||
getRemoteAddr: () => forward_for,
|
||||
getSessionIdName: () => sessname,
|
||||
getSessionId: () => sessid,
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue