Add local modules to fix http headers privacy problem

This commit is contained in:
Ayanami 2021-12-08 01:52:08 +09:00
parent 8838234e09
commit 2c173c6300
No known key found for this signature in database
GPG Key ID: 0CABDF03077D92E4
53 changed files with 11524 additions and 626 deletions

View File

@ -0,0 +1,47 @@
# web3-providers-http
[![NPM Package][npm-image]][npm-url] [![Dependency Status][deps-image]][deps-url] [![Dev Dependency Status][deps-dev-image]][deps-dev-url]
Package forked from https://github.com/ChainSafe/web3.js/tree/v1.6.1/packages/web3-providers-http to change http headers
This is a HTTP provider sub-package for [web3.js][repo].
Please read the [documentation][docs] for more.
## Installation
### Node.js
```bash
npm install web3-providers-http
```
## Usage
```js
const http = require('http');
const Web3HttpProvider = require('web3-providers-http');
const options = {
keepAlive: true,
timeout: 20000, // milliseconds,
headers: [{name: 'Access-Control-Allow-Origin', value: '*'},{...}],
withCredentials: false,
agent: {http: http.Agent(...), baseUrl: ''}
};
const provider = new Web3HttpProvider('http://localhost:8545', options);
```
## Types
All the TypeScript typings are placed in the `types` folder.
[docs]: http://web3js.readthedocs.io/en/1.0/
[repo]: https://github.com/ethereum/web3.js
[npm-image]: https://img.shields.io/npm/dm/web3-providers-http.svg
[npm-url]: https://npmjs.org/package/web3-providers-http
[deps-image]: https://david-dm.org/ethereum/web3.js/1.x/status.svg?path=packages/web3-providers-http
[deps-url]: https://david-dm.org/ethereum/web3.js/1.x?path=packages/web3-providers-http
[deps-dev-image]: https://david-dm.org/ethereum/web3.js/1.x/dev-status.svg?path=packages/web3-providers-http
[deps-dev-url]: https://david-dm.org/ethereum/web3.js/1.x?type=dev&path=packages/web3-providers-http

View File

@ -0,0 +1,125 @@
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file httpprovider.js
* @authors:
* Marek Kotewicz <marek@parity.io>
* Marian Oancea
* Fabian Vogelsteller <fabian@ethereum.org>
* @date 2015
*/
var errors = require('web3-core-helpers').errors;
var XHR2 = require('xhr2-cookies').XMLHttpRequest; // jshint ignore: line
var http = require('http');
var https = require('https');
/**
* HttpProvider should be used to send rpc calls over http
*/
var HttpProvider = function HttpProvider(host, options) {
options = options || {};
this.withCredentials = options.withCredentials || false;
this.timeout = options.timeout || 0;
this.headers = options.headers;
this.agent = options.agent;
this.connected = false;
// keepAlive is true unless explicitly set to false
const keepAlive = options.keepAlive !== false;
this.host = host || 'http://localhost:8545';
if (!this.agent) {
if (this.host.substring(0, 5) === "https") {
this.httpsAgent = new https.Agent({ keepAlive });
}
else {
this.httpAgent = new http.Agent({ keepAlive });
}
}
};
HttpProvider.prototype._prepareRequest = function () {
var request;
// the current runtime is a browser
if (typeof XMLHttpRequest !== 'undefined') {
request = new XMLHttpRequest();
}
else {
request = new XHR2();
var agents = { httpsAgent: this.httpsAgent, httpAgent: this.httpAgent, baseUrl: this.baseUrl };
if (this.agent) {
agents.httpsAgent = this.agent.https;
agents.httpAgent = this.agent.http;
agents.baseUrl = this.agent.baseUrl;
}
request.nodejsSet(agents);
}
request.open('POST', this.host, true);
request.setRequestHeader('Content-Type', 'application/json');
request.timeout = this.timeout;
request.withCredentials = this.withCredentials;
if (this.headers) {
this.headers.forEach(function (header) {
request.setRequestHeader(header.name, header.value);
});
}
return request;
};
/**
* Should be used to make async request
*
* @method send
* @param {Object} payload
* @param {Function} callback triggered on end with (err, result)
*/
HttpProvider.prototype.send = function (payload, callback) {
var _this = this;
var request = this._prepareRequest();
request.onreadystatechange = function () {
if (request.readyState === 4 && request.timeout !== 1) {
var result = request.responseText;
var error = null;
try {
result = JSON.parse(result);
}
catch (e) {
error = errors.InvalidResponse(request.responseText);
}
_this.connected = true;
callback(error, result);
}
};
request.ontimeout = function () {
_this.connected = false;
callback(errors.ConnectionTimeout(this.timeout));
};
try {
request.send(JSON.stringify(payload));
}
catch (error) {
this.connected = false;
callback(errors.InvalidConnection(this.host));
}
};
HttpProvider.prototype.disconnect = function () {
//NO OP
};
/**
* Returns the desired boolean.
*
* @method supportsSubscriptions
* @returns {boolean}
*/
HttpProvider.prototype.supportsSubscriptions = function () {
return false;
};
module.exports = HttpProvider;

View File

@ -0,0 +1,6 @@
node_modules
yarn-error.log
.idea
**/*.js
**/*.js.map
!wallaby.js

View File

@ -0,0 +1,4 @@
*
.idea
!dist/*
!package.json

View File

@ -0,0 +1,30 @@
# XMLHttpRequest polyfill for node.js
Based on [https://github.com/pwnall/node-xhr2/tree/bd6d48431ad93c8073811e5d4b77394dd637a85a](https://github.com/pwnall/node-xhr2/tree/bd6d48431ad93c8073811e5d4b77394dd637a85a)
* Adds support for cookies
* Adds in-project TypeScript type definitions
* Switched to TypeScript
### Cookies
* saved in `XMLHttpRequest.cookieJar`
* saved between redirects
* saved between requests
* can be cleared by doing:
```typescript
import * as Cookie from 'cookiejar';
XMLHttpRequest.cookieJar = Cookie.CookieJar();
```
### Aims
* Provide full XMLHttpRequest features to Angular Universal HttpClient &
`node-angular-http-client`
### Changelog
#### `1.1.0`
* added saving of cookies between requests, not just redirects
* bug fixes
* most tests from `xhr2` ported over and passing

View File

@ -0,0 +1,8 @@
export declare class SecurityError extends Error {
}
export declare class InvalidStateError extends Error {
}
export declare class NetworkError extends Error {
}
export declare class SyntaxError extends Error {
}

View File

@ -0,0 +1,2 @@
export * from './xml-http-request';
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';

View File

@ -0,0 +1,11 @@
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
export declare class ProgressEvent {
type: string;
bubbles: boolean;
cancelable: boolean;
target: XMLHttpRequestEventTarget;
loaded: number;
lengthComputable: boolean;
total: number;
constructor(type: string);
}

View File

@ -0,0 +1,19 @@
import { ProgressEvent } from './progress-event';
export declare type ProgressEventListener = (event: ProgressEvent) => void;
export declare type ProgressEventListenerObject = {
handleEvent(event: ProgressEvent): void;
};
export declare type ProgressEventListenerOrEventListenerObject = ProgressEventListener | ProgressEventListenerObject;
export declare class XMLHttpRequestEventTarget {
onloadstart: ProgressEventListener | null;
onprogress: ProgressEventListener | null;
onabort: ProgressEventListener | null;
onerror: ProgressEventListener | null;
onload: ProgressEventListener | null;
ontimeout: ProgressEventListener | null;
onloadend: ProgressEventListener | null;
private listeners;
addEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject): void;
removeEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject): void;
dispatchEvent(event: ProgressEvent): boolean;
}

View File

@ -0,0 +1,12 @@
/// <reference types="node" />
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
import { ClientRequest } from 'http';
export declare class XMLHttpRequestUpload extends XMLHttpRequestEventTarget {
private _contentType;
private _body;
constructor();
_reset(): void;
_setData(data?: string | Buffer | ArrayBuffer | ArrayBufferView): void;
_finalizeHeaders(headers: object, loweredHeaders: object): void;
_startUpload(request: ClientRequest): void;
}

View File

@ -0,0 +1,102 @@
/// <reference types="node" />
import { ProgressEvent } from './progress-event';
import { InvalidStateError, NetworkError, SecurityError, SyntaxError } from './errors';
import { ProgressEventListener, XMLHttpRequestEventTarget } from './xml-http-request-event-target';
import { XMLHttpRequestUpload } from './xml-http-request-upload';
import { Url } from 'url';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';
export interface XMLHttpRequestOptions {
anon?: boolean;
}
export interface XHRUrl extends Url {
method?: string;
}
export declare class XMLHttpRequest extends XMLHttpRequestEventTarget {
static ProgressEvent: typeof ProgressEvent;
static InvalidStateError: typeof InvalidStateError;
static NetworkError: typeof NetworkError;
static SecurityError: typeof SecurityError;
static SyntaxError: typeof SyntaxError;
static XMLHttpRequestUpload: typeof XMLHttpRequestUpload;
static UNSENT: number;
static OPENED: number;
static HEADERS_RECEIVED: number;
static LOADING: number;
static DONE: number;
static cookieJar: any;
UNSENT: number;
OPENED: number;
HEADERS_RECEIVED: number;
LOADING: number;
DONE: number;
onreadystatechange: ProgressEventListener | null;
readyState: number;
response: string | ArrayBuffer | Buffer | object | null;
responseText: string;
responseType: string;
status: number;
statusText: string;
timeout: number;
upload: XMLHttpRequestUpload;
responseUrl: string;
withCredentials: boolean;
nodejsHttpAgent: HttpsAgent;
nodejsHttpsAgent: HttpsAgent;
nodejsBaseUrl: string | null;
private _anonymous;
private _method;
private _url;
private _sync;
private _headers;
private _loweredHeaders;
private _mimeOverride;
private _request;
private _response;
private _responseParts;
private _responseHeaders;
private _aborting;
private _error;
private _loadedBytes;
private _totalBytes;
private _lengthComputable;
private _restrictedMethods;
private _restrictedHeaders;
private _privateHeaders;
private _userAgent;
constructor(options?: XMLHttpRequestOptions);
open(method: string, url: string, async?: boolean, user?: string, password?: string): void;
setRequestHeader(name: string, value: any): void;
send(data?: string | Buffer | ArrayBuffer | ArrayBufferView): void;
abort(): void;
getResponseHeader(name: string): string;
getAllResponseHeaders(): string;
overrideMimeType(mimeType: string): void;
nodejsSet(options: {
httpAgent?: HttpAgent;
httpsAgent?: HttpsAgent;
baseUrl?: string;
}): void;
static nodejsSet(options: {
httpAgent?: HttpAgent;
httpsAgent?: HttpsAgent;
baseUrl?: string;
}): void;
private _setReadyState(readyState);
private _sendFile(data);
private _sendHttp(data?);
private _sendHxxpRequest();
private _finalizeHeaders();
private _onHttpResponse(request, response);
private _onHttpResponseData(response, data);
private _onHttpResponseEnd(response);
private _onHttpResponseClose(response);
private _onHttpTimeout(request);
private _onHttpRequestError(request, error);
private _dispatchProgress(eventType);
private _setError();
private _parseUrl(urlString, user?, password?);
private _parseResponseHeaders(response);
private _parseResponse();
private _parseResponseEncoding();
}

View File

@ -0,0 +1,4 @@
export class SecurityError extends Error {}
export class InvalidStateError extends Error {}
export class NetworkError extends Error {}
export class SyntaxError extends Error {}

View File

@ -0,0 +1,2 @@
export * from './xml-http-request';
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';

View File

@ -0,0 +1,48 @@
{
"name": "xhr2-cookies",
"version": "1.1.0",
"author": "Ionut Costica <ionut.costica@gmail.com>",
"license": "MIT",
"description": "XMLHttpRequest polyfill for node.js",
"repository": "git://github.com/souldreamer/xhr2-cookies.git",
"keywords": [
"XMLHttpRequest",
"cookies",
"xhr2"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"dependencies": {
"cookiejar": "^2.1.1"
},
"devDependencies": {
"@types/body-parser": "^1.16.8",
"@types/cookie-parser": "^1.4.1",
"@types/express": "^4.0.39",
"@types/morgan": "^1.7.35",
"@types/node": "^6",
"ava": "^0.23.0",
"ava-ts": "^0.23.0",
"body-parser": "^1.18.2",
"cookie-parser": "^1.4.3",
"express": "^4.16.2",
"morgan": "^1.9.0",
"ts-loader": "^2.3.4",
"ts-node": "^3.3.0",
"typescript": "^2.5.2",
"webpack": "^3.5.5"
},
"scripts": {
"prepare": "tsc",
"test": "tsc -p ./test && ava-ts -v"
},
"ava": {
"files": [
"test/*.spec.ts"
],
"source": [
"*.ts",
"!dist/**/*"
]
}
}

View File

@ -0,0 +1,12 @@
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
export class ProgressEvent {
bubbles = false;
cancelable = false;
target: XMLHttpRequestEventTarget;
loaded = 0;
lengthComputable = false;
total = 0;
constructor (public type: string) {}
}

View File

