Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sdk-api): implement custom proxy agent support in BitGoAPI #5207

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/ts/http-proxy/create-wallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BitGoAPI } from '@bitgo/sdk-api';
import { Tpolygon } from '@bitgo/sdk-coin-polygon'; // Replace with your given coin (e.g. Ltc, Tltc)
import { ProxyAgent } from 'proxy-agent';

// This script emulates a front-end using the BitGo SDK to BitGo backend via a proxy.
// Set up the BitGo connection object.
Expand All @@ -10,7 +11,9 @@ const bitgo = new BitGoAPI({
// This *must* match the BitGo platform API your proxy instance is using.
env: 'test',
// TODO: In your real setup this would be <your.proxy.url>, where you host the proxy server.
proxy: 'http://localhost:3000',
customProxyAgent: new ProxyAgent({
getProxyForUrl: () => 'http://localhost:3000',
}),
});
const coin = 'tpolygon';
bitgo.register(coin, Tpolygon.createInstance);
Expand Down
8 changes: 4 additions & 4 deletions examples/ts/http-proxy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"author": "BitGo",
"license": "ISC",
"dependencies": {
"proxy": "2.1.1",
"proxy-agent": "6.4.0",
"superagent": "9.0.1",
"ts-node": "^10.8.1",
"typescript": "^4.7.3",
"typescript-cached-transpile": "^0.0.6",
"superagent": "9.0.1",
"proxy-agent": "6.4.0",
"proxy": "2.1.1"
"typescript-cached-transpile": "^0.0.6"
}
}
707 changes: 707 additions & 0 deletions examples/ts/http-proxy/yarn.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion modules/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"io-ts": "npm:@bitgo-forks/[email protected]",
"lodash": "^4.17.20",
"morgan": "^1.9.1",
"superagent": "^9.0.1"
"superagent": "^9.0.1",
"proxy-agent": "6.4.0"
},
"devDependencies": {
"@bitgo/public-types": "3.6.0",
Expand Down
10 changes: 10 additions & 0 deletions modules/express/src/clientRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
handleInitLightningWallet,
handleUnlockLightningWallet,
} from './lightning/lightningSignerRoutes';
import { ProxyAgent } from 'proxy-agent';