@ -0,0 +1,59 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
import * as Cookie from 'cookiejar';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
XMLHttpRequest.cookieJar = Cookie.CookieJar();
});
test('XMLHttpRequest sets cookies and passes them on on redirect', async t => {
const xhr = t.context.xhr;
t.plan(1);
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect-cookie/test/works`);
xhr.withCredentials = true;
xhr.onload = () => {
t.is(xhr.responseText, 'works');
resolve();
};
xhr.send();
});
});
test('XMLHttpRequest sets cookies and uses them for subsequent calls', async t => {
let xhr = t.context.xhr;
t.plan(1);
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/set-cookie/second-test/works`);
xhr.withCredentials = true;
xhr.onload = resolve;
xhr.send();
});
xhr = new XMLHttpRequest();
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/print-cookie/second-test`);
xhr.withCredentials = true;
xhr.onload = () => {
t.is(xhr.responseText, 'works');
resolve();
};
xhr.send();
});
});

View File

@ -0,0 +1,101 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { ProgressEvent } from '../progress-event';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest(),
loadEvent: new ProgressEvent('load')
}));
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
t.context.loadEvent = new ProgressEvent('load');
});
test('XMLHttpRequestEventTarget dispatchEvent works with a DOM0 listener', t => {
t.plan(1);
t.context.xhr.onload = () => t.pass();
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget dispatchEvent works with a DOM2 listener', t => {
t.plan(1);
t.context.xhr.addEventListener('load', () => t.pass());
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget dispatchEvent executes DOM2 listeners in order', t => {
t.plan(1);
let firstExecuted = false;
t.context.xhr.addEventListener('load', () => firstExecuted = true);
t.context.xhr.addEventListener('load', () => {
if (firstExecuted) { t.pass(); }
});
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget removes a DOM2 listener correctly', t => {
t.plan(1);
const listener = () => t.pass();
t.context.xhr.addEventListener('load', listener);
t.context.xhr.dispatchEvent(t.context.loadEvent);
t.context.xhr.removeEventListener('load', listener);
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget binds this correctly in a DOM0 listener', t => {
t.plan(1);
t.context.xhr.onload = function () { if (this === t.context.xhr) { t.pass(); } };
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget binds this correctly in a DOM2 listener', t => {
t.plan(1);
t.context.xhr.addEventListener('load', function () { if (this === t.context.xhr) { t.pass(); } });
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget sets target correctly in a DOM0 listener', t => {
t.plan(1);
t.context.xhr.onload = function (event) { if (event.target === t.context.xhr) { t.pass(); } };
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget sets target correctly in a DOM2 listener', t => {
t.plan(1);
t.context.xhr.addEventListener('load', function (event) { if (event.target === t.context.xhr) { t.pass(); } });
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget works with a DOM0 and two DOM2 listeners', t => {
t.plan(3);
t.context.xhr.addEventListener('load', () => t.pass());
t.context.xhr.onload = () => t.pass();
t.context.xhr.addEventListener('load', () => t.pass());
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget does not invoke a DOM0 listener for a different event', t => {
t.plan(0);
['onerror', 'onloadstart', 'onprogress', 'onabort', 'ontimeout', 'onloadend']
.forEach(eventType => t.context.xhr[eventType] = () => t.pass());
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
test('XMLHttpRequestEventTarget does not invoke a DOM2 listener for a different event', t => {
t.plan(0);
['error', 'loadstart', 'progress', 'abort', 'timeout', 'loadend']
.forEach(eventType => t.context.xhr.addEventListener(eventType, () => t.pass()));
t.context.xhr.dispatchEvent(t.context.loadEvent);
});
// TODO:
// * remove event listener from an event that had no listeners
// * remove non-existent event listener from an event that had listeners

View File

@ -0,0 +1,249 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest(),
dripUrl: `http://localhost:${HttpServer.port}/_/drip`,
dripJson: {drips: 3, size: 1000, ms: 50, length: true},
}));
test.before(async () => {
await HttpServer.serverStarted;
XMLHttpRequest.nodejsSet({
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
});
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
});
test('level 2 events for a successful fetch with Content-Length set', async t => {
let endFired = false;
let intermediateProgressFired = false;
const xhr = t.context.xhr;
await new Promise(resolve => {
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
xhr.addEventListener('loadend', () => {
endFired = true;
resolve();
});
xhr.addEventListener('error', () => resolve());
xhr.open('POST', t.context.dripUrl);
xhr.send(JSON.stringify(t.context.dripJson));
});
t.true(intermediateProgressFired, 'at least one intermediate progress event was fired');
function addCheckedEvent(eventType: string) {
xhr.addEventListener(eventType, event => {
t.is(event.type, eventType, `event type is ${eventType}`);
t.is(event.target, xhr, 'event has correct target');
t.false(endFired, 'end is not fired');
t.false(event.bubbles, 'event does not bubble');
t.false(event.cancelable, 'event is not cancelable');
switch (eventType) {
case 'loadstart':
t.is(event.loaded, 0, 'on loadstart loaded = 0');
t.false(event.lengthComputable, 'on loadstart length is not computable');
t.is(event.total, 0, 'on loadstart event total is 0');
break;
case 'load':
case 'loadend':
t.is(event.loaded, 3000, 'on load/loadend loaded = 3000');
t.true(event.lengthComputable, 'on load/loadend length is computable');
t.is(event.total, 3000, 'on load/loadend event total is 0');
break;
case 'progress':
t.true(event.loaded >= 0, 'on progress: loaded >= 0');
t.true(event.loaded <= 3000, 'on progress: loaded <= 3000');
if (event.lengthComputable) {
t.is(event.total, 3000, 'on progress event when length is computable total is 3000');
} else {
t.is(event.total, 0, 'on progress event when length is not computable total is 0');
}
if (event.loaded > 0 && event.loaded < 3000) { intermediateProgressFired = true; }
break;
}
})
}
});
test('level 2 events for a successful fetch without Content-Length set', async t => {
let endFired = false;
let intermediateProgressFired = false;
const xhr = t.context.xhr;
t.context.dripJson = {...t.context.dripJson, length: false};
await new Promise(resolve => {
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
xhr.addEventListener('loadend', () => {
endFired = true;
resolve();
});
xhr.open('POST', t.context.dripUrl);
xhr.send(JSON.stringify(t.context.dripJson));
});
t.true(intermediateProgressFired, 'at least one intermediate progress event was fired');
function addCheckedEvent(eventType: string) {
xhr.addEventListener(eventType, event => {
t.is(event.type, eventType, `event type is ${eventType}`);
t.is(event.target, xhr, 'event has correct target');
t.false(endFired, 'end is not fired');
t.false(event.bubbles, 'event does not bubble');
t.false(event.cancelable, 'event is not cancelable');
t.false(event.lengthComputable, 'length is not computable');
t.is(event.total, 0, 'when length is not computable total is 0');
switch (eventType) {
case 'loadstart':
t.is(event.loaded, 0, 'on loadstart loaded = 0');
break;
case 'load':
case 'loadend':
t.is(event.loaded, 3000, 'on load/loadend loaded = 3000');
break;
case 'progress':
t.true(event.loaded >= 0, 'on progress: loaded >= 0');
t.true(event.loaded <= 3000, 'on progress: loaded <= 3000');
if (event.loaded > 0 && event.loaded < 3000) { intermediateProgressFired = true; }
break;
}
})
}
});
test('level 2 events for a network error due to bad DNS', async t => {
let errorFired = false;
const xhr = t.context.xhr;
await new Promise(resolve => {
['loadstart', 'progress', 'load', 'loadend', 'error', 'abort'].forEach(addCheckedEvent);
xhr.addEventListener('loadend', () => resolve());
xhr.open('GET', 'https://broken.to.cause.an.xhrnetworkerror.com.a.com');
xhr.send();
});
t.true(errorFired, 'an error event was fired');
function addCheckedEvent(eventType: string) {
xhr.addEventListener(eventType, () => {
switch (eventType) {
case 'load':
case 'progress':
t.fail();
break;
case 'error':
errorFired = true;
break;
}
})
}
});
test('readystatechange for a successful fetch with Content-Length set', async t => {
let doneFired = false;
const xhr = t.context.xhr;
const states = [];
await new Promise(resolve => {
xhr.addEventListener('readystatechange', event => {
t.is(event.type, 'readystatechange', 'event type is correct');
t.false(doneFired, 'no readystatechange events after DONE');
t.is(event.target, xhr, 'event has correct target');
t.false(event.bubbles, 'event does not bubble');
t.false(event.cancelable, 'event is not cancelable');
states.push((event.target as XMLHttpRequest).readyState);
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
doneFired = true;
resolve();
}
});
xhr.open('POST', t.context.dripUrl);
xhr.send(JSON.stringify(t.context.dripJson));
});
t.deepEqual(states, [
XMLHttpRequest.OPENED,
XMLHttpRequest.HEADERS_RECEIVED,
XMLHttpRequest.LOADING,
XMLHttpRequest.DONE
], 'right order of ready states');
});
test('readystatechange for a successful fetch without Content-Length set', async t => {
let doneFired = false;
const xhr = t.context.xhr;
const states = [];
t.context.dripJson = {...t.context.dripJson, length: false};
await new Promise(resolve => {
xhr.addEventListener('readystatechange', event => {
t.is(event.type, 'readystatechange', 'event type is correct');
t.false(doneFired, 'no readystatechange events after DONE');
t.is(event.target, xhr, 'event has correct target');
t.false(event.bubbles, 'event does not bubble');
t.false(event.cancelable, 'event is not cancelable');
t.false(event.lengthComputable, 'length is not computable');
t.is(event.total, 0, 'when length is not computable total is 0');
states.push((event.target as XMLHttpRequest).readyState);
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
doneFired = true;
resolve();
}
});
xhr.open('POST', t.context.dripUrl);
xhr.send(JSON.stringify(t.context.dripJson));
});
t.deepEqual(states, [
XMLHttpRequest.OPENED,
XMLHttpRequest.HEADERS_RECEIVED,
XMLHttpRequest.LOADING,
XMLHttpRequest.DONE
], 'right order of ready states');
});
test('readystatechange for a network error due to bad DNS', async t => {
const xhr = t.context.xhr;
const states = [];
await new Promise(resolve => {
xhr.addEventListener('readystatechange', event => {
t.is(event.type, 'readystatechange', 'event type is correct');
t.is(event.target, xhr, 'event has correct target');
t.false(event.bubbles, 'event does not bubble');
t.false(event.cancelable, 'event is not cancelable');
states.push((event.target as XMLHttpRequest).readyState);
if ((event.target as XMLHttpRequest).readyState === XMLHttpRequest.DONE) {
resolve();
}
});
xhr.open('GET', 'https://broken.to.cause.an.xhrnetworkerror.com.a.com');
xhr.send();
});
t.deepEqual(states, [
XMLHttpRequest.OPENED,
XMLHttpRequest.DONE
], 'right order of ready states');
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

View File

@ -0,0 +1,189 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async () => {
await HttpServer.serverStarted;
XMLHttpRequest.nodejsSet({
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
});
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
});
test('#setRequestHeader with allowed headers should send the headers', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
xhr.responseType = 'text';
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('X-Answer', '42');
xhr.setRequestHeader('X-Header-Name', 'value');
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
const headers = JSON.parse(xhr.responseText);
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
t.is(headers.authorization, 'lol', 'authorization header is correct');
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
t.is(headers['x-answer'], '42', 'x-answer header is correct');
t.true(headers.hasOwnProperty('x-header-name'), 'headers have x-header-name header');
t.is(headers['x-header-name'], 'value', 'x-header-name header is correct');
resolve();
};
xhr.send('');
});
});
test('#setRequestHeader with a mix of allowed and forbidden headers should only send the allowed headers', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
xhr.responseType = 'text';
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('Proxy-Authorization', 'evil:kitten');
xhr.setRequestHeader('Sec-Breach', 'yes please');
xhr.setRequestHeader('Host', 'www.google.com');
xhr.setRequestHeader('Origin', 'https://www.google.com');
xhr.setRequestHeader('X-Answer', '42');
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
const headers = JSON.parse(xhr.responseText);
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
t.is(headers['authorization'], 'lol', 'authorization header is correct');
t.false(headers.hasOwnProperty('proxy-authorization'), 'headers do not have proxy-authorization header');
t.false(headers.hasOwnProperty('sec-breach'), 'headers do not have sec-breach header');
t.notRegex(headers['origin'] || '', /www\.google\.com/, 'header "origin" should not contain www.google.com');
t.notRegex(headers['host'] || '', /www\.google\.com/, 'header "host" should not contain www.google.com');
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
t.is(headers['x-answer'], '42', 'x-answer header is correct');
resolve();
};
xhr.send('');
});
});
test('#setRequestHeader with repeated headers should send all headers', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
xhr.responseType = 'text';
xhr.setRequestHeader('Authorization', 'troll');
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('X-Answer', '42');
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
const headers = JSON.parse(xhr.responseText);
t.true(headers.hasOwnProperty('authorization'), 'headers have authorization header');
t.is(headers['authorization'], 'troll, lol, lol', 'authorization header is correct');
t.true(headers.hasOwnProperty('x-answer'), 'headers have x-answer header');
t.is(headers['x-answer'], '42', 'x-answer header is correct');
resolve();
};
xhr.send('');
});
});
test('#setRequestHeader with no headers should set the protected headers correctly', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
xhr.responseType = 'text';
xhr.setRequestHeader('Authorization', 'troll');
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('Authorization', 'lol');
xhr.setRequestHeader('X-Answer', '42');
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/, 'response text looks like JSON');
const headers = JSON.parse(xhr.responseText);
t.true(headers.hasOwnProperty('connection'), 'headers have connection header');
t.is(headers['connection'], 'keep-alive', 'connection header is correct');
t.true(headers.hasOwnProperty('host'), 'headers have host header');
t.is(headers['host'], `localhost:${HttpServer.port}`, 'host header is correct');
t.true(headers.hasOwnProperty('user-agent'), 'headers have user-agent header');
t.regex(headers['user-agent'], /^Mozilla\//, 'user-agent header is correct');
resolve();
};
xhr.send('');
});
});
test('#getResponseHeader returns accessible headers, returns null for private headers, has headers on HEADERS_RECEIVED readyState', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/get-headers`);
const headerJson = `{
"Accept-Ranges": "bytes",
"Content-Type": "application/xhr2; charset=utf-1337",
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
"X-Header": "one, more, value"
}`;
await new Promise(resolve => {
xhr.onloadend = () => {
t.is(xhr.getResponseHeader('AccEPt-RANgeS'), 'bytes', 'AccEPt-RANgeS works correctly');
t.is(xhr.getResponseHeader('content-Type'), 'application/xhr2; charset=utf-1337', 'content-Type works correctly');
t.is(xhr.getResponseHeader('X-Header'), 'one, more, value', 'X-Header works correctly');
t.is(xhr.getResponseHeader('set-cookie'), null, 'set-cookie works correctly');
resolve();
};
xhr.onreadystatechange = () => {
if (xhr.readyState !== XMLHttpRequest.HEADERS_RECEIVED) { return; }
t.is(xhr.getResponseHeader('AccEPt-RANgeS'), 'bytes', 'AccEPt-RANgeS works correctly when HEADERS_RECEIVED ready state');
};
xhr.send(headerJson);
});
});
test('#getAllResponseHeaders contains accessible headers, does not contain private headers, has headers on HEADERS_RECEIVED readyState', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/get-headers`);
const headerJson = `{
"Accept-Ranges": "bytes",
"Content-Type": "application/xhr2; charset=utf-1337",
"Set-Cookie": "UserID=JohnDoe; Max-Age=3600; Version=1",
"X-Header": "one, more, value"
}`;
await new Promise(resolve => {
xhr.onloadend = () => {
const headers = xhr.getAllResponseHeaders();
t.regex(headers, /(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi);
t.regex(headers, /(\A|\r\n)content-type: application\/xhr2; charset=utf-1337(\r\n|\Z)/mi);
t.regex(headers, /(\A|\r\n)X-Header: one, more, value(\r\n|\Z)/mi);
t.notRegex(headers, /(\A|\r\n)set-cookie:/mi);
resolve();
};
xhr.onreadystatechange = () => {
if (xhr.readyState !== XMLHttpRequest.HEADERS_RECEIVED) { return; }
const headers = xhr.getAllResponseHeaders();
t.regex(headers, /(\A|\r\n)accept-ranges: bytes(\r\n|\Z)/mi);
};
xhr.send(headerJson);
});
});
// TODO:
// * set request header after request opened should throw InvalidStateError
// *

View File

@ -0,0 +1,50 @@
export const certificate = `-----BEGIN CERTIFICATE-----
MIIDXjCCAkYCCQCgZ4DViKxZtTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJS
TzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTALBgNV
BAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYIWEBY
WC5YWFgwHhcNMTcxMTEzMTQzMTE2WhcNMjAwOTAyMTQzMTE2WjBxMQswCQYDVQQG
EwJSTzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTAL
BgNVBAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYI
WEBYWC5YWFgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyJ+21siOW
oRkgVSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx
6ks6mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI
76MVjLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJ
P8mIAoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouig
RsjhFxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyb
lxhui0rfu8fFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABphKcUJbdEhUpWF4EZE
BBl/uzE4/WXtQZdgz3fGpvpzmXZBRtbkdPR3jxBW1c9asCfb366dXRb8im6/p6ae
sAxZINMKIQ8KCIEb+StVMc4MvxASMm1SSz/kFuTCA2Q8vD5sHJrFcoKk6HKNEOLu
dALKpO8ZDuxjv036sCnjfyDue9psSccsLuAhfr2NLL5Ky9lWrJFi3b35D5UHrlK/
9mb9izRgZSC9+sZgpSyvIK6idKoWB4s9RpCn8itucFHHUDOvv8DdwvsF/5iVyWz7
R5uR4/qA8k7lbHHLosu2ELyx3N6Go0AskjxzsONPOKNlGIDllTx21mkIvTkGlJgs
8/4=
-----END CERTIFICATE-----
`;
export const key = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAsifttbIjlqEZIFUqUDGlAMP0eeBhvfJPSBDEJxgaA+x5Z1+G
r4M9HzWgP8TXULilWakdKLIQsepLOpl+M/52B4eEjZkFZgB+5iZ0+Wqh1bODqZVV
OWZmTbAce/uyRBZOuBu5NNdayO+jFYy6zWCUk5YK7WDnDSZXumsAsJiNp7Kx0iSX
sjFThlCvB/UQ87Dz2SEEtLuMCT/JiAKJZ/5qYD+SNpTUzNhWqJJkKuJhGBK1LFn/
g4UpZp22RcbeVd6/8R1la6LooEbI4RcaBkYN6dB6FEe/UXPC6m2zLYm4dakpF3B4
7ntawXEmLq0DT83W390eFrlMm5cYbotK37vHxQIDAQABAoIBAEUu8EbA2MUj5kgC
Cp59yN/VONkjY5GJyXPo3uN3npKrgDG+jOUXh+LYxlQ9MogsTDnXTHWDQKx2maQ1
+yZhyJ//5l++brQ/uQfTI1XALPx568UtMp1JwKymmUkkYwPBzev9CB0XDDA/rwst
TVV4DfqKJ9Aq807N9v9zkh8B/vCB9Ecvfco7Q2+AgrsLoaUDR9IwbiQXLqrqLA/F
tXh29Okwt7A3cv2C7Yd0rWyZLJi5iyH/lzcu33xGfaIAeN0fHtefKEhPU/yS69VM
9HbdDC44h0/psNyBt0dlrUYx32oYzF8EV4brrqcZTVUJNfCEqA16nTMKSmCJQdR8
nPJCRYECgYEA3U/0MyNDVa/OphEcBGLnXhRBeBGTGIP768gkn0Fw3Fgk1v6eqfKb
JqBujdgJjxbebo32OZeRLw92RBsfNY5IyIwVUKgZbtNkysgf612IhNoeBF7Ljz3r
BbSq3gwOHuUszCjO8/SjQn9bRLxVifrRD04SdHudMN4V2g98yoBBEdUCgYEAzhRZ
BWdOlLG2gAa8waPeuHUkwGU4zKly3zLSnbNvJJJ/wSTbuGmPQhLcWXq27gepHzZf
fvVJbpHrLHksh3fwdPusmygXD/s0gxMQJqJJledk1GEUnPjuuAImKvmeJWyX5lGq
APMh+M5ZB6CBu1dqapAs7nkOLCsSDGatRwc65jECgYBGI2q/MjPK2jbhxpZchYPR
+xVsmhVGNb4HUZzZpAHCs2SphnR+Y9br/PhMl+Ufph3EZ9VbFz/57CqNFxNjA77p
YAv5Te0RhIlzAs2q6C+1+vJ8bBaTRQpQ+psUWDm5bOQvp9c+1Y9QKdChDhcF7amH
8jRDGlINBLVkMHhaLR9yKQKBgQDIBfH+D66zHucPzvpJTYAxM+qvH9CIvfP0doT9
cptvOQ7tbpQho7vcGyhrZXPHCAJ8fC8msHhM7S8B5L924dCwC1QW6UuxRFdM3iTw
Ctc3u/gfN/dlAS3bxqI7VjvNAWFSuXM0JsmTkN3TTFR/fTKaKkSiVzeNYWTMSqDn
bzoZEQKBgFZcAbn2h86jYJ2tcznBriLI8rZBkPL9MFP4QM2Ksz5/8fsJ84EPsatg
700S1yasmDwaOgBLtSKsy7Rju5E3nebaPgLw3x92LiI07F97p2Y5ftSbRgslaih4
fDBm/C82anx0q9s4psw1oNnYj20c+imPIWvM7A0W85kmqcmQvzwZ
-----END RSA PRIVATE KEY-----
`;

View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
rm localhost.key.pem localhost.cert.pem
openssl req -nodes -newkey rsa:2048 -keyout localhost.key2.pem -x509 -days 1024 -out localhost.cert.pem
openssl rsa -in localhost.key2.pem -out localhost.key.pem

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXjCCAkYCCQCgZ4DViKxZtTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJS
TzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTALBgNV
BAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYIWEBY
WC5YWFgwHhcNMTcxMTEzMTQzMTE2WhcNMjAwOTAyMTQzMTE2WjBxMQswCQYDVQQG
EwJSTzELMAkGA1UECAwCVE0xCzAJBgNVBAcMAlhYMQwwCgYDVQQKDANYWFgxDTAL
BgNVBAsMBFhYWFgxEjAQBgNVBAMMCWxvY2FsaG9zdDEXMBUGCSqGSIb3DQEJARYI
WEBYWC5YWFgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyJ+21siOW
oRkgVSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx
6ks6mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI
76MVjLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJ
P8mIAoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouig
RsjhFxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyb
lxhui0rfu8fFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABphKcUJbdEhUpWF4EZE
BBl/uzE4/WXtQZdgz3fGpvpzmXZBRtbkdPR3jxBW1c9asCfb366dXRb8im6/p6ae
sAxZINMKIQ8KCIEb+StVMc4MvxASMm1SSz/kFuTCA2Q8vD5sHJrFcoKk6HKNEOLu
dALKpO8ZDuxjv036sCnjfyDue9psSccsLuAhfr2NLL5Ky9lWrJFi3b35D5UHrlK/
9mb9izRgZSC9+sZgpSyvIK6idKoWB4s9RpCn8itucFHHUDOvv8DdwvsF/5iVyWz7
R5uR4/qA8k7lbHHLosu2ELyx3N6Go0AskjxzsONPOKNlGIDllTx21mkIvTkGlJgs
8/4=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAsifttbIjlqEZIFUqUDGlAMP0eeBhvfJPSBDEJxgaA+x5Z1+G
r4M9HzWgP8TXULilWakdKLIQsepLOpl+M/52B4eEjZkFZgB+5iZ0+Wqh1bODqZVV
OWZmTbAce/uyRBZOuBu5NNdayO+jFYy6zWCUk5YK7WDnDSZXumsAsJiNp7Kx0iSX
sjFThlCvB/UQ87Dz2SEEtLuMCT/JiAKJZ/5qYD+SNpTUzNhWqJJkKuJhGBK1LFn/
g4UpZp22RcbeVd6/8R1la6LooEbI4RcaBkYN6dB6FEe/UXPC6m2zLYm4dakpF3B4
7ntawXEmLq0DT83W390eFrlMm5cYbotK37vHxQIDAQABAoIBAEUu8EbA2MUj5kgC
Cp59yN/VONkjY5GJyXPo3uN3npKrgDG+jOUXh+LYxlQ9MogsTDnXTHWDQKx2maQ1
+yZhyJ//5l++brQ/uQfTI1XALPx568UtMp1JwKymmUkkYwPBzev9CB0XDDA/rwst
TVV4DfqKJ9Aq807N9v9zkh8B/vCB9Ecvfco7Q2+AgrsLoaUDR9IwbiQXLqrqLA/F
tXh29Okwt7A3cv2C7Yd0rWyZLJi5iyH/lzcu33xGfaIAeN0fHtefKEhPU/yS69VM
9HbdDC44h0/psNyBt0dlrUYx32oYzF8EV4brrqcZTVUJNfCEqA16nTMKSmCJQdR8
nPJCRYECgYEA3U/0MyNDVa/OphEcBGLnXhRBeBGTGIP768gkn0Fw3Fgk1v6eqfKb
JqBujdgJjxbebo32OZeRLw92RBsfNY5IyIwVUKgZbtNkysgf612IhNoeBF7Ljz3r
BbSq3gwOHuUszCjO8/SjQn9bRLxVifrRD04SdHudMN4V2g98yoBBEdUCgYEAzhRZ
BWdOlLG2gAa8waPeuHUkwGU4zKly3zLSnbNvJJJ/wSTbuGmPQhLcWXq27gepHzZf
fvVJbpHrLHksh3fwdPusmygXD/s0gxMQJqJJledk1GEUnPjuuAImKvmeJWyX5lGq
APMh+M5ZB6CBu1dqapAs7nkOLCsSDGatRwc65jECgYBGI2q/MjPK2jbhxpZchYPR
+xVsmhVGNb4HUZzZpAHCs2SphnR+Y9br/PhMl+Ufph3EZ9VbFz/57CqNFxNjA77p
YAv5Te0RhIlzAs2q6C+1+vJ8bBaTRQpQ+psUWDm5bOQvp9c+1Y9QKdChDhcF7amH
8jRDGlINBLVkMHhaLR9yKQKBgQDIBfH+D66zHucPzvpJTYAxM+qvH9CIvfP0doT9
cptvOQ7tbpQho7vcGyhrZXPHCAJ8fC8msHhM7S8B5L924dCwC1QW6UuxRFdM3iTw
Ctc3u/gfN/dlAS3bxqI7VjvNAWFSuXM0JsmTkN3TTFR/fTKaKkSiVzeNYWTMSqDn
bzoZEQKBgFZcAbn2h86jYJ2tcznBriLI8rZBkPL9MFP4QM2Ksz5/8fsJ84EPsatg
700S1yasmDwaOgBLtSKsy7Rju5E3nebaPgLw3x92LiI07F97p2Y5ftSbRgslaih4
fDBm/C82anx0q9s4psw1oNnYj20c+imPIWvM7A0W85kmqcmQvzwZ
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyJ+21siOWoRkg
VSpQMaUAw/R54GG98k9IEMQnGBoD7HlnX4avgz0fNaA/xNdQuKVZqR0oshCx6ks6
mX4z/nYHh4SNmQVmAH7mJnT5aqHVs4OplVU5ZmZNsBx7+7JEFk64G7k011rI76MV
jLrNYJSTlgrtYOcNJle6awCwmI2nsrHSJJeyMVOGUK8H9RDzsPPZIQS0u4wJP8mI
Aoln/mpgP5I2lNTM2FaokmQq4mEYErUsWf+DhSlmnbZFxt5V3r/xHWVrouigRsjh
FxoGRg3p0HoUR79Rc8LqbbMtibh1qSkXcHjue1rBcSYurQNPzdbf3R4WuUyblxhu
i0rfu8fFAgMBAAECggEARS7wRsDYxSPmSAIKnn3I39U42SNjkYnJc+je43eekquA
Mb6M5ReH4tjGVD0yiCxMOddMdYNArHaZpDX7JmHIn//mX75utD+5B9MjVcAs/Hnr
xS0ynUnArKaZSSRjA8HN6/0IHRcMMD+vCy1NVXgN+oon0CrzTs32/3OSHwH+8IH0
Ry99yjtDb4CCuwuhpQNH0jBuJBcuquosD8W1eHb06TC3sDdy/YLth3StbJksmLmL
If+XNy7ffEZ9ogB43R8e158oSE9T/JLr1Uz0dt0MLjiHT+mw3IG3R2WtRjHfahjM
XwRXhuuupxlNVQk18ISoDXqdMwpKYIlB1Hyc8kJFgQKBgQDdT/QzI0NVr86mERwE
YudeFEF4EZMYg/vryCSfQXDcWCTW/p6p8psmoG6N2AmPFt5ujfY5l5EvD3ZEGx81
jkjIjBVQqBlu02TKyB/rXYiE2h4EXsuPPesFtKreDA4e5SzMKM7z9KNCf1tEvFWJ
+tEPThJ0e50w3hXaD3zKgEER1QKBgQDOFFkFZ06UsbaABrzBo964dSTAZTjMqXLf
MtKds28kkn/BJNu4aY9CEtxZerbuB6kfNl9+9UlukesseSyHd/B0+6ybKBcP+zSD
ExAmokmV52TUYRSc+O64AiYq+Z4lbJfmUaoA8yH4zlkHoIG7V2pqkCzueQ4sKxIM
Zq1HBzrmMQKBgEYjar8yM8raNuHGllyFg9H7FWyaFUY1vgdRnNmkAcKzZKmGdH5j
1uv8+EyX5R+mHcRn1VsXP/nsKo0XE2MDvulgC/lN7RGEiXMCzaroL7X68nxsFpNF
ClD6mxRYObls5C+n1z7Vj1Ap0KEOFwXtqYfyNEMaUg0EtWQweFotH3IpAoGBAMgF
8f4PrrMe5w/O+klNgDEz6q8f0Ii98/R2hP1ym285Du1ulCGju9wbKGtlc8cIAnx8
LyaweEztLwHkv3bh0LALVBbpS7FEV0zeJPAK1ze7+B8392UBLdvGojtWO80BYVK5
czQmyZOQ3dNMVH99MpoqRKJXN41hZMxKoOdvOhkRAoGAVlwBufaHzqNgna1zOcGu
IsjytkGQ8v0wU/hAzYqzPn/x+wnzgQ+xq2DvTRLXJqyYPBo6AEu1IqzLtGO7kTed
5to+AvDfH3YuIjTsX3unZjl+1JtGCyVqKHh8MGb8LzZqfHSr2zimzDWg2diPbRz6
KY8ha8zsDRbzmSapyZC/PBk=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,8 @@
import * as fs from 'fs';
import * as path from 'path';
const PNGBuffer = fs.readFileSync(path.join(__dirname, '../fixtures/hello.png'));
const PNGUint8Array = new Uint8Array(PNGBuffer);
const PNGArrayBuffer = PNGUint8Array.buffer as ArrayBuffer;
export { PNGBuffer, PNGArrayBuffer, PNGUint8Array };

View File

@ -0,0 +1,228 @@
import * as express from 'express';
import { Application, NextFunction, Request, Response } from 'express';
import * as http from 'http';
import { Server as HttpServer } from 'http';
import * as https from 'https';
import { Server as HttpsServer } from 'https';
import * as bodyParser from 'body-parser';
import * as cookieParser from 'cookie-parser';
import { certificate, key } from './certificates/certificate';
import * as path from 'path';
export class XhrServer {
app: Application;
server: HttpServer | HttpsServer;
serverStarted: Promise<void>;
private setServerStarted: () => void;
constructor(public port = 8080, private useHttps = false) {
this.serverStarted = new Promise(resolve => this.setServerStarted = resolve);
this.createApp();
}
testUrl() {
return `https://localhost:${this.port}/test/html/browser_test.html`;
}
sslCertificate() {
return this.useHttps ? certificate : null;
}
sslKey() {
return this.useHttps ? key : null;
}
createApp() {
this.app = express();
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
this.app.use(cookieParser());
this.app.use((request: Request, response: Response, next: NextFunction) => {
response.header('Access-Control-Allow-Origin', '*');
response.header('Access-Control-Allow-Methods', 'DELETE,GET,POST,PUT');
response.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Cookie');
next();
});
this.app.get('/test/fixtures/hello.txt', (request: Request, response: Response) => {
const body = 'Hello, world!';
response.header('Content-Type', 'text/plain; charset=utf-8');
response.header('Content-Length', body.length.toString());
response.end(body);
});
this.app.get('/test/fixtures/hello.json', (request: Request, response: Response) => {
const body = '{"hello": "world", "answer": 42}\n';
response.header('Content-Type', 'application/json');
response.header('Content-Length', body.length.toString());
response.end(body);
});
this.app.get('/test/html/browser_test.html', (request: Request, response: Response) => {
const body = '<p>Test</p>';
response.header('Content-Type', 'text/html');
response.header('Content-Length', body.length.toString());
response.end(body);
});
this.app.all('/_/method', (request: Request, response: Response) => {
const body = request.method;
response.header('Content-Type', 'text/plain; charset=utf-8');
response.header('Content-Length', body.length.toString());
response.end(body);
});
// Echoes the request body. Used to test send(data).
this.app.post('/_/echo', (request: Request, response: Response) => {
if (request.headers['content-type']) {
response.header('Content-Type', request.headers['content-type']);
}
if (request.headers['content-length']) {
response.header('Content-Length', request.headers['content-length']);
}
request.on('data', chunk => response.write(chunk));
request.on('end', () => response.end());
});
// Lists the request headers. Used to test setRequestHeader().
this.app.all('/_/headers', (request: Request, response: Response) => {
const body = JSON.stringify(request.headers);
response.header('Content-Type', 'application/json');
response.header('Content-Length', body.length.toString());
response.end(body);
});
// Sets the response headers in the request. Used to test getResponse*().
this.app.post('/_/get-headers', (request: Request, response: Response) => {
let jsonString = '';
request.on('data', chunk => jsonString += chunk);
request.on('end', () => {
const headers = JSON.parse(jsonString);
for (let name in headers) {
if (headers.hasOwnProperty(name)) {
response.header(name, headers[name]);
}
}
response.header('Content-Length', '0');
response.end('');
});
});
// Sets every response detail. Used for error testing.
this.app.post('/_/response', (request: Request, response: Response) => {
let jsonString = '';
request.on('data', chunk => jsonString += chunk);
request.on('end', () => {
const json = JSON.parse(jsonString);
response.writeHead(json.code, json.status, json.headers);
if (json.body) { response.write(json.body); }
response.end();
});
});
// Sends data in small chunks. Used for event testing.
this.app.post('/_/drip', (request: Request, response: Response) => {
request.connection.setNoDelay();
let jsonString = '';
request.on('data', chunk => jsonString += chunk);
request.on('end', () => {
const json = JSON.parse(jsonString);
let sentDrips = 0;
const drip = new Array(json.size + 1).join('.');
response.header('Content-Type', 'text/plain');
if (json.length) { response.header('Content-Length', (json.drips * json.size).toString()); }
(function sendDrip() {
response.write(drip);
sentDrips++;
if (sentDrips >= json.drips) { return response.end(); }
setTimeout(sendDrip, json.ms);
})();
});
});
// Returns a HTTP redirect. Used to test the redirection handling code.
this.app.all('/_/redirect/:status/:next', (request: Request, response: Response) => {
response.statusCode = +request.params.status;
response.header('Location', `${request.protocol}://${request.get('host')}/_/${request.params.next}`);
const body = '<p>This is supposed to have a redirect link</p>';
response.header('Content-Type', 'text/html');
response.header('Content-Length', body.length.toString());
response.header('X-Redirect-Header', 'should not show up');
response.end(body);
});
// Sets a cookie
this.app.all('/_/set-cookie/:name/:value', (request: Request, response: Response) => {
response.cookie(request.params.name, request.params.value);
response.header('Content-Type', 'text/plain');
response.header('Content-Length', '0');
response.end();
});
// Redirects and sets a cookie.
this.app.all('/_/redirect-cookie/:name/:value', (request: Request, response: Response) => {
response.cookie(request.params.name, request.params.value);
response.redirect(301,
`${request.protocol}://${request.get('host')}/_/print-cookie/${request.params.name}`
);
});
// Read cookie + print its value.
this.app.get('/_/print-cookie/:name', (request: Request, response: Response) => {
const cookieValue = request.cookies[request.params.name];
response.header('Content-Type', 'text/plain');
response.header('Content-Length', cookieValue.length.toString());
response.end(cookieValue);
});
// Requested when the browser test suite completes.
this.app.get('/_/end', (request: Request, response: Response) => {
const failed = request.query.hasOwnProperty('failed') ? +request.query.failed : 1;
const total = request.query.hasOwnProperty('total') ? +request.query.total : 0;
const passed = total - failed;
const exitCode = failed ? 1 : 0;
console.log(`${passed} passed, ${failed} failed`);
response.header('Content-Type', 'image/png');
response.header('Content-Length', '0');
response.end('');
if (!process.env.hasOwnProperty('NO_EXIT')) {
this.server.close();
process.exit(exitCode);
}
});
this.app.use(express.static(path.join(__dirname, '../../')));
this.createServer();
}
createServer() {
this.server = this.useHttps
? https.createServer({
cert: this.sslCertificate(),
key: this.sslKey()
}, this.app)
: http.createServer(this.app);
this.server.on('error', (error) => {
if (error.code !== 'EADDRINUSE') { return; }
this.port += 2;
this.createServer();
});
this.server.on('listening', () => {
this.setServerStarted();
});
this.server.listen(this.port);
}
}
const HttpServer = new XhrServer(8900, false);
const HttpsServer = new XhrServer(8901, true);
export { HttpServer, HttpsServer };