const { version } = require('bitgo/package.json');
const pjson = require('../package.json');
Expand Down Expand Up @@ -1213,12 +1214,21 @@ function prepareBitGo(config: Config) {
const userAgent = req.headers['user-agent']
? BITGOEXPRESS_USER_AGENT + ' ' + req.headers['user-agent']
: BITGOEXPRESS_USER_AGENT;

const useProxyUrl = process.env.BITGO_USE_PROXY;
const bitgoConstructorParams: BitGoOptions = {
env,
customRootURI: customRootUri,
customBitcoinNetwork,
accessToken,
userAgent,
...(useProxyUrl
? {
customProxyAgent: new ProxyAgent({
getProxyForUrl: () => useProxyUrl,
}),
}
: {}),
};

req.bitgo = new BitGo(bitgoConstructorParams);
Expand Down
1 change: 0 additions & 1 deletion modules/sdk-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"@types/superagent": "4.1.15",
"bitcoinjs-message": "npm:@bitgo-forks/[email protected]",
"bluebird": "^3.5.3",
"browser-or-node": "2.0.0",
"debug": "3.1.0",
"eol": "^0.5.0",
"lodash": "^4.17.15",
Expand Down
42 changes: 11 additions & 31 deletions modules/sdk-api/src/bitgoAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import * as sjcl from '@bitgo/sjcl';
import * as utxolib from '@bitgo/utxo-lib';
import { bip32, ECPairInterface } from '@bitgo/utxo-lib';
import * as bitcoinMessage from 'bitcoinjs-message';
import { isBrowser, isWebWorker } from 'browser-or-node';
import { createHmac } from 'crypto';
import { type Agent } from 'http';
import debugLib from 'debug';
import * as _ from 'lodash';
import * as secp256k1 from 'secp256k1';
Expand Down Expand Up @@ -96,14 +96,6 @@ const PendingApprovals = require('./v1/pendingapprovals');
const TravelRule = require('./v1/travelRule');
const TransactionBuilder = require('./v1/transactionBuilder');

let enableProxyAgent = false;
let proxyAgentModule;
if (!isBrowser && !isWebWorker) {
debug('enabling proxy-agent');
enableProxyAgent = true;
proxyAgentModule = require('proxy-agent');
}

const patchedRequestMethods = ['get', 'post', 'put', 'del', 'patch', 'options'] as const;

export class BitGoAPI implements BitGoBase {
Expand Down Expand Up @@ -138,6 +130,7 @@ export class BitGoAPI implements BitGoBase {
protected readonly _clientSecret?: string;
protected _validate: boolean;
public readonly cookiesPropagationEnabled: boolean;
private _customProxyAgent?: Agent;

constructor(params: BitGoAPIOptions = {}) {
this.cookiesPropagationEnabled = false;
Expand Down Expand Up @@ -278,15 +271,12 @@ export class BitGoAPI implements BitGoBase {
debug('HMAC verification explicitly disabled by constructor option');
this._hmacVerification = params.hmacVerification;
}
if (!params.proxy && process.env.BITGO_USE_PROXY) {
params.proxy = process.env.BITGO_USE_PROXY;
}

if ((process as any).browser && params.proxy) {
throw new Error('cannot use https proxy params while in browser');
if ((process as any).browser && params.customProxyAgent) {
throw new Error('should not use https proxy while in browser');
}

this._proxy = params.proxy;
this._customProxyAgent = params.customProxyAgent;

// capture outer stack so we have useful debug information if fetch constants fails
const e = new Error();
Expand Down Expand Up @@ -342,14 +332,10 @@ export class BitGoAPI implements BitGoBase {
*/
private requestPatch(method: (typeof patchedRequestMethods)[number], url: string) {
const req = this.getAgentRequest(method, url);
if (this._proxy && enableProxyAgent) {
debug('proxying request through %s', this._proxy);
const proxyUrl: string = this._proxy;
const agent = new proxyAgentModule.ProxyAgent({
getProxyForUrl: () => proxyUrl,
});
if (agent) {
req.agent(agent);
if (this._customProxyAgent) {
debug('using custom proxy agent');
if (this._customProxyAgent) {
req.agent(this._customProxyAgent);
}
}

Expand Down Expand Up @@ -585,14 +571,8 @@ export class BitGoAPI implements BitGoBase {
// Proxy settings must still be respected however
const resultPromise = this.getAgentRequest('get', this.url('/client/constants'));
resultPromise.set('BitGo-SDK-Version', this._version);
if (this._proxy && enableProxyAgent) {
const proxyUrl: string = this._proxy;
const agent = new proxyAgentModule.ProxyAgent({
getProxyForUrl: () => proxyUrl,
});
if (agent) {
resultPromise.agent(agent);
}
if (this._customProxyAgent) {
resultPromise.agent(this._customProxyAgent);
}
const result = await resultPromise;
BitGoAPI._constants[env] = result.body.constants;
Expand Down
3 changes: 2 additions & 1 deletion modules/sdk-api/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EnvironmentName, IRequestTracer, V1Network } from '@bitgo/sdk-core';
import { ECPairInterface } from '@bitgo/utxo-lib';
import { type Agent } from 'http';

export interface BitGoAPIOptions {
accessToken?: string;
Expand All @@ -17,7 +18,7 @@ export interface BitGoAPIOptions {
zksyncExplorerApiToken?: string;
bscscanApiToken?: string;
hmacVerification?: boolean;
proxy?: string;
customProxyAgent?: Agent;
refreshToken?: string;
serverXpub?: string;
stellarFederationServerUrl?: string;
Expand Down
14 changes: 9 additions & 5 deletions modules/sdk-api/test/unit/bitgoAPI.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'should';
import { BitGoAPI } from '../../src/bitgoAPI';
import { ProxyAgent } from 'proxy-agent';

describe('Constructor', function () {
describe('cookiesPropagationEnabled argument', function () {
Expand Down Expand Up @@ -36,23 +37,26 @@ describe('Constructor', function () {
});
});
describe('http proxy agent', function () {
it('http proxy agent shall be created when proxy is set', function () {
it('http proxy agent shall be created when proxy(customProxyagent) is set', function () {
const customProxyAgent = new ProxyAgent({
getProxyForUrl: () => 'http://localhost:3000',
});
const bitgo = new BitGoAPI({
env: 'custom',
customRootURI: 'https://app.example.local',
proxy: 'http://localhost:3000',
customProxyAgent,
});

bitgo.should.have.property('_proxy', 'http://localhost:3000');
bitgo.should.have.property('_customProxyAgent', customProxyAgent);
});

it('bitgo api is still initiated when proxy is not set', function () {
it('bitgo api is still initiated when proxy(customProxyAgent) is not set', function () {
const bitgo = new BitGoAPI({
env: 'custom',
customRootURI: 'https://app.example.local',
});

bitgo.should.have.property('_proxy', undefined);
bitgo.should.have.property('_customProxyAgent', undefined);
});
});

Expand Down
3 changes: 1 addition & 2 deletions webpack/bitgojs.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ module.exports = {
alias: {
// this is only required if using bitgo instead of just the sdk-api
'@hashgraph/sdk': path.resolve('../../node_modules/@hashgraph/sdk/src/browser.js'),
'proxy-agent': false,
// use the default version here since we're webpacking ourselves
'@bitgo/sdk-api': path.resolve('../sdk-api/dist/src/index.js'),
async: path.resolve('../../node_modules/async/index.js'),
Expand All @@ -36,7 +35,7 @@ module.exports = {
async: require.resolve('async'),
},
},
externals: ['morgan', 'proxy-agent', 'wasmer_wasi_js_bg.wasm'],
externals: ['morgan', 'wasmer_wasi_js_bg.wasm'],
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
Expand Down
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7321,11 +7321,6 @@ brorand@^1.0.1, brorand@^1.1.0:
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==

[email protected]:
version "2.0.0"
resolved "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.0.0.tgz#808ea90282a670931cdc0ea98166538a50dd0d89"
integrity sha512-3Lrks/Okgof+/cRguUNG+qRXSeq79SO3hY4QrXJayJofwJwHiGC0qi99uDjsfTwULUFSr1OGVsBkdIkygKjTUA==

browser-pack@^6.0.1:
version "6.1.0"
resolved "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774"
Expand Down
Loading