View File

@ -0,0 +1,120 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest(),
customXhr: new XMLHttpRequest()
}));
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
t.context.customXhr = new XMLHttpRequest();
});
test('XMLHttpRequest.nodejsSet with a httpAgent option', t => {
const customAgent = {custom: 'httpAgent'};
const defaultAgent = XMLHttpRequest.prototype.nodejsHttpAgent;
const agent = {mocking: 'httpAgent'};
t.context.customXhr.nodejsHttpAgent = customAgent as any;
XMLHttpRequest.nodejsSet({httpAgent: agent} as any);
t.is(t.context.xhr.nodejsHttpAgent, agent as any, 'sets the default nodejsHttpAgent');
t.is(t.context.customXhr.nodejsHttpAgent, customAgent as any, 'does not interfere with custom nodejsHttpAgent settings');
XMLHttpRequest.nodejsSet({httpAgent: defaultAgent});
});
test('XMLHttpRequest.nodejsSet with a httpsAgent option', t => {
const customAgent = {custom: 'httpsAgent'};
const defaultAgent = XMLHttpRequest.prototype.nodejsHttpsAgent;
const agent = {mocking: 'httpsAgent'};
t.context.customXhr.nodejsHttpsAgent = customAgent as any;
XMLHttpRequest.nodejsSet({httpsAgent: agent} as any);
t.is(t.context.xhr.nodejsHttpsAgent, agent as any, 'sets the default nodejsHttpsAgent');
t.is(t.context.customXhr.nodejsHttpsAgent, customAgent as any, 'does not interfere with custom nodejsHttpsAgent settings');
XMLHttpRequest.nodejsSet({httpsAgent: defaultAgent});
});
test('XMLHttpRequest.nodejsSet with a baseUrl option', t => {
const customBaseUrl = 'http://custom.url/base';
const defaultBaseUrl = XMLHttpRequest.prototype.nodejsBaseUrl;
const baseUrl = 'http://localhost/base';
t.context.customXhr.nodejsBaseUrl = customBaseUrl;
XMLHttpRequest.nodejsSet({baseUrl});
t.is(t.context.xhr.nodejsBaseUrl, baseUrl, 'sets the default nodejsBaseUrl');
t.is(t.context.customXhr.nodejsBaseUrl, customBaseUrl, 'does not interfere with custom nodejsBaseUrl settings');
XMLHttpRequest.nodejsSet({baseUrl: defaultBaseUrl});
});
test('#nodejsSet with a httpAgent option', t => {
const customAgent = {custom: 'httpAgent'};
t.context.customXhr.nodejsSet({httpAgent: customAgent as any});
t.is(t.context.customXhr.nodejsHttpAgent, customAgent as any, 'sets nodejsHttpAgent on the XHR instance');
t.not(t.context.xhr.nodejsHttpAgent, customAgent as any, 'does not interfere with default nodejsHttpAgent settings');
});
test('#nodejsSet with a httpsAgent option', t => {
const customAgent = {custom: 'httpsAgent'};
t.context.customXhr.nodejsSet({httpsAgent: customAgent as any});
t.is(t.context.customXhr.nodejsHttpsAgent, customAgent as any, 'sets nodejsHttpsAgent on the XHR instance');
t.not(t.context.xhr.nodejsHttpsAgent, customAgent as any, 'does not interfere with default nodejsHttpsAgent settings');
});
test('base URL parsing with null baseUrl', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: null});
const parsedUrl = xhr._parseUrl('http://www.domain.com/path');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'http://www.domain.com/path');
});
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses an absolute URL', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
const parsedUrl = xhr._parseUrl('http://www.domain.com/path');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'http://www.domain.com/path');
});
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a path-relative URL', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
const parsedUrl = xhr._parseUrl('path/to.js');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'https://base.url/dir/path/to.js');
});
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a path-relative URL with ..', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
const parsedUrl = xhr._parseUrl('../path/to.js');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'https://base.url/path/to.js');
});
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a host-relative URL', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
const parsedUrl = xhr._parseUrl('/path/to.js');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'https://base.url/path/to.js');
});
test('base URL parsing with a (protocol, domain, filePath) baseUrl parses a protocol-relative URL', t => {
const xhr = t.context.xhr as any;
xhr.nodejsSet({baseUrl: 'https://base.url/dir/file.html'});
const parsedUrl = xhr._parseUrl('//domain.com/path/to.js');
t.truthy(parsedUrl);
t.true(parsedUrl.hasOwnProperty('href'));
t.is(parsedUrl.href, 'https://domain.com/path/to.js');
});

View File

@ -0,0 +1,120 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
});
test('XMLHttpRequest when redirected issues a GET for the next location', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('POST', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
xhr.onload = () => {
t.regex(xhr.responseText, /GET/i);
resolve();
};
xhr.onerror = () => {
t.fail();
resolve();
};
xhr.send('This should be dropped during the redirect');
});
});
test('XMLHttpRequest when redirected does not return the redirect headers', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
xhr.onload = () => {
t.is(xhr.getResponseHeader('Content-Type'), 'text/plain; charset=utf-8');
t.falsy(xhr.getResponseHeader('X-Redirect-Header'));
resolve();
};
xhr.onerror = () => {
t.fail();
resolve();
};
xhr.send();
});
});
test('XMLHttpRequest when redirected persists custom request headers across redirects', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/headers`);
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/);
const headers = JSON.parse(xhr.responseText);
t.is(headers.connection, 'keep-alive');
t.true(headers.hasOwnProperty('host'));
t.is(headers.host, `localhost:${HttpServer.port}`);
t.true(headers.hasOwnProperty('x-redirect-test'));
t.is(headers['x-redirect-test'], 'should be preserved');
resolve();
};
xhr.onerror = () => {
t.fail();
resolve();
};
xhr.send();
});
});
test('XMLHttpRequest when redirected drops content-related headers across redirects', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/headers`);
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/);
const headers = JSON.parse(xhr.responseText);
t.is(headers.connection, 'keep-alive');
t.true(headers.hasOwnProperty('host'));
t.is(headers.host, `localhost:${HttpServer.port}`);
t.true(headers.hasOwnProperty('x-redirect-test'));
t.is(headers['x-redirect-test'], 'should be preserved');
t.false(headers.hasOwnProperty('content-type'));
t.false(headers.hasOwnProperty('content-length'));
resolve();
};
xhr.onerror = () => {
t.fail();
resolve();
};
xhr.send();
});
});
test('XMLHttpRequest when redirected provides the final responseURL', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/redirect/302/method`);
xhr.setRequestHeader('X-Redirect-Test', 'should be preserved');
xhr.onload = () => {
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
resolve();
};
xhr.onerror = () => {
t.fail();
resolve();
};
xhr.send();
});
});

View File

@ -0,0 +1,134 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
import { PNGArrayBuffer, PNGBuffer } from './helpers/png';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest(),
jsonUrl: '',
jsonString: '',
imageUrl: ''
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
t.context.jsonUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.json`;
t.context.jsonString = '{"hello": "world", "answer": 42}\n';
t.context.imageUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.png`;
});
test('XMLHttpRequest #responseType text reads a JSON file into a String', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('load', () => {
t.is(xhr.response, t.context.jsonString);
t.is(xhr.responseText, t.context.jsonString);
resolve();
});
xhr.open('GET', t.context.jsonUrl);
xhr.responseType = 'text';
xhr.send();
});
});
test('XMLHttpRequest #responseType json reads a JSON file into a parsed JSON object', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('readystatechange', () => {
if (xhr.readyState !== XMLHttpRequest.DONE) { return; }
t.deepEqual(xhr.response, { hello: 'world', answer: 42 });
resolve();
});
xhr.open('GET', t.context.jsonUrl);
xhr.responseType = 'json';
xhr.send();
});
});
test('XMLHttpRequest #responseType json produces null when reading a non-JSON file', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('loadend', () => {
t.is(xhr.response, null);
resolve();
});
xhr.open('GET', `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`);
xhr.responseType = 'json';
xhr.send();
});
});
test('XMLHttpRequest #responseType arraybuffer reads a JSON file into an ArrayBuffer', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('loadend', () => {
t.true(xhr.response instanceof ArrayBuffer);
if (!(xhr.response instanceof ArrayBuffer)) { return; }
const view = new Uint8Array(xhr.response);
const response = Array.from(view).map(viewElement => String.fromCharCode(viewElement)).join('');
t.is(response, t.context.jsonString);
resolve();
});
xhr.open('GET', t.context.jsonUrl);
xhr.responseType = 'arraybuffer';
xhr.send();
});
});
test('XMLHttpRequest #responseType arraybuffer reads a binary file into an ArrayBuffer', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('loadend', () => {
t.true(xhr.response instanceof ArrayBuffer);
if (!(xhr.response instanceof ArrayBuffer)) { return; }
t.deepEqual(xhr.response, PNGArrayBuffer);
resolve();
});
xhr.open('GET', t.context.imageUrl);
xhr.responseType = 'arraybuffer';
xhr.send();
});
});
test('XMLHttpRequest #responseType buffer reads a JSON file into a node.js Buffer', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('loadend', () => {
t.true(xhr.response instanceof Buffer);
if (!(xhr.response instanceof Buffer)) { return; }
const response = Array.from(xhr.response).map(viewElement => String.fromCharCode(viewElement)).join('');
t.is(response, t.context.jsonString);
resolve();
});
xhr.open('GET', t.context.jsonUrl);
xhr.responseType = 'buffer';
xhr.send();
});
});
test('XMLHttpRequest #responseType buffer reads a binary file into a node.js Buffer', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.addEventListener('loadend', () => {
t.true(xhr.response instanceof Buffer);
if (!(xhr.response instanceof Buffer)) { return; }
t.deepEqual(xhr.response, PNGBuffer);
resolve();
});
xhr.open('GET', t.context.imageUrl);
xhr.responseType = 'buffer';
xhr.send();
});
});

View File

@ -0,0 +1,46 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
});
test('XMLHttpRequest #responseURL provides the URL of the response', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/method`);
xhr.onload = () => {
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
resolve();
};
xhr.send();
});
});
test('XMLHttpRequest #responseURL ignores the hash fragment', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', `http://localhost:${HttpServer.port}/_/method#foo`);
xhr.onload = () => {
t.is(xhr.responseUrl, `http://localhost:${HttpServer.port}/_/method`);
resolve();
};
xhr.send();
});
});

View File

@ -0,0 +1,137 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
import { PNGArrayBuffer, PNGUint8Array } from './helpers/png';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
t.context.xhr.open('POST', `http://localhost:${HttpServer.port}/_/echo`);
});
test('XMLHttpRequest #send works with ASCII DOMStrings', async t => {
const xhr = t.context.xhr;
t.plan(2);
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.getResponseHeader('content-type'), /^text\/plain(;\s?charset=UTF-8)?$/);
t.is(xhr.responseText, 'Hello world!');
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send('Hello world!');
});
});
test('XMLHttpRequest #send works with UTF-8 DOMStrings', async t => {
const xhr = t.context.xhr;
t.plan(2);
await new Promise(resolve => {
xhr.onload = () => {
t.regex(xhr.getResponseHeader('content-type'), /^text\/plain(;\s?charset=UTF-8)?$/);
t.is(xhr.responseText, '世界你好!');
resolve();
};
xhr.send('世界你好!');
});
});
test('XMLHttpRequest #send works with ArrayBufferViews', async t => {
const xhr = t.context.xhr;
t.plan(2);
await new Promise(resolve => {
xhr.responseType = 'arraybuffer';
xhr.onload = () => {
t.is(xhr.getResponseHeader('content-type'), null);
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
t.deepEqual(new Uint8Array(xhr.response), PNGUint8Array);
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send(PNGUint8Array);
});
});
test('XMLHttpRequest #send works with ArrayBufferViews with set index and length', async t => {
const xhr = t.context.xhr;
t.plan(2);
const arrayBufferView10 = new Uint8Array(PNGArrayBuffer, 10, 42);
await new Promise(resolve => {
xhr.responseType = 'arraybuffer';
xhr.onload = () => {
t.is(xhr.getResponseHeader('content-type'), null);
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
t.deepEqual(new Uint8Array(xhr.response), arrayBufferView10);
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send(arrayBufferView10);
});
});
test('XMLHttpRequest #send works with ArrayBuffers', async t => {
const xhr = t.context.xhr;
t.plan(2);
await new Promise(resolve => {
xhr.responseType = 'arraybuffer';
xhr.onload = () => {
t.is(xhr.getResponseHeader('content-type'), null);
if (!(xhr.response instanceof ArrayBuffer)) { t.fail(); return resolve(); }
t.deepEqual(xhr.response, PNGArrayBuffer);
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send(PNGArrayBuffer);
});
});
test('XMLHttpRequest #send works with node.js Buffers', async t => {
const xhr = t.context.xhr;
const buffer = Buffer.alloc(PNGUint8Array.length);
for (let i = 0; i < PNGUint8Array.length; i++) { buffer.writeUInt8(PNGUint8Array[i], i); }
t.plan(2);
await new Promise(resolve => {
xhr.responseType = 'buffer';
xhr.onload = () => {
t.is(xhr.getResponseHeader('content-type'), null);
if (!(xhr.response instanceof Buffer)) { t.fail(); return resolve(); }
t.deepEqual(new Uint8Array(xhr.response), PNGUint8Array);
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send(PNGArrayBuffer);
});
});
test('XMLHttpRequest #send sets POST headers correctly when given null data', async t => {
const xhr = t.context.xhr;
xhr.open('POST', `http://localhost:${HttpServer.port}/_/headers`);
await new Promise(resolve => {
xhr.responseType = 'text';
xhr.onload = () => {
t.regex(xhr.responseText, /^\{.*\}$/);
const headers = JSON.parse(xhr.responseText);
t.true(headers.hasOwnProperty('content-length'));
t.is(headers['content-length'], '0');
t.false(headers.hasOwnProperty('content-type'));
resolve();
};
xhr.onerror = () => { t.fail(); return resolve(); };
xhr.send();
});
});

View File

@ -0,0 +1,84 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer } from './helpers/server';
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest(),
okUrl: '',
errorUrl: '',
errorJson: ''
}));
test.before(async () => {
await HttpServer.serverStarted;
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
t.context.okUrl = `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`;
t.context.errorUrl = `http://localhost:${HttpServer.port}/_/response`;
t.context.errorJson = JSON.stringify({
code: 401,
status: 'Unauthorized',
body: JSON.stringify({error: 'Credential error'}),
headers: {
'Content-Type': 'application/json',
'Content-Length': '28'
}
});
});
test('XMLHttpRequest #status is 200 for a normal request', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('GET', t.context.okUrl);
let done = false;
xhr.addEventListener('readystatechange', () => {
if (done) { return; }
if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) {
t.is(xhr.status, 0);
t.is(xhr.statusText, '');
} else {
t.is(xhr.status, 200);
t.truthy(xhr.statusText);
t.not(xhr.statusText, '');
if (xhr.readyState === XMLHttpRequest.DONE) {
done = true;
resolve();
}
}
});
xhr.send();
});
});
test('XMLHttpRequest #status returns the server-reported status', async t => {
const xhr = t.context.xhr;
await new Promise(resolve => {
xhr.open('POST', t.context.errorUrl);
let done = false;
xhr.addEventListener('readystatechange', () => {
if (done) { return; }
if (xhr.readyState < XMLHttpRequest.HEADERS_RECEIVED) {
t.is(xhr.status, 0);
t.is(xhr.statusText, '');
} else {
t.is(xhr.status, 401);
t.truthy(xhr.statusText);
t.not(xhr.statusText, '');
if (xhr.readyState === XMLHttpRequest.DONE) {
done = true;
resolve();
}
}
});
xhr.send(t.context.errorJson);
});
});

View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"lib": [ "es5", "es6", "es2016", "es2017", "dom" ]
},
"include": [
"*.spec.ts",
"./png.d.ts"
]
}

View File

@ -0,0 +1,135 @@
import * as ava from 'ava';
import { XMLHttpRequest } from '../xml-http-request';
import { HttpServer, HttpsServer } from './helpers/server';
import * as https from 'https';
const agent = new https.Agent({
rejectUnauthorized: true,
ca: HttpsServer.sslCertificate()
});
XMLHttpRequest.nodejsSet({
httpsAgent: agent
});
function contextualize<T>(getContext: () => T): ava.RegisterContextual<T> {
ava.test.beforeEach(t => {
Object.assign(t.context, getContext());
});
return ava.test;
}
const test = contextualize(() => ({
xhr: new XMLHttpRequest()
}));
test.before(async t => {
await HttpServer.serverStarted;
await HttpsServer.serverStarted;
XMLHttpRequest.nodejsSet({
baseUrl: HttpServer.testUrl().replace('https://', 'http://')
});
});
test.beforeEach(t => {
t.context.xhr = new XMLHttpRequest();
});
test('constructor', t => {
const xhr = t.context.xhr;
t.is(xhr.readyState, XMLHttpRequest.UNSENT, 'sets readyState to UNSENT');
t.is(xhr.timeout, 0, 'sets timeout to 0');
t.is(xhr.responseType, '', 'sets responseType to ""');
t.is(xhr.status, 0, 'sets status to 0');
t.is(xhr.statusText, '', 'sets statusText to ""');
});
test('#open throws SecurityError on CONNECT', t => {
t.throws(() => t.context.xhr.open('CONNECT', `http://localhost:${HttpServer.port}/test`), XMLHttpRequest.SecurityError);
});
test('#open with a GET for a local https request', t => {
const xhr = t.context.xhr;
xhr.open('GET', `https://localhost:${HttpsServer.port}/test/fixtures/hello.txt`);
t.is(xhr.readyState, XMLHttpRequest.OPENED, 'sets readyState to OPENED');
t.is(xhr.status, 0, 'keeps status 0');
t.is(xhr.statusText, '', 'keeps statusText ""');
});
test('#send on a local http GET kicks off the request', async t => {
const xhr = t.context.xhr;
xhr.open('GET', `http://localhost:${HttpServer.port}/test/fixtures/hello.txt`);
t.plan(2);
await new Promise((resolve, reject) => {
xhr.onload = (event) => {
t.is(xhr.status, 200, 'the status is 200');
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
resolve();
};
xhr.onerror = (event) => {
reject(event);
};
xhr.send();
});
});
test('#send on a local https GET kicks off the request', async t => {
const xhr = t.context.xhr;
xhr.open('GET', `https://localhost:${HttpsServer.port}/test/fixtures/hello.txt`);
t.plan(2);
await new Promise((resolve, reject) => {
xhr.onload = (event) => {
t.is(xhr.status, 200, 'the status is 200');
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
resolve();
};
xhr.onerror = (event) => {
reject(event);
};
xhr.send();
});
});
test('on a local relative GET it kicks off the request', async t => {
const xhr = t.context.xhr;
xhr.open('GET', '../fixtures/hello.txt');
t.plan(2);
await new Promise((resolve, reject) => {
xhr.onload = (event) => {
t.is(xhr.status, 200, 'the status is 200');
t.is(xhr.responseText, 'Hello, world!', 'the text is correct');
resolve();
};
xhr.onerror = (event) => {
reject(event);
};
xhr.send();
});
});
test('on a local gopher GET #open + #send throws a NetworkError', async t => {
const xhr = t.context.xhr;
t.throws(() => {
xhr.open('GET', `gopher:localhost:${HttpServer.port}`);
xhr.send();
}, XMLHttpRequest.NetworkError);
});
test('readyState constants', t => {
t.is(XMLHttpRequest.UNSENT < XMLHttpRequest.OPENED, true, 'UNSENT < OPENED');
t.is(XMLHttpRequest.OPENED < XMLHttpRequest.HEADERS_RECEIVED, true, 'OPENED < HEADERS_RECEIVED');
t.is(XMLHttpRequest.HEADERS_RECEIVED < XMLHttpRequest.LOADING, true, 'HEADERS_RECEIVED < LOADING');
t.is(XMLHttpRequest.LOADING < XMLHttpRequest.DONE, true, 'LOADING < DONE');
});
test('XMLHttpRequest constants match the instance constants', t => {
const xhr = t.context.xhr;
t.is(XMLHttpRequest.UNSENT, xhr.UNSENT, 'UNSENT');
t.is(XMLHttpRequest.OPENED, xhr.OPENED, 'OPENED');
t.is(XMLHttpRequest.HEADERS_RECEIVED, xhr.HEADERS_RECEIVED, 'HEADERS_RECEIVED');
t.is(XMLHttpRequest.LOADING, xhr.LOADING, 'LOADING');
t.is(XMLHttpRequest.DONE, xhr.DONE, 'DONE');
});

View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "dist",
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declaration": true,
"declarationDir": "dist",
"lib": [ "es5", "es6", "es2016", "es2017", "dom" ]
},
"files": [
"index.ts"
]
}

View File

@ -0,0 +1,115 @@
{
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs"
],
"import-spacing": true,
"indent": [
true,
"tabs"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
]
}
}

View File

@ -0,0 +1,27 @@
module.exports = function (wallaby) {
return {
files: ['**/*.ts', '*.ts', '!test/**/*'],
tests: ['test/**/*.ts'],
env: {type: 'node'},
testFramework: 'ava',
recycle: true,
name: 'XMLHttpRequest 2+',
slowTestThreshold: 300,
reportUnhandledPromises: false,
workers: {
// initial: 1,
// regular: 1,
recycle: true
},
compilers: {
'**/*.ts': wallaby.compilers.typeScript({
target: 'es2015',
module: 'commonjs',
sourceMap: true,
experimentalDecorators: true,
emitDecoratorMetadata: true,
lib: ['es5', 'es6', 'es2016', 'es2017', 'dom']
})
}
}
};

View File

@ -0,0 +1,49 @@
import { ProgressEvent } from './progress-event';
export type ProgressEventListener = (event: ProgressEvent) => void;
export type ProgressEventListenerObject = {handleEvent(event: ProgressEvent): void};
export type ProgressEventListenerOrEventListenerObject = ProgressEventListener | ProgressEventListenerObject;
export class XMLHttpRequestEventTarget {
onloadstart: ProgressEventListener | null;
onprogress: ProgressEventListener | null;
onabort: ProgressEventListener | null;
onerror: ProgressEventListener | null;
onload: ProgressEventListener | null;
ontimeout: ProgressEventListener | null;
onloadend: ProgressEventListener | null;
private listeners: {[eventType: string]: ProgressEventListener[]} = {};
addEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject) {
eventType = eventType.toLowerCase();
this.listeners[eventType] = this.listeners[eventType] || [];
this.listeners[eventType].push((listener as ProgressEventListenerObject).handleEvent || (listener as ProgressEventListener));
}
removeEventListener(eventType: string, listener?: ProgressEventListenerOrEventListenerObject) {
eventType = eventType.toLowerCase();
if (!this.listeners[eventType]) { return; }
const index = this.listeners[eventType].indexOf((listener as ProgressEventListenerObject).handleEvent || (listener as ProgressEventListener));
if (index < 0) { return; }
this.listeners[eventType].splice(index, 1);
}
dispatchEvent(event: ProgressEvent) {
const eventType = event.type.toLowerCase();
event.target = this; // TODO: set event.currentTarget?
if (this.listeners[eventType]) {
for (let listener of this.listeners[eventType]) {
listener.call(this, event);
}
}
const listener = this[`on${eventType}`];
if (listener) {
listener.call(this, event);
}
return true;
}
}

View File

@ -0,0 +1,57 @@
import { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
import { ClientRequest } from 'http';
export class XMLHttpRequestUpload extends XMLHttpRequestEventTarget {
private _contentType: string | null = null;
private _body = null;
constructor() {
super();
this._reset();
}
_reset() {
this._contentType = null;
this._body = null;
}
_setData(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
if (data == null) { return; }
if (typeof data === 'string') {
if (data.length !== 0) {
this._contentType = 'text/plain;charset=UTF-8';
}
this._body = Buffer.from(data, 'utf-8');
} else if (Buffer.isBuffer(data)) {
this._body = data;
} else if (data instanceof ArrayBuffer) {
const body = Buffer.alloc(data.byteLength);
const view = new Uint8Array(data);
for (let i = 0; i < data.byteLength; i++) { body[i] = view[i]; }
this._body = body;
} else if (data.buffer && data.buffer instanceof ArrayBuffer) {
const body = Buffer.alloc(data.byteLength);
const offset = data.byteOffset;
const view = new Uint8Array(data.buffer);
for (let i = 0; i < data.byteLength; i++) { body[i] = view[i + offset]; }
this._body = body;
} else {
throw new Error(`Unsupported send() data ${data}`);
}
}
_finalizeHeaders(headers: object, loweredHeaders: object) {
if (this._contentType && !loweredHeaders['content-type']) {
headers['Content-Type'] = this._contentType;
}
if (this._body) {
headers['Content-Length'] = this._body.length.toString();
}
}
_startUpload(request: ClientRequest) {
if (this._body) { request.write(this._body); }
request.end();
}
}

View File

@ -0,0 +1,471 @@
import * as http from 'http';
import * as https from 'https';
import * as os from 'os';
import * as url from 'url';
import { ProgressEvent } from './progress-event';
import { InvalidStateError, NetworkError, SecurityError, SyntaxError } from './errors';
import { ProgressEventListener, XMLHttpRequestEventTarget } from './xml-http-request-event-target';
import { XMLHttpRequestUpload } from './xml-http-request-upload';
import { Url } from 'url';
import { Agent as HttpAgent, ClientRequest, IncomingMessage, RequestOptions as RequestOptionsHttp } from 'http';
import { Agent as HttpsAgent } from 'https';
import * as Cookie from 'cookiejar';
export interface XMLHttpRequestOptions {
anon?: boolean;
}
export interface XHRUrl extends Url {
method?: string;
}
export class XMLHttpRequest extends XMLHttpRequestEventTarget {
static ProgressEvent = ProgressEvent;
static InvalidStateError = InvalidStateError;
static NetworkError = NetworkError;
static SecurityError = SecurityError;
static SyntaxError = SyntaxError;
static XMLHttpRequestUpload = XMLHttpRequestUpload;
static UNSENT = 0;
static OPENED = 1;
static HEADERS_RECEIVED = 2;
static LOADING = 3;
static DONE = 4;
static cookieJar = Cookie.CookieJar();
UNSENT = XMLHttpRequest.UNSENT;
OPENED = XMLHttpRequest.OPENED;
HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED;
LOADING = XMLHttpRequest.LOADING;
DONE = XMLHttpRequest.DONE;
onreadystatechange: ProgressEventListener | null = null;
readyState: number = XMLHttpRequest.UNSENT;
response: string | ArrayBuffer | Buffer | object | null = null;
responseText = '';
responseType = '';
status = 0; // TODO: UNSENT?
statusText = '';
timeout = 0;
upload = new XMLHttpRequestUpload();
responseUrl = '';
withCredentials = false;
nodejsHttpAgent: HttpsAgent;
nodejsHttpsAgent: HttpsAgent;
nodejsBaseUrl: string | null;
private _anonymous: boolean;
private _method: string | null = null;
private _url: XHRUrl | null = null;
private _sync = false;
private _headers: {[header: string]: string} = {};
private _loweredHeaders: {[lowercaseHeader: string]: string} = {};
private _mimeOverride: string | null = null; // TODO: is type right?
private _request: ClientRequest | null = null;
private _response: IncomingMessage | null = null;
private _responseParts: Buffer[] | null = null;
private _responseHeaders: {[lowercaseHeader: string]: string} | null = null;
private _aborting = null; // TODO: type?
private _error = null; // TODO: type?
private _loadedBytes = 0;
private _totalBytes = 0;
private _lengthComputable = false;
private _restrictedMethods = {CONNECT: true, TRACE: true, TRACK: true};
private _restrictedHeaders = {
'accept-charset': true,
'accept-encoding': true,
'access-control-request-headers': true,
'access-control-request-method': true,
connection: true,
'content-length': true,
cookie: true,
cookie2: true,
date: true,
dnt: true,
expect: true,
host: true,
'keep-alive': true,
origin: true,
referer: true,
te: true,
trailer: true,
'transfer-encoding': true,
upgrade: true,
'user-agent': true,
via: true
};
private _privateHeaders = {'set-cookie': true, 'set-cookie2': true};
//Redacted private information (${os.type()} ${os.arch()}) node.js/${process.versions.node} v8/${process.versions.v8} from the original version @ github
//Pretend to be tor-browser https://blog.torproject.org/browser-fingerprinting-introduction-and-challenges-ahead/
private _userAgent = `Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0`;
constructor(options: XMLHttpRequestOptions = {}) {
super();
this._anonymous = options.anon || false;
}
open(method: string, url: string, async = true, user?: string, password?: string) {
method = method.toUpperCase();
if (this._restrictedMethods[method]) { throw new XMLHttpRequest.SecurityError(`HTTP method ${method} is not allowed in XHR`)};
const xhrUrl = this._parseUrl(url, user, password);
if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED || this.readyState === XMLHttpRequest.LOADING) {
// TODO(pwnall): terminate abort(), terminate send()
}
this._method = method;
this._url = xhrUrl;
this._sync = !async;
this._headers = {};
this._loweredHeaders = {};
this._mimeOverride = null;
this._setReadyState(XMLHttpRequest.OPENED);
this._request = null;
this._response = null;
this.status = 0;
this.statusText = '';
this._responseParts = [];
this._responseHeaders = null;
this._loadedBytes = 0;
this._totalBytes = 0;
this._lengthComputable = false;
}
setRequestHeader(name: string, value: any) {
if (this.readyState !== XMLHttpRequest.OPENED) { throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED'); }
const loweredName = name.toLowerCase();
if (this._restrictedHeaders[loweredName] || /^sec-/.test(loweredName) || /^proxy-/.test(loweredName)) {
console.warn(`Refused to set unsafe header "${name}"`);
return;
}
value = value.toString();
if (this._loweredHeaders[loweredName] != null) {
name = this._loweredHeaders[loweredName];
this._headers[name] = `${this._headers[name]}, ${value}`;
} else {
this._loweredHeaders[loweredName] = name;
this._headers[name] = value;
}
}
send(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
if (this.readyState !== XMLHttpRequest.OPENED) { throw new XMLHttpRequest.InvalidStateError('XHR readyState must be OPENED'); }
if (this._request) { throw new XMLHttpRequest.InvalidStateError('send() already called'); }
switch (this._url.protocol) {
case 'file:':
return this._sendFile(data);
case 'http:':
case 'https:':
return this._sendHttp(data);
default:
throw new XMLHttpRequest.NetworkError(`Unsupported protocol ${this._url.protocol}`);
}
}
abort() {
if (this._request == null) { return; }
this._request.abort();
this._setError();
this._dispatchProgress('abort');
this._dispatchProgress('loadend');
}
getResponseHeader(name: string) {
if (this._responseHeaders == null || name == null) { return null; }
const loweredName = name.toLowerCase();
return this._responseHeaders.hasOwnProperty(loweredName)
? this._responseHeaders[name.toLowerCase()]
: null;
}
getAllResponseHeaders() {
if (this._responseHeaders == null) { return ''; }
return Object.keys(this._responseHeaders).map(key => `${key}: ${this._responseHeaders[key]}`).join('\r\n');
}
overrideMimeType(mimeType: string) {
if (this.readyState === XMLHttpRequest.LOADING || this.readyState === XMLHttpRequest.DONE) { throw new XMLHttpRequest.InvalidStateError('overrideMimeType() not allowed in LOADING or DONE'); }
this._mimeOverride = mimeType.toLowerCase();
}
nodejsSet(options: {httpAgent?: HttpAgent, httpsAgent?: HttpsAgent, baseUrl?: string }) {
this.nodejsHttpAgent = options.httpAgent || this.nodejsHttpAgent;
this.nodejsHttpsAgent = options.httpsAgent || this.nodejsHttpsAgent;
if (options.hasOwnProperty('baseUrl')) {
if (options.baseUrl != null) {
const parsedUrl = url.parse(options.baseUrl, false, true);
if (!parsedUrl.protocol) {
throw new XMLHttpRequest.SyntaxError("baseUrl must be an absolute URL")
}
}
this.nodejsBaseUrl = options.baseUrl;
}
}
static nodejsSet(options: {httpAgent?: HttpAgent, httpsAgent?: HttpsAgent, baseUrl?: string }) {
XMLHttpRequest.prototype.nodejsSet(options);
}
private _setReadyState(readyState: number) {
this.readyState = readyState;
this.dispatchEvent(new ProgressEvent('readystatechange'));
}
private _sendFile(data: any) {
// TODO
throw new Error('Protocol file: not implemented');
}
private _sendHttp(data?: string | Buffer | ArrayBuffer | ArrayBufferView) {
if (this._sync) { throw new Error('Synchronous XHR processing not implemented'); }
if (data && (this._method === 'GET' || this._method === 'HEAD')) {
console.warn(`Discarding entity body for ${this._method} requests`);
data = null;
} else {
data = data || '';
}
this.upload._setData(data);
this._finalizeHeaders();
this._sendHxxpRequest();
}
private _sendHxxpRequest() {
if (this.withCredentials) {
const cookie = XMLHttpRequest.cookieJar
.getCookies(
Cookie.CookieAccessInfo(this._url.hostname, this._url.pathname, this._url.protocol === 'https:')
).toValueString();
this._headers.cookie = this._headers.cookie2 = cookie;
}
const [hxxp, agent] = this._url.protocol === 'http:' ? [http, this.nodejsHttpAgent] : [https, this.nodejsHttpsAgent];
const requestMethod: (options: RequestOptionsHttp) => ClientRequest = hxxp.request.bind(hxxp);
const request = requestMethod({
hostname: this._url.hostname,
port: +this._url.port,
path: this._url.path,
auth: this._url.auth,
method: this._method,
headers: this._headers,
agent
});
this._request = request;
if (this.timeout) { request.setTimeout(this.timeout, () => this._onHttpTimeout(request)); }
request.on('response', response => this._onHttpResponse(request, response));
request.on('error', error => this._onHttpRequestError(request, error));
this.upload._startUpload(request);
if (this._request === request) { this._dispatchProgress('loadstart'); }
}
private _finalizeHeaders() {
this._headers = {
...this._headers,
Connection: 'keep-alive',
Host: this._url.host,
'User-Agent': this._userAgent,
...this._anonymous ? {Referer: 'about:blank'} : {}
};
this.upload._finalizeHeaders(this._headers, this._loweredHeaders);
}
private _onHttpResponse(request: ClientRequest, response: IncomingMessage) {
if (this._request !== request) { return; }
if (this.withCredentials && (response.headers['set-cookie'] || response.headers['set-cookie2'])) {
XMLHttpRequest.cookieJar
.setCookies(response.headers['set-cookie'] || response.headers['set-cookie2']);
}
if ([301, 302, 303, 307, 308].indexOf(response.statusCode) >= 0) {
this._url = this._parseUrl(response.headers.location);
this._method = 'GET';
if (this._loweredHeaders['content-type']) {
delete this._headers[this._loweredHeaders['content-type']];
delete this._loweredHeaders['content-type'];
}
if (this._headers['Content-Type'] != null) {
delete this._headers['Content-Type'];
}
delete this._headers['Content-Length'];
this.upload._reset();
this._finalizeHeaders();
this._sendHxxpRequest();
return;
}
this._response = response;
this._response.on('data', data => this._onHttpResponseData(response, data));
this._response.on('end', () => this._onHttpResponseEnd(response));
this._response.on('close', () => this._onHttpResponseClose(response));
this.responseUrl = this._url.href.split('#')[0];
this.status = response.statusCode;
this.statusText = http.STATUS_CODES[this.status];
this._parseResponseHeaders(response);
const lengthString = this._responseHeaders['content-length'] || '';
this._totalBytes = +lengthString;
this._lengthComputable = !!lengthString;
this._setReadyState(XMLHttpRequest.HEADERS_RECEIVED);
}
private _onHttpResponseData(response: IncomingMessage, data: string | Buffer) {
if (this._response !== response) { return; }
this._responseParts.push(Buffer.from(data as any));
this._loadedBytes += data.length;
if (this.readyState !== XMLHttpRequest.LOADING) {
this._setReadyState(XMLHttpRequest.LOADING);
}
this._dispatchProgress('progress');
}
private _onHttpResponseEnd(response: IncomingMessage) {
if (this._response !== response) { return; }
this._parseResponse();
this._request = null;
this._response = null;
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress('load');
this._dispatchProgress('loadend');
}
private _onHttpResponseClose(response: IncomingMessage) {
if (this._response !== response) { return; }
const request = this._request;
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress('error');
this._dispatchProgress('loadend');
}
private _onHttpTimeout(request: ClientRequest) {
if (this._request !== request) { return; }
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress('timeout');
this._dispatchProgress('loadend');
}
private _onHttpRequestError(request: ClientRequest, error: Error) {
if (this._request !== request) { return; }
this._setError();
request.abort();
this._setReadyState(XMLHttpRequest.DONE);
this._dispatchProgress('error');
this._dispatchProgress('loadend');
}
private _dispatchProgress(eventType: string) {
const event = new XMLHttpRequest.ProgressEvent(eventType);
event.lengthComputable = this._lengthComputable;
event.loaded = this._loadedBytes;
event.total = this._totalBytes;
this.dispatchEvent(event);
}
private _setError() {
this._request = null;
this._response = null;
this._responseHeaders = null;
this._responseParts = null;
}
private _parseUrl(urlString: string, user?: string, password?: string) {
const absoluteUrl = this.nodejsBaseUrl == null ? urlString : url.resolve(this.nodejsBaseUrl, urlString);
const xhrUrl: XHRUrl = url.parse(absoluteUrl, false, true);
xhrUrl.hash = null;
const [xhrUser, xhrPassword] = (xhrUrl.auth || '').split(':');
if (xhrUser || xhrPassword || user || password) {
xhrUrl.auth = `${user || xhrUser || ''}:${password || xhrPassword || ''}`;
}
return xhrUrl;
}
private _parseResponseHeaders(response: IncomingMessage) {
this._responseHeaders = {};
for (let name in response.headers) {
const loweredName = name.toLowerCase();
if (this._privateHeaders[loweredName]) { continue; }
this._responseHeaders[loweredName] = response.headers[name];
}
if (this._mimeOverride != null) {
this._responseHeaders['content-type'] = this._mimeOverride;
}
}
private _parseResponse() {
const buffer = Buffer.concat(this._responseParts);
this._responseParts = null;
switch (this.responseType) {
case 'json':
this.responseText = null;
try {
this.response = JSON.parse(buffer.toString('utf-8'));
} catch {
this.response = null;
}
return;
case 'buffer':
this.responseText = null;
this.response = buffer;
return;
case 'arraybuffer':
this.responseText = null;
const arrayBuffer = new ArrayBuffer(buffer.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < buffer.length; i++) { view[i] = buffer[i]; }
this.response = arrayBuffer;
return;
case 'text':
default:
try {
this.responseText = buffer.toString(this._parseResponseEncoding());
} catch {
this.responseText = buffer.toString('binary');
}
this.response = this.responseText;
}
}
private _parseResponseEncoding() {
return /;\s*charset=(.*)$/.exec(this._responseHeaders['content-type'] || '')[1] || 'utf-8';
}
}
XMLHttpRequest.prototype.nodejsHttpAgent = http.globalAgent;
XMLHttpRequest.prototype.nodejsHttpsAgent = https.globalAgent;
XMLHttpRequest.prototype.nodejsBaseUrl = null;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
{
"name": "web3-providers-http",
"version": "1.6.1",
"description": "Module to handle web3 RPC connections over HTTP.",
"repository": "https://github.com/ethereum/web3.js/tree/1.x/packages/web3-providers-http",
"license": "LGPL-3.0",
"engines": {
"node": ">=8.0.0"
},
"scripts": {
"compile": "tsc -b tsconfig.json",
"dtslint": "dtslint --localTs ../../node_modules/typescript/lib types"
},
"types": "types/index.d.ts",
"main": "lib/index.js",
"dependencies": {
"web3-core-helpers": "1.6.1",
"xhr2-cookies": "file:./local_modules/xhr2-cookies"
},
"devDependencies": {
"dtslint": "^3.4.1",
"typescript": "^3.9.5"
}
}

View File

@ -0,0 +1,142 @@
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file httpprovider.js
* @authors:
* Marek Kotewicz <marek@parity.io>
* Marian Oancea
* Fabian Vogelsteller <fabian@ethereum.org>
* @date 2015
*/
var errors = require('web3-core-helpers').errors;
var XHR2 = require('xhr2-cookies').XMLHttpRequest; // jshint ignore: line
var http = require('http');
var https = require('https');
/**
* HttpProvider should be used to send rpc calls over http
*/
var HttpProvider = function HttpProvider(host, options) {
options = options || {};
this.withCredentials = options.withCredentials || false;
this.timeout = options.timeout || 0;
this.headers = options.headers;
this.agent = options.agent;
this.connected = false;
// keepAlive is true unless explicitly set to false
const keepAlive = options.keepAlive !== false;
this.host = host || 'http://localhost:8545';
if (!this.agent) {
if (this.host.substring(0,5) === "https") {
this.httpsAgent = new https.Agent({ keepAlive });
} else {
this.httpAgent = new http.Agent({ keepAlive });
}
}
};
HttpProvider.prototype._prepareRequest = function(){
var request;
// the current runtime is a browser
if (typeof XMLHttpRequest !== 'undefined') {
request = new XMLHttpRequest();
} else {
request = new XHR2();
var agents = {httpsAgent: this.httpsAgent, httpAgent: this.httpAgent, baseUrl: this.baseUrl};
if (this.agent) {
agents.httpsAgent = this.agent.https;
agents.httpAgent = this.agent.http;
agents.baseUrl = this.agent.baseUrl;
}
request.nodejsSet(agents);
}
request.open('POST', this.host, true);
request.setRequestHeader('Content-Type','application/json');
request.timeout = this.timeout;
request.withCredentials = this.withCredentials;
if(this.headers) {
this.headers.forEach(function(header) {
request.setRequestHeader(header.name, header.value);
});
}
return request;
};
/**
* Should be used to make async request
*
* @method send
* @param {Object} payload
* @param {Function} callback triggered on end with (err, result)
*/
HttpProvider.prototype.send = function (payload, callback) {
var _this = this;
var request = this._prepareRequest();
request.onreadystatechange = function() {
if (request.readyState === 4 && request.timeout !== 1) {
var result = request.responseText;
var error = null;
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(request.responseText);
}
_this.connected = true;
callback(error, result);
}
};
request.ontimeout = function() {
_this.connected = false;
callback(errors.ConnectionTimeout(this.timeout));
};
try {
request.send(JSON.stringify(payload));
} catch(error) {
this.connected = false;
callback(errors.InvalidConnection(this.host));
}
};
HttpProvider.prototype.disconnect = function () {
//NO OP
};
/**
* Returns the desired boolean.
*
* @method supportsSubscriptions
* @returns {boolean}
*/
HttpProvider.prototype.supportsSubscriptions = function () {
return false;
};
module.exports = HttpProvider;

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./lib"
},
"include": [
"./src"
]
}

View File

@ -0,0 +1,66 @@
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file index.d.ts
* @author Josh Stevens <joshstevens19@hotmail.co.uk>
* @date 2018
*/
import * as http from 'http';
import * as https from 'https';
import { HttpProviderBase, JsonRpcResponse } from 'web3-core-helpers';
export interface HttpHeader {
name: string;
value: string;
}
export interface HttpProviderAgent {
baseUrl?: string;
http?: http.Agent;
https?: https.Agent;
}
export interface HttpProviderOptions {
withCredentials?: boolean;
timeout?: number;
headers?: HttpHeader[];
agent?: HttpProviderAgent;
keepAlive?: boolean;
}
export class HttpProvider extends HttpProviderBase {
host: string;
withCredentials: boolean;
timeout: number;
headers?: HttpHeader[];
agent?: HttpProviderAgent;
connected: boolean;
constructor(host?: string, options?: HttpProviderOptions);
send(
payload: object,
callback?: (
error: Error | null,
result: JsonRpcResponse | undefined
) => void
): void;
disconnect(): boolean;
supportsSubscriptions(): boolean;
}

View File

@ -0,0 +1,51 @@
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file web3-provider-http-tests.ts
* @author Josh Stevens <joshstevens19@hotmail.co.uk> , Samuel Furter <samuel@ethereum.org>
* @date 2018
*/
import * as http from 'http';
import * as https from 'https';
import { HttpProvider } from 'web3-providers';
import { JsonRpcResponse } from 'web3-core-helpers';
const httpProvider = new HttpProvider('http://localhost:8545', {
timeout: 20000,
headers: [
{
name: 'Access-Control-Allow-Origin',
value: '*'
}
],
withCredentials: false,
agent: {
baseUrl: 'base',
http: new http.Agent({}),
https: new https.Agent({})
}
});
// $ExpectType void
httpProvider.send({}, (error: Error | null) => {});
// $ExpectType void
httpProvider.send({}, (error: Error | null, result: JsonRpcResponse | undefined) => {});
// $ExpectType boolean
httpProvider.disconnect();

View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": ["es6"],
"target": "es6",
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noEmit": true,
"allowSyntheticDefaultImports": false,
"baseUrl": ".",
"paths": {
"web3-providers": ["."]
}
}
}

View File

@ -0,0 +1,10 @@
{
"extends": "dtslint/dtslint.json",
"rules": {
"semicolon": false,
"no-import-default-of-export-equals": false,
"file-name-casing": [true, "kebab-case"],
"whitespace": false,
"no-unnecessary-class": false
}
}

2267
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,9 +14,11 @@
"circomlib": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4",
"commander": "^5.1.0",
"dotenv": "^8.2.0",
"gas-price-oracle": "^0.2.2",
"gas-price-oracle": "^0.4.4",
"socks-proxy-agent": "^6.1.1",
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
"web3": "^1.2.8",
"web3": "^1.6.1",
"web3-providers-http": "file:./local_modules/web3-providers-http",
"websnark": "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d"
},
"devDependencies": {

368
yarn.lock
View File

@ -39,6 +39,22 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
"@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348"
integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA==
dependencies:
crc-32 "^1.2.0"
ethereumjs-util "^7.1.3"
"@ethereumjs/tx@^3.3.2":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7"
integrity sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw==
dependencies:
"@ethereumjs/common" "^2.6.0"
ethereumjs-util "^7.1.3"
"@ethersproject/abi@5.0.7":
version "5.0.7"
resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b"
@ -232,6 +248,13 @@
dependencies:
"@types/node" "*"
"@types/bn.js@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68"
integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==
dependencies:
"@types/node" "*"
"@types/node@*":
version "14.14.14"
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae"
@ -279,6 +302,13 @@ acorn@^7.4.0:
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
agent-base@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
dependencies:
debug "4"
ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.9.1:
version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@ -421,6 +451,13 @@ axios@^0.19.2:
dependencies:
follow-redirects "1.5.10"
axios@^0.21.2:
version "0.21.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
dependencies:
follow-redirects "^1.14.0"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@ -511,6 +548,11 @@ bn.js@^5.0.0, bn.js@^5.1.1:
resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
bn.js@^5.1.2, bn.js@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
body-parser@1.19.0, body-parser@^1.16.0:
version "1.19.0"
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
@ -886,6 +928,14 @@ cors@^2.8.1:
object-assign "^4"
vary "^1"
crc-32@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==
dependencies:
exit-on-epipe "~1.0.1"
printj "~1.1.0"
create-ecdh@^4.0.0:
version "4.0.4"
resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
@ -976,6 +1026,13 @@ debug@2.6.9, debug@^2.2.0:
dependencies:
ms "2.0.0"
debug@4, debug@^4.3.1:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@ -1468,6 +1525,17 @@ ethereumjs-util@^6.0.0:
ethjs-util "0.1.6"
rlp "^2.2.3"
ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23"
integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw==
dependencies:
"@types/bn.js" "^5.1.0"
bn.js "^5.1.2"
create-hash "^1.1.2"
ethereum-cryptography "^0.1.3"
rlp "^2.2.4"
ethjs-unit@0.1.6:
version "0.1.6"
resolved "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699"
@ -1510,6 +1578,11 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exit-on-epipe@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
express@^4.14.0:
version "4.17.1"
resolved "https://registry.npmjs.org/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
@ -1672,6 +1745,11 @@ follow-redirects@1.5.10:
dependencies:
debug "=3.1.0"
follow-redirects@^1.14.0:
version "1.14.5"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
@ -1732,12 +1810,12 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
gas-price-oracle@^0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/gas-price-oracle/-/gas-price-oracle-0.2.2.tgz#32c57a9aa6bc69152be96812880232efebfecbc6"
integrity sha512-I4+rLbc7C1vgYXV+cYY0MKeqdZVna2hXpNfD2fcIvf/wIgvtIYmG9gsmhiaYGSgOE2RSPUs2xf/W4K2nJOoNuQ==
gas-price-oracle@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.4.4.tgz#9b7e5583ed7126a68f9d230b9efbd9d75d864bad"
integrity sha512-alAHLiZmPJ+GxKvujZZzEY8NRPqgGGHmDQUPFTa6HAMFB4LR/T6ShTDbqQzsdeWLPSw/j8/Gux0ZSC2AsPK+Hg==
dependencies:
axios "^0.19.2"
axios "^0.21.2"
bignumber.js "^9.0.0"
get-caller-file@^1.0.1:
@ -2059,6 +2137,11 @@ invert-kv@^2.0.0:
resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@ -2883,6 +2966,11 @@ prepend-http@^2.0.0:
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
printj@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@ -3089,6 +3177,13 @@ rlp@^2.2.3:
dependencies:
bn.js "^4.11.1"
rlp@^2.2.4:
version "2.2.7"
resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf"
integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==
dependencies:
bn.js "^5.2.0"
run-async@^2.2.0:
version "2.4.1"
resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@ -3266,6 +3361,11 @@ slice-ansi@^4.0.0:
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
smart-buffer@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
"snarkjs@git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5":
version "0.1.20"
resolved "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
@ -3277,6 +3377,23 @@ slice-ansi@^4.0.0:
keccak "^2.0.0"
yargs "^12.0.5"
socks-proxy-agent@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87"
integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==
dependencies:
agent-base "^6.0.2"
debug "^4.3.1"
socks "^2.6.1"
socks@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e"
integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==
dependencies:
ip "^1.1.5"
smart-buffer "^4.1.0"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@ -3714,6 +3831,15 @@ web3-bzz@1.3.1:
swarm-js "^0.1.40"
underscore "1.9.1"
web3-bzz@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.6.1.tgz#8430eb3cbb69baaee4981d190b840748c37a9ec2"
integrity sha512-JbnFNbRlwwHJZPtVuCxo7rC4U4OTg+mPsyhjgPQJJhS0a6Y54OgVWYk9UA/95HqbmTJwTtX329gJoSsseEfrng==
dependencies:
"@types/node" "^12.12.6"
got "9.6.0"
swarm-js "^0.1.40"
web3-core-helpers@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.3.1.tgz#ffd6f47c1b54a8523f00760a8d713f44d0f97e97"
@ -3723,6 +3849,14 @@ web3-core-helpers@1.3.1:
web3-eth-iban "1.3.1"
web3-utils "1.3.1"
web3-core-helpers@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.6.1.tgz#cb21047306871f4cf0fedfece7d47ea2aa96141b"
integrity sha512-om2PZvK1uoWcgMq6JfcSx3241LEIVF6qi2JuHz2SLKiKEW5UsBUaVx0mNCmcZaiuYQCyOsLS3r33q5AdM+v8ng==
dependencies:
web3-eth-iban "1.6.1"
web3-utils "1.6.1"
web3-core-method@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.3.1.tgz#c1d8bf1e2104a8d625c99caf94218ad2dc948c92"
@ -3735,6 +3869,17 @@ web3-core-method@1.3.1:
web3-core-subscriptions "1.3.1"
web3-utils "1.3.1"
web3-core-method@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.6.1.tgz#4ae91c639bf1da85ebfd8b99595da6a2235d7b98"
integrity sha512-szH5KyIWIaULQDBdDvevQUCHV9lsExJ/oV0ePqK+w015D2SdMPMuhii0WB+HCePaksWO+rr/GAypvV9g2T3N+w==
dependencies:
"@ethersproject/transactions" "^5.0.0-beta.135"
web3-core-helpers "1.6.1"
web3-core-promievent "1.6.1"
web3-core-subscriptions "1.6.1"
web3-utils "1.6.1"
web3-core-promievent@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.3.1.tgz#b4da4b34cd9681e22fcda25994d7629280a1e046"
@ -3742,6 +3887,13 @@ web3-core-promievent@1.3.1:
dependencies:
eventemitter3 "4.0.4"
web3-core-promievent@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.6.1.tgz#f650dea9361e2edf02691015b213fcc8ea499992"
integrity sha512-byJ5s2MQxrWdXd27pWFmujfzsTZK4ik8rDgIV1RFDFc+rHZ2nZhq+VWk7t/Nkrj7EaVXncEgTdPEHc18nx+ocQ==
dependencies:
eventemitter3 "4.0.4"
web3-core-requestmanager@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.3.1.tgz#6dd2b5161ba778dfffe68994a4accff2decc54fe"
@ -3754,6 +3906,17 @@ web3-core-requestmanager@1.3.1:
web3-providers-ipc "1.3.1"
web3-providers-ws "1.3.1"
web3-core-requestmanager@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.6.1.tgz#d9c08b0716c9cda546a0c02767b7e08deb04448a"
integrity sha512-4y7etYEUtkfflyYVBfN1oJtCbVFNhNX1omlEYzezhTnPj3/dT7n+dhUXcqvIhx9iKA13unGfpFge80XNFfcB8A==
dependencies:
util "^0.12.0"
web3-core-helpers "1.6.1"
web3-providers-http "1.6.1"
web3-providers-ipc "1.6.1"
web3-providers-ws "1.6.1"
web3-core-subscriptions@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.3.1.tgz#be1103259f91b7fc7f4c6a867aa34dea70a636f7"
@ -3763,6 +3926,14 @@ web3-core-subscriptions@1.3.1:
underscore "1.9.1"
web3-core-helpers "1.3.1"
web3-core-subscriptions@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.6.1.tgz#4dfc1f74137354d4ac9eaa628aa916c5e2cc8741"
integrity sha512-WZwxsYttIojyGQ5RqxuQcKg0IJdDCFpUe4EncS3QKZwxPqWzGmgyLwE0rm7tP+Ux1waJn5CUaaoSCBxWGSun1g==
dependencies:
eventemitter3 "4.0.4"
web3-core-helpers "1.6.1"
web3-core@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-core/-/web3-core-1.3.1.tgz#fb0fc5d952a7f3d580a7e6155d2f28be064e64cb"
@ -3776,6 +3947,19 @@ web3-core@1.3.1:
web3-core-requestmanager "1.3.1"
web3-utils "1.3.1"
web3-core@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.6.1.tgz#b41f08fdc9ea1082d15384a3d6fa93a47c3fc1b4"
integrity sha512-m+b7UfYvU5cQUAh6NRfxRzH/5B3to1AdEQi1HIQt570cDWlObOOmoO9tY6iJnI5w4acxIO19LqjDMqEJGBYyRQ==
dependencies:
"@types/bn.js" "^4.11.5"
"@types/node" "^12.12.6"
bignumber.js "^9.0.0"
web3-core-helpers "1.6.1"
web3-core-method "1.6.1"
web3-core-requestmanager "1.6.1"
web3-utils "1.6.1"
web3-eth-abi@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.3.1.tgz#d60fe5f15c7a3a426c553fdaa4199d07f1ad899c"
@ -3785,6 +3969,14 @@ web3-eth-abi@1.3.1:
underscore "1.9.1"
web3-utils "1.3.1"
web3-eth-abi@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.6.1.tgz#15b937e3188570754d50bbac51a4bb0578600d1d"
integrity sha512-svhYrAlXP9XQtV7poWKydwDJq2CaNLMtmKydNXoOBLcQec6yGMP+v20pgrxF2H6wyTK+Qy0E3/5ciPOqC/VuoQ==
dependencies:
"@ethersproject/abi" "5.0.7"
web3-utils "1.6.1"
web3-eth-accounts@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.3.1.tgz#63b247461f1ae0ae46f9a5d5aa896ea80237143e"
@ -3802,6 +3994,23 @@ web3-eth-accounts@1.3.1:
web3-core-method "1.3.1"
web3-utils "1.3.1"
web3-eth-accounts@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.6.1.tgz#aeb0dfb52c4391773550569732975b471212583f"
integrity sha512-rGn3jwnuOKwaQRu4SiShz0YAQ87aVDBKs4HO43+XTCI1q1Y1jn3NOsG3BW9ZHaOckev4+zEyxze/Bsh2oEk24w==
dependencies:
"@ethereumjs/common" "^2.5.0"
"@ethereumjs/tx" "^3.3.2"
crypto-browserify "3.12.0"
eth-lib "0.2.8"
ethereumjs-util "^7.0.10"
scrypt-js "^3.0.1"
uuid "3.3.2"
web3-core "1.6.1"
web3-core-helpers "1.6.1"
web3-core-method "1.6.1"
web3-utils "1.6.1"
web3-eth-contract@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.3.1.tgz#05cb77bd2a671c5480897d20de487f3bae82e113"
@ -3817,6 +4026,20 @@ web3-eth-contract@1.3.1:
web3-eth-abi "1.3.1"
web3-utils "1.3.1"
web3-eth-contract@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.6.1.tgz#4b0a2c0b37015d70146e54c7cb3f035a58fbeec0"
integrity sha512-GXqTe3mF6kpbOAakiNc7wtJ120/gpuKMTZjuGFKeeY8aobRLfbfgKzM9IpyqVZV2v5RLuGXDuurVN2KPgtu3hQ==
dependencies:
"@types/bn.js" "^4.11.5"
web3-core "1.6.1"
web3-core-helpers "1.6.1"
web3-core-method "1.6.1"
web3-core-promievent "1.6.1"
web3-core-subscriptions "1.6.1"
web3-eth-abi "1.6.1"
web3-utils "1.6.1"
web3-eth-ens@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.3.1.tgz#ccfd621ddc1fecb44096bc8e60689499a9eb4421"
@ -3832,6 +4055,20 @@ web3-eth-ens@1.3.1:
web3-eth-contract "1.3.1"
web3-utils "1.3.1"
web3-eth-ens@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.6.1.tgz#801bd5fb5237377ec2ed8517a9fe4634f2269c7a"
integrity sha512-ngprtbnoRgxg8s1wXt9nXpD3h1P+p7XnKXrp/8GdFI9uDmrbSQPRfzBw86jdZgOmy78hAnWmrHI6pBInmgi2qQ==
dependencies:
content-hash "^2.5.2"
eth-ens-namehash "2.0.8"
web3-core "1.6.1"
web3-core-helpers "1.6.1"
web3-core-promievent "1.6.1"
web3-eth-abi "1.6.1"
web3-eth-contract "1.6.1"
web3-utils "1.6.1"
web3-eth-iban@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.3.1.tgz#4351e1a658efa5f3218357f0a38d6d8cad82481e"
@ -3840,6 +4077,14 @@ web3-eth-iban@1.3.1:
bn.js "^4.11.9"
web3-utils "1.3.1"
web3-eth-iban@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.6.1.tgz#20bbed75723e3e9ff98e624979629d26329462b6"
integrity sha512-91H0jXZnWlOoXmc13O9NuQzcjThnWyAHyDn5Yf7u6mmKOhpJSGF/OHlkbpXt1Y4v2eJdEPaVFa+6i8aRyagE7Q==
dependencies:
bn.js "^4.11.9"
web3-utils "1.6.1"
web3-eth-personal@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.3.1.tgz#cfe8af01588870d195dabf0a8d9e34956fb8856d"
@ -3852,6 +4097,18 @@ web3-eth-personal@1.3.1:
web3-net "1.3.1"
web3-utils "1.3.1"
web3-eth-personal@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.6.1.tgz#9b524fb9f92b51163f46920ee2663d34a4897c8d"
integrity sha512-ItsC89Ln02+irzJjK6ALcLrMZfbVUCqVbmb/ieDKJ+eLW3pNkBNwoUzaydh92d5NzxNZgNxuQWVdlFyYX2hkEw==
dependencies:
"@types/node" "^12.12.6"
web3-core "1.6.1"
web3-core-helpers "1.6.1"
web3-core-method "1.6.1"
web3-net "1.6.1"
web3-utils "1.6.1"
web3-eth@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-eth/-/web3-eth-1.3.1.tgz#60ac4b58e5fd17b8dbbb8378abd63b02e8326727"
@ -3871,6 +4128,24 @@ web3-eth@1.3.1:
web3-net "1.3.1"
web3-utils "1.3.1"
web3-eth@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.6.1.tgz#a25aba1ac213d872ecf3f81c7b4ab8072ecae224"
integrity sha512-kOV1ZgCKypSo5BQyltRArS7ZC3bRpIKAxSgzl7pUFinUb/MxfbM9KGeNxUXoCfTSErcCQJaDjcS6bSre5EMKuQ==
dependencies:
web3-core "1.6.1"
web3-core-helpers "1.6.1"
web3-core-method "1.6.1"
web3-core-subscriptions "1.6.1"
web3-eth-abi "1.6.1"
web3-eth-accounts "1.6.1"
web3-eth-contract "1.6.1"
web3-eth-ens "1.6.1"
web3-eth-iban "1.6.1"
web3-eth-personal "1.6.1"
web3-net "1.6.1"
web3-utils "1.6.1"
web3-net@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-net/-/web3-net-1.3.1.tgz#79374b1df37429b0839b83b0abc4440ac6181568"
@ -3880,6 +4155,15 @@ web3-net@1.3.1:
web3-core-method "1.3.1"
web3-utils "1.3.1"
web3-net@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.6.1.tgz#7a630a804ec9f81908ae52ccbb4ebbb9530b3906"
integrity sha512-gpnqKEIwfUHh5ik7wsQFlCje1DfcmGv+Sk7LCh1hCqn++HEDQxJ/mZCrMo11ZZpZHCH7c87imdxTg96GJnRxDw==
dependencies:
web3-core "1.6.1"
web3-core-method "1.6.1"
web3-utils "1.6.1"
web3-providers-http@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.3.1.tgz#becbea61706b2fa52e15aca6fe519ee108a8fab9"
@ -3888,6 +4172,20 @@ web3-providers-http@1.3.1:
web3-core-helpers "1.3.1"
xhr2-cookies "1.1.0"
web3-providers-http@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.6.1.tgz#b59b14eefef23b98c327806f5f566303a73bd435"
integrity sha512-xBoKOJxu10+kO3ikamXmBfrWZ/xpQOGy0ocdp7Y81B17En5TXELwlmMXt1UlIgWiyYDhjq4OwlH/VODYqHXy3A==
dependencies:
web3-core-helpers "1.6.1"
xhr2-cookies "1.1.0"
"web3-providers-http@file:./local_modules/web3-providers-http":
version "1.6.1"
dependencies:
web3-core-helpers "1.6.1"
xhr2-cookies "file:./../../AppData/Local/Yarn/Cache/v6/npm-web3-providers-http-1.6.1-6879cf8b-ee02-483d-9a46-76314494b334-1638895560210/node_modules/web3-providers-http/local_modules/xhr2-cookies"
web3-providers-ipc@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.3.1.tgz#3cb2572fc5286ab2f3117e0a2dce917816c3dedb"
@ -3897,6 +4195,14 @@ web3-providers-ipc@1.3.1:
underscore "1.9.1"
web3-core-helpers "1.3.1"
web3-providers-ipc@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.6.1.tgz#7ba460589d46896bb3d124288deed1b6a72d517e"
integrity sha512-anyoIZlpMzwEQI4lwylTzDrHsVp20v0QUtSTp2B5jInBinmQtyCE7vnbX20jEQ4j5uPwfJabKNtoJsk6a3O4WQ==
dependencies:
oboe "2.1.5"
web3-core-helpers "1.6.1"
web3-providers-ws@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.3.1.tgz#a70140811d138a1a5cf3f0c39d11887c8e341c83"
@ -3907,6 +4213,15 @@ web3-providers-ws@1.3.1:
web3-core-helpers "1.3.1"
websocket "^1.0.32"
web3-providers-ws@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.6.1.tgz#f7ee71f158971102b865e99ea7911f483e0507e9"
integrity sha512-FWMEFYb4rYFYRgSFBf/O1Ex4p/YKSlN+JydCtdlJwRimd89qm95CTfs4xGjCskwvXMjV2sarH+f1NPwJXicYpg==
dependencies:
eventemitter3 "4.0.4"
web3-core-helpers "1.6.1"
websocket "^1.0.32"
web3-shh@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-shh/-/web3-shh-1.3.1.tgz#42294d684358c22aa48616cb9a3eb2e9c1e6362f"
@ -3917,6 +4232,16 @@ web3-shh@1.3.1:
web3-core-subscriptions "1.3.1"
web3-net "1.3.1"
web3-shh@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.6.1.tgz#eebaab2e5e6be80fe2585c6c094fa10a03349ca7"
integrity sha512-oP00HbAtybLCGlLOZUYXOdeB9xq88k2l0TtStvKBtmFqRt+zVk5TxEeuOnVPRxNhcA2Un8RUw6FtvgZlWStu9A==
dependencies:
web3-core "1.6.1"
web3-core-method "1.6.1"
web3-core-subscriptions "1.6.1"
web3-net "1.6.1"
web3-utils@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/web3-utils/-/web3-utils-1.3.1.tgz#9aa880dd8c9463fe5c099107889f86a085370c2e"
@ -3931,7 +4256,20 @@ web3-utils@1.3.1:
underscore "1.9.1"
utf8 "3.0.0"
web3@^1.2.11, web3@^1.2.8:
web3-utils@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.6.1.tgz#befcb23922b00603ab56d8c5b4158468dc494aca"
integrity sha512-RidGKv5kOkcerI6jQqDFDoTllQQqV+rPhTzZHhmbqtFObbYpU93uc+yG1LHivRTQhA6llIx67iudc/vzisgO+w==
dependencies:
bn.js "^4.11.9"
ethereum-bloom-filters "^1.0.6"
ethereumjs-util "^7.1.0"
ethjs-unit "0.1.6"
number-to-bn "1.7.0"
randombytes "^2.1.0"
utf8 "3.0.0"
web3@^1.2.11:
version "1.3.1"
resolved "https://registry.npmjs.org/web3/-/web3-1.3.1.tgz#f780138c92ae3c42ea45e1a3c6ae8844e0aa5054"
integrity sha512-lDJwOLSRWHYwhPy4h5TNgBRJ/lED7lWXyVOXHCHcEC8ai3coBNdgEXWBu/GGYbZMsS89EoUOJ14j3Ufi4dUkog==
@ -3944,6 +4282,19 @@ web3@^1.2.11, web3@^1.2.8:
web3-shh "1.3.1"
web3-utils "1.3.1"
web3@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.6.1.tgz#c9e68fe7b3073adddf35393441f950ec69b92735"
integrity sha512-c299lLiyb2/WOcxh7TinwvbATaMmrgNIeAzbLbmOKHI0LcwyfsB1eu2ReOIrfrCYDYRW2KAjYr7J7gHawqDNPQ==
dependencies:
web3-bzz "1.6.1"
web3-core "1.6.1"
web3-eth "1.6.1"
web3-eth-personal "1.6.1"
web3-net "1.6.1"
web3-shh "1.6.1"
web3-utils "1.6.1"
"websnark@git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d":
version "0.0.4"
resolved "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d"
@ -4060,6 +4411,11 @@ xhr2-cookies@1.1.0:
dependencies:
cookiejar "^2.1.1"
"xhr2-cookies@file:./local_modules/web3-providers-http/local_modules/xhr2-cookies":
version "1.1.0"
dependencies:
cookiejar "^2.1.1"
xhr@^2.0.4, xhr@^2.3.3:
version "2.6.0"
resolved "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d"