Merge pull request #16 from 0xAyanami/develop
EIP-1559 & Tor Socks5 Proxy & BSC network support
This commit is contained in:
commit
4b13d53cab
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
.env
|
||||
.idea
|
||||
backup-tornado-*
|
500
README.md
500
README.md
@ -1,13 +1,13 @@
|
||||
# Warning!
|
||||
Current cli version doesn't support [Anonymity Mining](https://tornado-cash.medium.com/tornado-cash-governance-proposal-a55c5c7d0703)
|
||||
|
||||
### Goerli, Mainnet
|
||||
### Goerli, Mainnet, Binance Smart Chain
|
||||
1. Add `PRIVATE_KEY` to `.env` file
|
||||
2. `./cli.js --help`
|
||||
|
||||
Example:
|
||||
```bash
|
||||
$ ./cli.js deposit ETH 0.1 --rpc https://goerli.infura.io/v3/27a9649f826b4e31a83e07ae09a87448
|
||||
$ ./cli.js deposit ETH 0.1 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --tor 9050
|
||||
|
||||
Your note: tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652
|
||||
Tornado ETH balance is 8.9
|
||||
@ -18,7 +18,7 @@ Sender account ETH balance is 1004873.361652048361352542
|
||||
```
|
||||
|
||||
```bash
|
||||
$ ./cli.js withdraw tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://goerli.infura.io/v3/27a9649f826b4e31a83e07ae09a87448 --relayer https://goerli-frelay.duckdns.org
|
||||
$ ./cli.js withdraw tornado-eth-0.1-5-0xf73dd6833ccbcc046c44228c8e2aa312bf49e08389dadc7c65e6a73239867b7ef49c705c4db227e2fadd8489a494b6880bdcb6016047e019d1abec1c7652 0x8589427373D6D84E98730D7795D8f6f8731FDA16 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --relayer https://goerli-frelay.duckdns.org --tor 9050
|
||||
|
||||
Relay address: 0x6A31736e7490AbE5D5676be059DFf064AB4aC754
|
||||
Getting current state from tornado contract
|
||||
@ -29,3 +29,497 @@ Transaction submitted through the relay. View transaction on etherscan https://g
|
||||
Transaction mined in block 17036120
|
||||
Done
|
||||
```
|
||||
|
||||
### List of public rpc & relayers for withdrawal
|
||||
|
||||
Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
|
||||
```json
|
||||
{
|
||||
"netId1":{
|
||||
"rpcUrls":{
|
||||
"Infura":{
|
||||
"name":"Infura",
|
||||
"url":"https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"
|
||||
},
|
||||
"MyEtherWallet":{
|
||||
"name":"MyEtherWallet",
|
||||
"url":"https://nodes.mewapi.io/rpc/eth"
|
||||
},
|
||||
"MyCrypto":{
|
||||
"name":"MyCrypto",
|
||||
"url":"https://api.mycryptoapi.com/eth"
|
||||
},
|
||||
"CloudFlare":{
|
||||
"name":"CloudFlare",
|
||||
"url":"https://cloudflare-eth.com"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"mainnet-v2.poanet.eth":{
|
||||
"url":"mainnet-v2.poanet.eth",
|
||||
"name":"mainnet-v2.poanet.eth",
|
||||
"cachedUrl":"https://tornado-mainnet-v2.poa.network/"
|
||||
},
|
||||
"mainnet-v2.relaymy.eth":{
|
||||
"url":"mainnet-v2.relaymy.eth",
|
||||
"name":"mainnet-v2.relaymy.eth",
|
||||
"cachedUrl":"https://mainnet-v2.relaymy.xyz/"
|
||||
},
|
||||
"mainnet-v2.gaasservices.eth":{
|
||||
"url":"mainnet-v2.gaasservices.eth",
|
||||
"name":"mainnet-v2.gaasservices.eth",
|
||||
"cachedUrl":"https://mainnet-v2.gaas.services/"
|
||||
},
|
||||
"mainnet-v2.reasoned.eth":{
|
||||
"url":"mainnet-v2.reasoned.eth",
|
||||
"name":"mainnet-v2.reasoned.eth",
|
||||
"cachedUrl":"https://mainnet-v2.solarsis.net/"
|
||||
},
|
||||
"v2.mainnet.thewizardseye.eth":{
|
||||
"url":"v2.mainnet.thewizardseye.eth",
|
||||
"name":"v2.mainnet.thewizardseye.eth",
|
||||
"cachedUrl":"https://v2.mainnet.thewizardseye.de/"
|
||||
},
|
||||
"v2.odanrot.eth":{
|
||||
"url":"v2.odanrot.eth",
|
||||
"name":"v2.odanrot.eth",
|
||||
"cachedUrl":"https://tcrv2.avado.cloud/"
|
||||
},
|
||||
"mainnet-v2.releth.eth":{
|
||||
"url":"mainnet-v2.releth.eth",
|
||||
"name":"mainnet-v2.releth.eth",
|
||||
"cachedUrl":"https://mainnet-v2.reloch.net/"
|
||||
},
|
||||
"mainnet.t-relay.eth":{
|
||||
"url":"mainnet.t-relay.eth",
|
||||
"name":"mainnet.t-relay.eth",
|
||||
"cachedUrl":"https://mainnet.t-relay.online/"
|
||||
},
|
||||
"mainnet-v2.therelayer.eth":{
|
||||
"url":"mainnet-v2.therelayer.eth",
|
||||
"name":"mainnet-v2.therelayer.eth",
|
||||
"cachedUrl":"https://mainnet-v2.therelayer.xyz/"
|
||||
},
|
||||
"mainnet.relayer-service.eth":{
|
||||
"url":"mainnet.relayer-service.eth",
|
||||
"name":"mainnet.relayer-service.eth",
|
||||
"cachedUrl":"https://mainnet-relayer.hertz.zone/"
|
||||
},
|
||||
"mainnet-v2.tornadosolutions.eth":{
|
||||
"url":"mainnet-v2.tornadosolutions.eth",
|
||||
"name":"mainnet-v2.tornadosolutions.eth",
|
||||
"cachedUrl":"https://mainnet-v2.tornado.solutions/"
|
||||
},
|
||||
"mainnet-v2.torn.eth":{
|
||||
"url":"mainnet-v2.torn.eth",
|
||||
"name":"mainnet-v2.torn.eth",
|
||||
"cachedUrl":"https://mainnet-v2.torn.cash/"
|
||||
},
|
||||
"mainnet-v2.defidevotee.eth":{
|
||||
"url":"mainnet-v2.defidevotee.eth",
|
||||
"name":"mainnet-v2.defidevotee.eth",
|
||||
"cachedUrl":"https://mainnet-v2.defidevotee.xyz/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId56":{
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"BSC Public RPC 1",
|
||||
"url":"https://bsc-dataseed.binance.org/"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"BSC Public RPC 2",
|
||||
"url":"https://bsc-dataseed1.defibit.io/"
|
||||
},
|
||||
"publicRpc3":{
|
||||
"name":"BSC Public RPC 3",
|
||||
"url":"https://bsc-dataseed1.ninicoin.io/"
|
||||
},
|
||||
"MyEtherWallet":{
|
||||
"name":"MyEtherWallet",
|
||||
"url":"https://nodes.mewapi.io/rpc/bsc/"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"bsc.relayer-service.eth":{
|
||||
"url":"bsc.relayer-service.eth",
|
||||
"name":"bsc.relayer-service.eth",
|
||||
"cachedUrl":"https://bsc-relayer.hertz.zone/"
|
||||
},
|
||||
"bsc.t-relay.eth":{
|
||||
"url":"bsc.t-relay.eth",
|
||||
"name":"bsc.t-relay.eth",
|
||||
"cachedUrl":"https://bsc.t-relay.online/"
|
||||
},
|
||||
"bsc.therelayer.eth":{
|
||||
"url":"bsc.therelayer.eth",
|
||||
"name":"bsc.therelayer.eth",
|
||||
"cachedUrl":"https://bsc.therelayer.xyz/"
|
||||
},
|
||||
"bsc-v2.defidevotee.eth":{
|
||||
"url":"bsc-v2.defidevotee.eth",
|
||||
"name":"bsc-v2.defidevotee.eth",
|
||||
"cachedUrl":"https://bsc-v2.defidevotee.xyz/"
|
||||
},
|
||||
"v1.bsc.thewizardseye.eth":{
|
||||
"url":"v1.bsc.thewizardseye.eth",
|
||||
"name":"v1.bsc.thewizardseye.eth",
|
||||
"cachedUrl":"https://v1.bsc.thewizardseye.de/"
|
||||
},
|
||||
"bsc.relaymy.eth":{
|
||||
"url":"bsc.relaymy.eth",
|
||||
"name":"bsc.relaymy.eth",
|
||||
"cachedUrl":"https://bsc.relaymy.xyz/"
|
||||
},
|
||||
"bsc.torn.eth":{
|
||||
"url":"bsc.torn.eth",
|
||||
"name":"bsc.torn.eth",
|
||||
"cachedUrl":"https://bsc.torn.cash/"
|
||||
},
|
||||
"bsc.gaasservices.eth":{
|
||||
"url":"bsc.gaasservices.eth",
|
||||
"name":"bsc.gaasservices.eth",
|
||||
"cachedUrl":"https://bsc.gaas.services/"
|
||||
},
|
||||
"bsc.tornadosolutions.eth":{
|
||||
"url":"bsc.tornadosolutions.eth",
|
||||
"name":"bsc.tornadosolutions.eth",
|
||||
"cachedUrl":"https://bsc.tornado.solutions/"
|
||||
},
|
||||
"bsc.odanrot.eth":{
|
||||
"url":"bsc.odanrot.eth",
|
||||
"name":"bsc.odanrot.eth",
|
||||
"cachedUrl":"https://tcrbsc.avado.cloud/"
|
||||
},
|
||||
"bsc.releth.eth":{
|
||||
"url":"bsc.releth.eth",
|
||||
"name":"bsc.releth.eth",
|
||||
"cachedUrl":"https://bsc.reloch.net/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId100":{
|
||||
"rpcUrls":{
|
||||
"publicRpc":{
|
||||
"name":"xDAI Chain RPC",
|
||||
"url":"https://rpc.xdaichain.com"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"xDAI Chain RPC2",
|
||||
"url":"https://xdai.poanetwork.dev"
|
||||
},
|
||||
"publicRpc3":{
|
||||
"name":"xDAI Chain RPC3",
|
||||
"url":"https://dai.poa.network/"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"xdai.relayer-service.eth":{
|
||||
"url":"xdai.relayer-service.eth",
|
||||
"name":"xdai.relayer-service.eth",
|
||||
"cachedUrl":"https://xdai-relayer.hertz.zone/"
|
||||
},
|
||||
"xdai.releth.eth":{
|
||||
"url":"xdai.releth.eth",
|
||||
"name":"xdai.releth.eth",
|
||||
"cachedUrl":"https://xdai.reloch.net/"
|
||||
},
|
||||
"xdai.relaymy.eth":{
|
||||
"url":"xdai.relaymy.eth",
|
||||
"name":"xdai.relaymy.eth",
|
||||
"cachedUrl":"https://xdai.relaymy.xyz/"
|
||||
},
|
||||
"xdai.torn.eth":{
|
||||
"url":"xdai.torn.eth",
|
||||
"name":"xdai.torn.eth",
|
||||
"cachedUrl":"https://xdai.torn.cash/"
|
||||
},
|
||||
"xdai.t-relay.eth":{
|
||||
"url":"xdai.t-relay.eth",
|
||||
"name":"xdai.t-relay.eth",
|
||||
"cachedUrl":"https://xdai.t-relay.online/"
|
||||
},
|
||||
"xdai-v2.poanet.eth":{
|
||||
"url":"xdai-v2.poanet.eth",
|
||||
"name":"xdai-v2.poanet.eth",
|
||||
"cachedUrl":"https://tornado-xdai.poa.network/"
|
||||
},
|
||||
"xdai.gaasservices.eth":{
|
||||
"url":"xdai.gaasservices.eth",
|
||||
"name":"xdai.gaasservices.eth",
|
||||
"cachedUrl":"https://xdai.gaas.services/"
|
||||
},
|
||||
"xdai.therelayer.eth":{
|
||||
"url":"xdai.therelayer.eth",
|
||||
"name":"xdai.therelayer.eth",
|
||||
"cachedUrl":"https://xdai.therelayer.xyz/"
|
||||
},
|
||||
"xdai.tornadosolutions.eth":{
|
||||
"url":"xdai.tornadosolutions.eth",
|
||||
"name":"xdai.tornadosolutions.eth",
|
||||
"cachedUrl":"https://xdai.tornado.solutions/"
|
||||
},
|
||||
"xdai.odanrot.eth":{
|
||||
"url":"xdai.odanrot.eth",
|
||||
"name":"xdai.odanrot.eth",
|
||||
"cachedUrl":"https://tcxdai.avado.cloud/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId137":{
|
||||
"rpcUrls":{
|
||||
"publicRpc1":{
|
||||
"name":"publicRpc1",
|
||||
"url":"https://polygon-rpc.com"
|
||||
},
|
||||
"publicRpc2":{
|
||||
"name":"publicRpc2",
|
||||
"url":"https://rpc-mainnet.matic.network"
|
||||
},
|
||||
"publicRpc3":{
|
||||
"name":"publicRpc3",
|
||||
"url":"https://matic-mainnet.chainstacklabs.com"
|
||||
},
|
||||
"MyEtherWallet":{
|
||||
"name":"MyEtherWallet",
|
||||
"url":"https://nodes.mewapi.io/ws/matic"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"polygon.therelayer.eth":{
|
||||
"url":"polygon.therelayer.eth",
|
||||
"name":"polygon.therelayer.eth",
|
||||
"cachedUrl":"https://polygon.therelayer.xyz/"
|
||||
},
|
||||
"polygon.odanrot.eth":{
|
||||
"url":"polygon.odanrot.eth",
|
||||
"name":"polygon.odanrot.eth",
|
||||
"cachedUrl":"https://tcrmatic.avado.cloud/"
|
||||
},
|
||||
"polygon.t-relay.eth":{
|
||||
"url":"polygon.t-relay.eth",
|
||||
"name":"polygon.t-relay.eth",
|
||||
"cachedUrl":"https://polygon.t-relay.online/"
|
||||
},
|
||||
"polygon.relayer-service.eth":{
|
||||
"url":"polygon.relayer-service.eth",
|
||||
"name":"polygon.relayer-service.eth",
|
||||
"cachedUrl":"https://polygon-relayer.hertz.zone/"
|
||||
},
|
||||
"poly.releth.eth":{
|
||||
"url":"poly.releth.eth",
|
||||
"name":"poly.releth.eth",
|
||||
"cachedUrl":"https://poly.reloch.net/"
|
||||
},
|
||||
"v1.polygon.thewizardseye.eth":{
|
||||
"url":"v1.polygon.thewizardseye.eth",
|
||||
"name":"v1.polygon.thewizardseye.eth",
|
||||
"cachedUrl":"https://v1.polygon.thewizardseye.de/"
|
||||
},
|
||||
"polygon.reasoned.eth":{
|
||||
"url":"polygon.reasoned.eth",
|
||||
"name":"polygon.reasoned.eth",
|
||||
"cachedUrl":"https://polygon.solarsis.net/"
|
||||
},
|
||||
"polygon.torn.eth":{
|
||||
"url":"polygon.torn.eth",
|
||||
"name":"polygon.torn.eth",
|
||||
"cachedUrl":"https://polygon.torn.cash/"
|
||||
},
|
||||
"polygon.relaymy.eth":{
|
||||
"url":"polygon.relaymy.eth",
|
||||
"name":"polygon.relaymy.eth",
|
||||
"cachedUrl":"https://polygon.relaymy.xyz/"
|
||||
},
|
||||
"polygon.tornadosolutions.eth":{
|
||||
"url":"polygon.tornadosolutions.eth",
|
||||
"name":"polygon.tornadosolutions.eth",
|
||||
"cachedUrl":"https://polygon.tornado.solutions/"
|
||||
},
|
||||
"polygon.gaasservices.eth":{
|
||||
"url":"polygon.gaasservices.eth",
|
||||
"name":"polygon.gaasservices.eth",
|
||||
"cachedUrl":"https://polygon.gaas.services/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId42161":{
|
||||
"rpcUrls":{
|
||||
"Arbitrum":{
|
||||
"name":"Arbitrum Public RPC",
|
||||
"url":"https://arb1.arbitrum.io/rpc"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"arb.releth.eth":{
|
||||
"url":"arb.releth.eth",
|
||||
"name":"arb.releth.eth",
|
||||
"cachedUrl":"https://arbitrum.reloch.net/"
|
||||
},
|
||||
"arbitrum.therelayer.eth":{
|
||||
"url":"arbitrum.therelayer.eth",
|
||||
"name":"arbitrum.therelayer.eth",
|
||||
"cachedUrl":"https://arbitrum.therelayer.xyz/"
|
||||
},
|
||||
"arbitrum.relayer-service.eth":{
|
||||
"url":"arbitrum.relayer-service.eth",
|
||||
"name":"arbitrum.relayer-service.eth",
|
||||
"cachedUrl":"https://arbitrum-relayer.hertz.zone/"
|
||||
},
|
||||
"arbitrum.t-relay.eth":{
|
||||
"url":"arbitrum.t-relay.eth",
|
||||
"name":"arbitrum.t-relay.eth",
|
||||
"cachedUrl":"https://arbitrum.t-relay.online/"
|
||||
},
|
||||
"arbitrum.relaymy.eth":{
|
||||
"url":"arbitrum.relaymy.eth",
|
||||
"name":"arbitrum.relaymy.eth",
|
||||
"cachedUrl":"https://arbitrum.relaymy.xyz/"
|
||||
},
|
||||
"arbitrum.torn.eth":{
|
||||
"url":"arbitrum.torn.eth",
|
||||
"name":"arbitrum.torn.eth",
|
||||
"cachedUrl":"https://arbitrum.torn.cash/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId43114":{
|
||||
"rpcUrls":{
|
||||
"publicRpc":{
|
||||
"name":"Avalanche RPC",
|
||||
"url":"https://api.avax.network/ext/bc/C/rpc"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"avax.odanrot.eth":{
|
||||
"url":"avax.odanrot.eth",
|
||||
"name":"avax.odanrot.eth",
|
||||
"cachedUrl":"https://tcravalanche.avado.cloud/"
|
||||
},
|
||||
"avalanche.therelayer.eth":{
|
||||
"url":"avalanche.therelayer.eth",
|
||||
"name":"avalanche.therelayer.eth",
|
||||
"cachedUrl":"https://avalanche.therelayer.xyz/"
|
||||
},
|
||||
"avalanche.t-relay.eth":{
|
||||
"url":"avalanche.t-relay.eth",
|
||||
"name":"avalanche.t-relay.eth",
|
||||
"cachedUrl":"https://avalanche.t-relay.online/"
|
||||
},
|
||||
"avalanche.relaymy.eth":{
|
||||
"url":"avalanche.relaymy.eth",
|
||||
"name":"avalanche.relaymy.eth",
|
||||
"cachedUrl":"https://avalanche.relaymy.xyz/"
|
||||
},
|
||||
"avalanche.tornadosolutions.eth":{
|
||||
"url":"avalanche.tornadosolutions.eth",
|
||||
"name":"avalanche.tornadosolutions.eth",
|
||||
"cachedUrl":"https://avalanche.tornado.solutions/"
|
||||
},
|
||||
"avalanche.gaasservices.eth":{
|
||||
"url":"avalanche.gaasservices.eth",
|
||||
"name":"avalanche.gaasservices.eth",
|
||||
"cachedUrl":"https://avalanche.gaas.services/"
|
||||
},
|
||||
"avax.releth.eth":{
|
||||
"url":"avax.releth.eth",
|
||||
"name":"avax.releth.eth",
|
||||
"cachedUrl":"https://avax.reloch.net/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netId5":{
|
||||
"rpcUrls":{
|
||||
"Infura":{
|
||||
"name":"Infura",
|
||||
"url":"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"
|
||||
},
|
||||
"Mudit":{
|
||||
"name":"Mudit",
|
||||
"url":"https://rpc.goerli.mudit.blog"
|
||||
},
|
||||
"Slockit":{
|
||||
"name":"Slockit",
|
||||
"url":"https://rpc.slock.it/goerli"
|
||||
},
|
||||
"Prylabs":{
|
||||
"name":"Prylabs",
|
||||
"url":"https://goerli.prylabs.net"
|
||||
},
|
||||
"MyEtherWallet":{
|
||||
"name":"MyEtherWallet",
|
||||
"url":"https://nodes.mewapi.io/ws/goerli"
|
||||
}
|
||||
},
|
||||
"relayers":{
|
||||
"goerli-v2.poanet.eth":{
|
||||
"url":"goerli-v2.poanet.eth",
|
||||
"name":"goerli-v2.poanet.eth",
|
||||
"cachedUrl":"https://tornado-goerli-v2.poa.network/"
|
||||
},
|
||||
"goerli.v2.odanrot.eth":{
|
||||
"url":"goerli.v2.odanrot.eth",
|
||||
"name":"goerli.v2.odanrot.eth",
|
||||
"cachedUrl":"https://tcrv2goerli.avado.cloud/"
|
||||
},
|
||||
"goerli-v2.releth.eth":{
|
||||
"url":"goerli-v2.releth.eth",
|
||||
"name":"goerli-v2.releth.eth",
|
||||
"cachedUrl":"https://goerli-v2.reloch.net/"
|
||||
},
|
||||
"goerli-v2.relaymy.eth":{
|
||||
"url":"goerli-v2.relaymy.eth",
|
||||
"name":"goerli-v2.relaymy.eth",
|
||||
"cachedUrl":"https://goerli-v2.relaymy.xyz/"
|
||||
},
|
||||
"goerli-v2.gaasservices.eth":{
|
||||
"url":"goerli-v2.gaasservices.eth",
|
||||
"name":"goerli-v2.gaasservices.eth",
|
||||
"cachedUrl":"https://goerli-v2.gaas.services/"
|
||||
},
|
||||
"v2.goerli.thewizardseye.eth":{
|
||||
"url":"v2.goerli.thewizardseye.eth",
|
||||
"name":"v2.goerli.thewizardseye.eth",
|
||||
"cachedUrl":"https://digitalocean.v2.goerli.thewizardseye.de/"
|
||||
},
|
||||
"goerli-v2.reasoned.eth":{
|
||||
"url":"goerli-v2.reasoned.eth",
|
||||
"name":"goerli-v2.reasoned.eth",
|
||||
"cachedUrl":"https://goerli-v2.fairish.net/"
|
||||
},
|
||||
"goerli.t-relay.eth":{
|
||||
"url":"goerli.t-relay.eth",
|
||||
"name":"goerli.t-relay.eth",
|
||||
"cachedUrl":"https://goerli.t-relay.online/"
|
||||
},
|
||||
"goerli-v2.therelayer.eth":{
|
||||
"url":"goerli-v2.therelayer.eth",
|
||||
"name":"goerli-v2.therelayer.eth",
|
||||
"cachedUrl":"https://goerli-v2.therelayer.xyz/"
|
||||
},
|
||||
"goerli.relayer-service.eth":{
|
||||
"url":"goerli.relayer-service.eth",
|
||||
"name":"goerli.relayer-service.eth",
|
||||
"cachedUrl":"https://goerli-relayer.hertz.zone/"
|
||||
},
|
||||
"goerli-v2.tornadosolutions.eth":{
|
||||
"url":"goerli-v2.tornadosolutions.eth",
|
||||
"name":"goerli-v2.tornadosolutions.eth",
|
||||
"cachedUrl":"https://goerli-v2.tornado.solutions/"
|
||||
},
|
||||
"goerli-v2.torn.eth":{
|
||||
"url":"goerli-v2.torn.eth",
|
||||
"name":"goerli-v2.torn.eth",
|
||||
"cachedUrl":"https://goerli-v2.torn.cash/"
|
||||
},
|
||||
"goerli-v2.defidevotee.eth":{
|
||||
"url":"goerli-v2.defidevotee.eth",
|
||||
"name":"goerli-v2.defidevotee.eth",
|
||||
"cachedUrl":"https://goerli-v2.defidevotee.xyz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
80208
cache/binancesmartchain/deposits_bnb_0.1.json
vendored
Normal file
80208
cache/binancesmartchain/deposits_bnb_0.1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105590
cache/binancesmartchain/deposits_bnb_1.json
vendored
Normal file
105590
cache/binancesmartchain/deposits_bnb_1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
67461
cache/binancesmartchain/deposits_bnb_10.json
vendored
Normal file
67461
cache/binancesmartchain/deposits_bnb_10.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22941
cache/binancesmartchain/deposits_bnb_100.json
vendored
Normal file
22941
cache/binancesmartchain/deposits_bnb_100.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
72697
cache/binancesmartchain/withdrawals_bnb_0.1.json
vendored
Normal file
72697
cache/binancesmartchain/withdrawals_bnb_0.1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
100753
cache/binancesmartchain/withdrawals_bnb_1.json
vendored
Normal file
100753
cache/binancesmartchain/withdrawals_bnb_1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
65011
cache/binancesmartchain/withdrawals_bnb_10.json
vendored
Normal file
65011
cache/binancesmartchain/withdrawals_bnb_10.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
17852
cache/binancesmartchain/withdrawals_bnb_100.json
vendored
Normal file
17852
cache/binancesmartchain/withdrawals_bnb_100.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
515
cli.js
515
cli.js
@ -12,14 +12,16 @@ const circomlib = require('circomlib')
|
||||
const bigInt = snarkjs.bigInt
|
||||
const merkleTree = require('./lib/MerkleTree')
|
||||
const Web3 = require('web3')
|
||||
const Web3HttpProvider = require('web3-providers-http');
|
||||
const buildGroth16 = require('websnark/src/groth16')
|
||||
const websnarkUtils = require('websnark/src/utils')
|
||||
const { toWei, fromWei, toBN, BN } = require('web3-utils')
|
||||
const config = require('./config')
|
||||
const program = require('commander')
|
||||
const { GasPriceOracle } = require('gas-price-oracle')
|
||||
const SocksProxyAgent = require('socks-proxy-agent')
|
||||
|
||||
let web3, tornado, tornadoContract, tornadoInstance, circuit, proving_key, groth16, erc20, senderAccount, netId
|
||||
let web3, tornado, tornadoContract, tornadoInstance, circuit, proving_key, groth16, erc20, senderAccount, netId, netName, netSymbol
|
||||
let MERKLE_TREE_HEIGHT, ETH_AMOUNT, TOKEN_AMOUNT, PRIVATE_KEY
|
||||
|
||||
/** Whether we are in a browser or node.js */
|
||||
@ -39,15 +41,70 @@ function toHex(number, length = 32) {
|
||||
}
|
||||
|
||||
/** Display ETH account balance */
|
||||
async function printETHBalance({ address, name }) {
|
||||
console.log(`${name} ETH balance is`, web3.utils.fromWei(await web3.eth.getBalance(address)))
|
||||
async function printETHBalance({ address, name, symbol }) {
|
||||
console.log(`${name} balance is`, web3.utils.fromWei(await web3.eth.getBalance(address)),`${symbol}`)
|
||||
}
|
||||
|
||||
/** Display ERC20 account balance */
|
||||
async function printERC20Balance({ address, name, tokenAddress }) {
|
||||
const erc20ContractJson = require('./build/contracts/ERC20Mock.json')
|
||||
erc20 = tokenAddress ? new web3.eth.Contract(erc20ContractJson.abi, tokenAddress) : erc20
|
||||
console.log(`${name} Token Balance is`, web3.utils.fromWei(await erc20.methods.balanceOf(address).call()))
|
||||
balance = await erc20.methods.balanceOf(address).call()
|
||||
decimals = await erc20.methods.decimals().call()
|
||||
console.log(`${name}`,(await erc20.methods.name().call()),`Token Balance is`,toDecimals(balance, decimals, (balance.length + decimals)).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","),(await erc20.methods.symbol().call()))
|
||||
}
|
||||
|
||||
async function generateTransaction(to, encodedData, value = 0) {
|
||||
const nonce = await web3.eth.getTransactionCount(senderAccount)
|
||||
const gasPrice = await fetchGasPrice()
|
||||
let gasLimit;
|
||||
let tx = {}
|
||||
|
||||
async function estimateGas() {
|
||||
const fetchedGas = await web3.eth.estimateGas({
|
||||
from : senderAccount,
|
||||
to : to,
|
||||
value : value,
|
||||
nonce : nonce,
|
||||
data : encodedData
|
||||
})
|
||||
const bumped = Math.floor(fetchedGas * 1.3)
|
||||
gasLimit = web3.utils.toHex(bumped)
|
||||
}
|
||||
await estimateGas();
|
||||
|
||||
async function txoptions() {
|
||||
// Generate EIP-1559 transaction
|
||||
if (netId == 1 || netId == 5) {
|
||||
tx = {
|
||||
to : to,
|
||||
value : value,
|
||||
nonce : nonce,
|
||||
maxFeePerGas : gasPrice,
|
||||
maxPriorityFeePerGas : web3.utils.toHex(web3.utils.toWei('3', 'gwei')),
|
||||
gas : gasLimit,
|
||||
data : encodedData
|
||||
}
|
||||
} else {
|
||||
tx = {
|
||||
to : to,
|
||||
value : value,
|
||||
nonce : nonce,
|
||||
gasPrice : gasPrice,
|
||||
gas : gasLimit,
|
||||
data : encodedData
|
||||
}
|
||||
}
|
||||
}
|
||||
await txoptions();
|
||||
const signed = await web3.eth.accounts.signTransaction(tx, PRIVATE_KEY);
|
||||
await web3.eth.sendSignedTransaction(signed.rawTransaction)
|
||||
.on('transactionHash', function (txHash) {
|
||||
console.log(`View transaction on block explorer https://${getExplorerLink()}/tx/${txHash}`)
|
||||
})
|
||||
.on('error', function (e) {
|
||||
console.error('on transactionHash error', e.message)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,12 +120,22 @@ function createDeposit({ nullifier, secret }) {
|
||||
return deposit
|
||||
}
|
||||
|
||||
async function backupNote({ currency, amount, netId, note, noteString }) {
|
||||
try {
|
||||
await fs.writeFileSync(`./backup-tornado-${currency}-${amount}-${netId}-${note.slice(0, 10)}.txt`, noteString, 'utf8');
|
||||
console.log("Backed up deposit note as",`./backup-tornado-${currency}-${amount}-${netId}-${note.slice(0, 10)}.txt`)
|
||||
} catch (e) {
|
||||
throw new Error('Writing backup note failed:',e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a deposit
|
||||
* @param currency Сurrency
|
||||
* @param amount Deposit amount
|
||||
*/
|
||||
async function deposit({ currency, amount }) {
|
||||
assert(senderAccount != null, 'Error! PRIVATE_KEY not found. Please provide PRIVATE_KEY in .env file if you deposit')
|
||||
const deposit = createDeposit({
|
||||
nullifier: rbigint(31),
|
||||
secret: rbigint(31)
|
||||
@ -76,35 +143,36 @@ async function deposit({ currency, amount }) {
|
||||
const note = toHex(deposit.preimage, 62)
|
||||
const noteString = `tornado-${currency}-${amount}-${netId}-${note}`
|
||||
console.log(`Your note: ${noteString}`)
|
||||
if (currency === 'eth') {
|
||||
await printETHBalance({ address: tornado._address, name: 'Tornado' })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account' })
|
||||
await backupNote({ currency, amount, netId, note, noteString })
|
||||
if (currency === 'eth' || currency === 'bnb' || currency === 'xdai' || currency === 'matic' || currency === 'avax') {
|
||||
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract', symbol: currency.toUpperCase() })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account', symbol: currency.toUpperCase() })
|
||||
const value = isLocalRPC ? ETH_AMOUNT : fromDecimals({ amount, decimals: 18 })
|
||||
console.log('Submitting deposit transaction')
|
||||
await tornado.methods.deposit(tornadoInstance, toHex(deposit.commitment), []).send({ value, from: senderAccount, gas: 2e6 })
|
||||
await printETHBalance({ address: tornado._address, name: 'Tornado' })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account' })
|
||||
await generateTransaction(contractAddress, await tornado.methods.deposit(tornadoInstance, toHex(deposit.commitment), []).encodeABI(), value)
|
||||
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract', symbol: currency.toUpperCase() })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account', symbol: currency.toUpperCase() })
|
||||
} else {
|
||||
// a token
|
||||
await printERC20Balance({ address: tornado._address, name: 'Tornado' })
|
||||
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printERC20Balance({ address: senderAccount, name: 'Sender account' })
|
||||
const decimals = isLocalRPC ? 18 : config.deployments[`netId${netId}`][currency].decimals
|
||||
const tokenAmount = isLocalRPC ? TOKEN_AMOUNT : fromDecimals({ amount, decimals })
|
||||
if (isLocalRPC) {
|
||||
console.log('Minting some test tokens to deposit')
|
||||
await erc20.methods.mint(senderAccount, tokenAmount).send({ from: senderAccount, gas: 2e6 })
|
||||
await generateTransaction(erc20Address, await erc20.methods.mint(senderAccount, tokenAmount).encodeABI())
|
||||
}
|
||||
|
||||
const allowance = await erc20.methods.allowance(senderAccount, tornado._address).call({ from: senderAccount })
|
||||
console.log('Current allowance is', fromWei(allowance))
|
||||
if (toBN(allowance).lt(toBN(tokenAmount))) {
|
||||
console.log('Approving tokens for deposit')
|
||||
await erc20.methods.approve(tornado._address, tokenAmount).send({ from: senderAccount, gas: 1e6 })
|
||||
await generateTransaction(erc20Address, await erc20.methods.approve(tornado._address, tokenAmount).encodeABI())
|
||||
}
|
||||
|
||||
console.log('Submitting deposit transaction')
|
||||
await tornado.methods.deposit(toHex(deposit.commitment)).send({ from: senderAccount, gas: 2e6 })
|
||||
await printERC20Balance({ address: tornado._address, name: 'Tornado' })
|
||||
await generateTransaction(contractAddress, await tornado.methods.deposit(toHex(deposit.commitment)).encodeABI())
|
||||
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printERC20Balance({ address: senderAccount, name: 'Sender account' })
|
||||
}
|
||||
|
||||
@ -117,34 +185,13 @@ async function deposit({ currency, amount }) {
|
||||
* in it and generates merkle proof
|
||||
* @param deposit Deposit object
|
||||
*/
|
||||
async function generateMerkleProof(deposit, amount) {
|
||||
async function generateMerkleProof(deposit, currency, amount) {
|
||||
let leafIndex = -1
|
||||
// Get all deposit events from smart contract and assemble merkle tree from them
|
||||
|
||||
const cachedEvents = loadCachedEvents({ type: 'Deposit', amount })
|
||||
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount })
|
||||
|
||||
const startBlock = cachedEvents.lastBlock
|
||||
|
||||
let rpcEvents = await tornadoContract.getPastEvents('Deposit', {
|
||||
fromBlock: startBlock,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
rpcEvents = rpcEvents.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { commitment, leafIndex, timestamp } = returnValues
|
||||
return {
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
commitment,
|
||||
leafIndex: Number(leafIndex),
|
||||
timestamp
|
||||
}
|
||||
})
|
||||
|
||||
const events = cachedEvents.events.concat(rpcEvents)
|
||||
console.log('events', events.length)
|
||||
|
||||
const leaves = events
|
||||
const leaves = cachedEvents
|
||||
.sort((a, b) => a.leafIndex - b.leafIndex) // Sort events in chronological order
|
||||
.map((e) => {
|
||||
const index = toBN(e.leafIndex).toNumber()
|
||||
@ -176,9 +223,9 @@ async function generateMerkleProof(deposit, amount) {
|
||||
* @param fee Relayer fee
|
||||
* @param refund Receive ether for exchanged tokens
|
||||
*/
|
||||
async function generateProof({ deposit, amount, recipient, relayerAddress = 0, fee = 0, refund = 0 }) {
|
||||
async function generateProof({ deposit, currency, amount, recipient, relayerAddress = 0, fee = 0, refund = 0 }) {
|
||||
// Compute merkle proof of our commitment
|
||||
const { root, path_elements, path_index } = await generateMerkleProof(deposit, amount)
|
||||
const { root, path_elements, path_index } = await generateMerkleProof(deposit, currency, amount)
|
||||
|
||||
// Prepare circuit input
|
||||
const input = {
|
||||
@ -220,7 +267,8 @@ async function generateProof({ deposit, amount, recipient, relayerAddress = 0, f
|
||||
* @param noteString Note to withdraw
|
||||
* @param recipient Recipient address
|
||||
*/
|
||||
async function withdraw({ deposit, currency, amount, recipient, relayerURL, refund = '0' }) {
|
||||
async function withdraw({ deposit, currency, amount, recipient, relayerURL, torPort, refund = '0' }) {
|
||||
let options = {};
|
||||
if (currency === 'eth' && refund !== '0') {
|
||||
throw new Error('The ETH purchase is supposted to be 0 for ETH withdrawals')
|
||||
}
|
||||
@ -229,11 +277,14 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
||||
if (relayerURL.endsWith('.eth')) {
|
||||
throw new Error('ENS name resolving is not supported. Please provide DNS name of the relayer. See instuctions in README.md')
|
||||
}
|
||||
const relayerStatus = await axios.get(relayerURL + '/status')
|
||||
if (torPort) {
|
||||
options = { httpsAgent: new SocksProxyAgent('socks5h://127.0.0.1:'+torPort), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' } }
|
||||
}
|
||||
const relayerStatus = await axios.get(relayerURL + '/status', options)
|
||||
|
||||
const { rewardAccount, netId, ethPrices, tornadoServiceFee } = relayerStatus.data
|
||||
assert(netId === (await web3.eth.net.getId()) || netId === '*', 'This relay is for different network')
|
||||
console.log('Relay address: ', rewardAccount)
|
||||
console.log('Relay address:', rewardAccount)
|
||||
|
||||
const gasPrice = await fetchGasPrice()
|
||||
|
||||
@ -251,7 +302,7 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
||||
throw new Error('Too high refund')
|
||||
}
|
||||
|
||||
const { proof, args } = await generateProof({ deposit, amount, recipient, relayerAddress: rewardAccount, fee, refund })
|
||||
const { proof, args } = await generateProof({ deposit, currency, amount, recipient, relayerAddress: rewardAccount, fee, refund })
|
||||
|
||||
console.log('Sending withdraw transaction through relay')
|
||||
try {
|
||||
@ -259,11 +310,11 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
||||
contract: tornadoInstance,
|
||||
proof,
|
||||
args
|
||||
})
|
||||
}, options)
|
||||
|
||||
const { id } = response.data
|
||||
|
||||
const result = await getStatus(id, relayerURL)
|
||||
const result = await getStatus(id, relayerURL, options)
|
||||
console.log('STATUS', result)
|
||||
} catch (e) {
|
||||
if (e.response) {
|
||||
@ -274,30 +325,23 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
||||
}
|
||||
} else {
|
||||
// using private key
|
||||
const { proof, args } = await generateProof({ deposit, recipient, refund })
|
||||
|
||||
// check if the address of recepient matches with the account of provided private key from environment to prevent accidental use of deposit address for withdrawal transaction.
|
||||
const { address } = await web3.eth.accounts.privateKeyToAccount('0x' + PRIVATE_KEY)
|
||||
assert(recipient.toLowerCase() == address.toLowerCase(), 'Withdrawal amount recepient',recipient,'mismatches with the account of provided private key from environment file',address)
|
||||
|
||||
const { proof, args } = await generateProof({ deposit, currency, amount, recipient, refund })
|
||||
|
||||
console.log('Submitting withdraw transaction')
|
||||
await tornado.methods
|
||||
.withdraw(tornadoInstance, proof, ...args)
|
||||
.send({ from: senderAccount, value: refund.toString(), gas: 1e6 })
|
||||
.on('transactionHash', function (txHash) {
|
||||
if (netId === 1 || netId === 42) {
|
||||
console.log(`View transaction on etherscan https://${getCurrentNetworkName()}etherscan.io/tx/${txHash}`)
|
||||
} else {
|
||||
console.log(`The transaction hash is ${txHash}`)
|
||||
}
|
||||
})
|
||||
.on('error', function (e) {
|
||||
console.error('on transactionHash error', e.message)
|
||||
})
|
||||
await generateTransaction(contractAddress, await tornado.methods.withdraw(tornadoInstance, proof, ...args).encodeABI())
|
||||
}
|
||||
console.log('Done')
|
||||
console.log('Done withdrawal from Tornado Cash')
|
||||
}
|
||||
|
||||
function getStatus(id, relayerURL) {
|
||||
function getStatus(id, relayerURL, options) {
|
||||
return new Promise((resolve) => {
|
||||
async function getRelayerStatus() {
|
||||
const responseStatus = await axios.get(relayerURL + '/v1/jobs/' + id)
|
||||
const responseStatus = await axios.get(relayerURL + '/v1/jobs/' + id, options)
|
||||
|
||||
if (responseStatus.status === 200) {
|
||||
const { txHash, status, confirmations, failedReason } = responseStatus.data
|
||||
@ -311,7 +355,7 @@ function getStatus(id, relayerURL) {
|
||||
if (status === 'CONFIRMED') {
|
||||
const receipt = await waitForTxReceipt({ txHash })
|
||||
console.log(
|
||||
`Transaction submitted through the relay. View transaction on etherscan https://${getCurrentNetworkName()}etherscan.io/tx/${txHash}`
|
||||
`Transaction submitted through the relay. View transaction on block explorer https://${getExplorerLink()}/tx/${txHash}`
|
||||
)
|
||||
console.log('Transaction mined in block', receipt.blockNumber)
|
||||
resolve(status)
|
||||
@ -327,6 +371,10 @@ function getStatus(id, relayerURL) {
|
||||
})
|
||||
}
|
||||
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
function fromDecimals({ amount, decimals }) {
|
||||
amount = amount.toString()
|
||||
let ether = amount.toString()
|
||||
@ -411,30 +459,95 @@ function toDecimals(value, decimals, fixed) {
|
||||
return value
|
||||
}
|
||||
|
||||
function getCurrentNetworkName() {
|
||||
// List fetched from https://github.com/ethereum-lists/chains/blob/master/_data/chains
|
||||
function getExplorerLink() {
|
||||
switch (netId) {
|
||||
case 1:
|
||||
return ''
|
||||
case 56:
|
||||
return 'bscscan.com'
|
||||
case 100:
|
||||
return 'blockscout.com/poa/xdai'
|
||||
case 137:
|
||||
return 'polygonscan.com'
|
||||
case 42161:
|
||||
return 'arbiscan.io'
|
||||
case 43114:
|
||||
return 'snowtrace.io'
|
||||
case 5:
|
||||
return 'goerli.'
|
||||
return 'goerli.etherscan.io'
|
||||
case 42:
|
||||
return 'kovan.'
|
||||
return 'kovan.etherscan.io'
|
||||
default:
|
||||
return 'etherscan.io'
|
||||
}
|
||||
}
|
||||
|
||||
function gasPrices(value = 80) {
|
||||
// List fetched from https://github.com/trustwallet/assets/tree/master/blockchains
|
||||
function getCurrentNetworkName() {
|
||||
switch (netId) {
|
||||
case 1:
|
||||
return 'Ethereum'
|
||||
case 56:
|
||||
return 'BinanceSmartChain'
|
||||
case 100:
|
||||
return 'xDai'
|
||||
case 137:
|
||||
return 'Polygon'
|
||||
case 42161:
|
||||
return 'Arbitrum'
|
||||
case 43114:
|
||||
return 'Avalanche'
|
||||
case 5:
|
||||
return 'Goerli'
|
||||
case 42:
|
||||
return 'Kovan'
|
||||
default:
|
||||
return 'localRPC'
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentNetworkSymbol() {
|
||||
switch (netId) {
|
||||
case 56:
|
||||
return 'BNB'
|
||||
case 100:
|
||||
return 'xDAI'
|
||||
case 137:
|
||||
return 'MATIC'
|
||||
case 43114:
|
||||
return 'AVAX'
|
||||
default:
|
||||
return 'ETH'
|
||||
}
|
||||
}
|
||||
|
||||
function gasPricesETH(value = 80) {
|
||||
const tenPercent = (Number(value) * 5) / 100
|
||||
const max = Math.max(tenPercent, 3)
|
||||
const bumped = Math.floor(Number(value) + max)
|
||||
return toHex(toWei(bumped.toString(), 'gwei'))
|
||||
}
|
||||
|
||||
function gasPrices(value = 5) {
|
||||
return toHex(toWei(value.toString(), 'gwei'))
|
||||
}
|
||||
|
||||
async function fetchGasPrice() {
|
||||
try {
|
||||
const oracle = new GasPriceOracle()
|
||||
const gas = await oracle.gasPrices()
|
||||
|
||||
return gasPrices(gas.fast)
|
||||
const options = {
|
||||
chainId: netId
|
||||
}
|
||||
// Bump fees for Ethereum network
|
||||
if (netId == 1) {
|
||||
const oracle = new GasPriceOracle(options)
|
||||
const gas = await oracle.gasPrices()
|
||||
return gasPricesETH(gas.instant)
|
||||
} else if (netId == 5 || isLocalRPC) {
|
||||
return gasPrices(1)
|
||||
} else {
|
||||
const oracle = new GasPriceOracle(options)
|
||||
const gas = await oracle.gasPrices()
|
||||
return gasPrices(gas.instant)
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Method fetchGasPrice has error ${err.message}`)
|
||||
}
|
||||
@ -453,6 +566,22 @@ function calculateFee({ currency, gasPrice, amount, refund, ethPrices, relayerSe
|
||||
desiredFee = expense.add(feePercent)
|
||||
break
|
||||
}
|
||||
case 'bnb': {
|
||||
desiredFee = expense.add(feePercent)
|
||||
break
|
||||
}
|
||||
case 'xdai': {
|
||||
desiredFee = expense.add(feePercent)
|
||||
break
|
||||
}
|
||||
case 'matic': {
|
||||
desiredFee = expense.add(feePercent)
|
||||
break
|
||||
}
|
||||
case 'avax': {
|
||||
desiredFee = expense.add(feePercent)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
desiredFee = expense
|
||||
.add(toBN(refund))
|
||||
@ -489,16 +618,9 @@ function waitForTxReceipt({ txHash, attempts = 60, delay = 1000 }) {
|
||||
})
|
||||
}
|
||||
|
||||
function loadCachedEvents({ type, amount }) {
|
||||
function loadCachedEvents({ type, currency, amount }) {
|
||||
try {
|
||||
if (netId !== 1) {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const module = require(`./cache/${type.toLowerCase()}s_eth_${amount}.json`)
|
||||
const module = require(`./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`)
|
||||
|
||||
if (module) {
|
||||
const events = module
|
||||
@ -509,10 +631,99 @@ function loadCachedEvents({ type, amount }) {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Method loadCachedEvents has error: ${err.message}`)
|
||||
console.log("Error fetching cached files, syncing from block",deployedBlockNumber)
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: deployedBlockNumber,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchEvents({ type, currency, amount}) {
|
||||
let leafIndex = -1
|
||||
let events = [];
|
||||
let fetchedEvents, chunks, targetBlock;
|
||||
|
||||
if (type === "withdraw") {
|
||||
type = "withdrawal"
|
||||
}
|
||||
|
||||
const cachedEvents = loadCachedEvents({ type, currency, amount })
|
||||
const startBlock = cachedEvents.lastBlock + 1
|
||||
|
||||
console.log("Fetching",amount,currency.toUpperCase(),type,"events for",netName,"network")
|
||||
|
||||
async function fetchLatestEvents() {
|
||||
targetBlock = await web3.eth.getBlockNumber();
|
||||
chunks = 1000;
|
||||
fetchedEvents = [];
|
||||
for (let i=startBlock; i < targetBlock; i+=chunks) {
|
||||
await tornadoContract.getPastEvents(capitalizeFirstLetter(type), {
|
||||
fromBlock: i,
|
||||
toBlock: i+chunks-1,
|
||||
}).then(r => { fetchedEvents = fetchedEvents.concat(r); console.log("Fetched",amount,currency.toUpperCase(),type,"events from block:", i) }, err => { console.error(i + " failed fetching",type,"events from node", err) }).catch(console.log);
|
||||
}
|
||||
}
|
||||
await fetchLatestEvents()
|
||||
|
||||
async function mapDepositEvents() {
|
||||
fetchedEvents = fetchedEvents.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { commitment, leafIndex, timestamp } = returnValues
|
||||
return {
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
commitment,
|
||||
leafIndex: Number(leafIndex),
|
||||
timestamp
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function mapWithdrawEvents() {
|
||||
fetchedEvents = fetchedEvents.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { nullifierHash, to, fee } = returnValues
|
||||
return {
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
nullifierHash,
|
||||
to,
|
||||
fee
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function mapLatestEvents() {
|
||||
console.log("Mapping",amount,currency.toUpperCase(),type,"events, please wait")
|
||||
if (type === "deposit"){
|
||||
await mapDepositEvents();
|
||||
} else {
|
||||
await mapWithdrawEvents();
|
||||
}
|
||||
}
|
||||
await mapLatestEvents();
|
||||
|
||||
console.log("Gathering cached events + collected events from node")
|
||||
|
||||
async function concatEvents() {
|
||||
events = cachedEvents.events.concat(fetchedEvents)
|
||||
}
|
||||
await concatEvents();
|
||||
|
||||
console.log('Total events:', events.length)
|
||||
|
||||
async function updateCache() {
|
||||
try {
|
||||
await fs.writeFileSync(`./cache/${netName.toLowerCase()}/${type}s_${currency}_${amount}.json`, JSON.stringify(events, null, 2), 'utf8')
|
||||
console.log("Cache updated for Tornado",type,amount,currency,"instance successfully")
|
||||
} catch (e) {
|
||||
throw new Error('Writing cache file failed:',e)
|
||||
}
|
||||
}
|
||||
await updateCache();
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Tornado.cash note
|
||||
* @param noteString the note
|
||||
@ -538,21 +749,19 @@ function parseNote(noteString) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDepositData({ deposit }) {
|
||||
async function loadDepositData({ amount, currency, deposit }) {
|
||||
try {
|
||||
const eventWhenHappened = await tornadoContract.getPastEvents('Deposit', {
|
||||
filter: {
|
||||
commitment: deposit.commitmentHex
|
||||
},
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount })
|
||||
const eventWhenHappened = await cachedEvents.filter(function (event) {
|
||||
return event.commitment === deposit.commitmentHex;
|
||||
})[0]
|
||||
|
||||
if (eventWhenHappened.length === 0) {
|
||||
throw new Error('There is no related deposit, the note is invalid')
|
||||
}
|
||||
|
||||
const { timestamp } = eventWhenHappened[0].returnValues
|
||||
const txHash = eventWhenHappened[0].transactionHash
|
||||
const timestamp = eventWhenHappened.timestamp
|
||||
const txHash = eventWhenHappened.transactionHash
|
||||
const isSpent = await tornadoContract.methods.isSpent(deposit.nullifierHex).call()
|
||||
const receipt = await web3.eth.getTransactionReceipt(txHash)
|
||||
|
||||
@ -570,29 +779,9 @@ async function loadDepositData({ deposit }) {
|
||||
}
|
||||
async function loadWithdrawalData({ amount, currency, deposit }) {
|
||||
try {
|
||||
const cachedEvents = loadCachedEvents({ type: 'Withdrawal', amount })
|
||||
const cachedEvents = await fetchEvents({ type: 'withdrawal', currency, amount })
|
||||
|
||||
const startBlock = cachedEvents.lastBlock
|
||||
|
||||
let rpcEvents = await tornadoContract.getPastEvents('Withdrawal', {
|
||||
fromBlock: startBlock,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
|
||||
rpcEvents = rpcEvents.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { nullifierHash, to, fee } = returnValues
|
||||
return {
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
nullifierHash,
|
||||
to,
|
||||
fee
|
||||
}
|
||||
})
|
||||
|
||||
const events = cachedEvents.events.concat(rpcEvents)
|
||||
|
||||
const withdrawEvent = events.filter((event) => {
|
||||
const withdrawEvent = cachedEvents.filter((event) => {
|
||||
return event.nullifierHash === deposit.nullifierHex
|
||||
})[0]
|
||||
|
||||
@ -616,7 +805,7 @@ async function loadWithdrawalData({ amount, currency, deposit }) {
|
||||
/**
|
||||
* Init web3, contracts, and snark
|
||||
*/
|
||||
async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
||||
async function init({ rpc, noteNetId, currency = 'dai', amount = '100', torPort, balanceCheck }) {
|
||||
let contractJson, instanceJson, erc20ContractJson, erc20tornadoJson, tornadoAddress, tokenAddress
|
||||
// TODO do we need this? should it work in browser really?
|
||||
if (inBrowser) {
|
||||
@ -634,8 +823,22 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
||||
TOKEN_AMOUNT = 1e19
|
||||
senderAccount = (await web3.eth.getAccounts())[0]
|
||||
} else {
|
||||
// Initialize from local node
|
||||
web3 = new Web3(rpc, null, { transactionConfirmationBlocks: 1 })
|
||||
if (torPort) {
|
||||
console.log("Using tor network")
|
||||
web3Options = { agent: { https: new SocksProxyAgent('socks5h://127.0.0.1:'+torPort) }, timeout: 60000 }
|
||||
// Use forked web3-providers-http from local file to modify user-agent header value which improves privacy.
|
||||
web3 = new Web3(new Web3HttpProvider(rpc, web3Options), null, { transactionConfirmationBlocks: 1 })
|
||||
} else if (rpc.includes("ipc")) {
|
||||
console.log("Using ipc connection")
|
||||
web3 = new Web3(new Web3.providers.IpcProvider(rpc, net), null, { transactionConfirmationBlocks: 1 })
|
||||
} else if (rpc.includes("ws") || rpc.includes("wss")) {
|
||||
console.log("Using websocket connection (Note: Tor is not supported for Websocket providers)")
|
||||
web3Options = { clientConfig: { keepalive: true, keepaliveInterval: -1 }, reconnect: { auto: true, delay: 1000, maxAttempts: 10, onTimeout: false } }
|
||||
web3 = new Web3(new Web3.providers.WebsocketProvider(rpc, web3Options), net, { transactionConfirmationBlocks: 1 })
|
||||
} else {
|
||||
console.log("Connecting to remote node")
|
||||
web3 = new Web3(rpc, null, { transactionConfirmationBlocks: 1 })
|
||||
}
|
||||
contractJson = require('./build/contracts/TornadoProxy.abi.json')
|
||||
instanceJson = require('./build/contracts/Instance.abi.json')
|
||||
circuit = require('./build/circuits/tornado.json')
|
||||
@ -649,8 +852,6 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
||||
web3.eth.accounts.wallet.add('0x' + PRIVATE_KEY)
|
||||
web3.eth.defaultAccount = account.address
|
||||
senderAccount = account.address
|
||||
} else {
|
||||
console.log('Warning! PRIVATE_KEY not found. Please provide PRIVATE_KEY in .env file if you deposit')
|
||||
}
|
||||
erc20ContractJson = require('./build/contracts/ERC20Mock.json')
|
||||
erc20tornadoJson = require('./build/contracts/ERC20Tornado.json')
|
||||
@ -658,32 +859,45 @@ async function init({ rpc, noteNetId, currency = 'dai', amount = '100' }) {
|
||||
// groth16 initialises a lot of Promises that will never be resolved, that's why we need to use process.exit to terminate the CLI
|
||||
groth16 = await buildGroth16()
|
||||
netId = await web3.eth.net.getId()
|
||||
netName = getCurrentNetworkName()
|
||||
if (noteNetId && Number(noteNetId) !== netId) {
|
||||
throw new Error('This note is for a different network. Specify the --rpc option explicitly')
|
||||
}
|
||||
isLocalRPC = netId > 42
|
||||
if (netName === "localRPC") {
|
||||
isLocalRPC = true;
|
||||
}
|
||||
|
||||
if (isLocalRPC) {
|
||||
tornadoAddress = currency === 'eth' ? contractJson.networks[netId].address : erc20tornadoJson.networks[netId].address
|
||||
tokenAddress = currency !== 'eth' ? erc20ContractJson.networks[netId].address : null
|
||||
netSymbol = getCurrentNetworkSymbol()
|
||||
deployedBlockNumber = 0
|
||||
senderAccount = (await web3.eth.getAccounts())[0]
|
||||
} else {
|
||||
try {
|
||||
if (balanceCheck) {
|
||||
netSymbol = getCurrentNetworkSymbol()
|
||||
currency = netSymbol.toLowerCase()
|
||||
amount = Object.keys(config.deployments[`netId${netId}`][currency].instanceAddress)[0]
|
||||
}
|
||||
tornadoAddress = config.deployments[`netId${netId}`].proxy
|
||||
tornadoInstance = config.deployments[`netId${netId}`][currency].instanceAddress[amount]
|
||||
deployedBlockNumber = config.deployments[`netId${netId}`][currency].deployedBlockNumber[amount]
|
||||
|
||||
if (!tornadoAddress) {
|
||||
throw new Error()
|
||||
}
|
||||
tokenAddress = config.deployments[`netId${netId}`][currency].tokenAddress
|
||||
} catch (e) {
|
||||
console.error('There is no such tornado instance, check the currency and amount you provide')
|
||||
console.error('There is no such tornado instance, check the currency and amount you provide', e)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
tornado = new web3.eth.Contract(contractJson, tornadoAddress)
|
||||
tornadoContract = new web3.eth.Contract(instanceJson, tornadoInstance)
|
||||
contractAddress = tornadoAddress
|
||||
erc20 = currency !== 'eth' ? new web3.eth.Contract(erc20ContractJson.abi, tokenAddress) : {}
|
||||
erc20Address = tokenAddress
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@ -703,8 +917,9 @@ async function main() {
|
||||
}
|
||||
} else {
|
||||
program
|
||||
.option('-r, --rpc <URL>', 'The RPC, CLI should interact with', 'http://localhost:8545')
|
||||
.option('-r, --rpc <URL>', 'The RPC that CLI should interact with', 'http://localhost:8545')
|
||||
.option('-R, --relayer <URL>', 'Withdraw via relayer')
|
||||
.option('-T, --tor <PORT>', 'Optional tor port')
|
||||
program
|
||||
.command('deposit <currency> <amount>')
|
||||
.description(
|
||||
@ -712,7 +927,7 @@ async function main() {
|
||||
)
|
||||
.action(async (currency, amount) => {
|
||||
currency = currency.toLowerCase()
|
||||
await init({ rpc: program.rpc, currency, amount })
|
||||
await init({ rpc: program.rpc, currency, amount, torPort: program.tor })
|
||||
await deposit({ currency, amount })
|
||||
})
|
||||
program
|
||||
@ -722,24 +937,25 @@ async function main() {
|
||||
)
|
||||
.action(async (noteString, recipient, refund) => {
|
||||
const { currency, amount, netId, deposit } = parseNote(noteString)
|
||||
await init({ rpc: program.rpc, noteNetId: netId, currency, amount })
|
||||
await init({ rpc: program.rpc, noteNetId: netId, currency, amount, torPort: program.tor })
|
||||
await withdraw({
|
||||
deposit,
|
||||
currency,
|
||||
amount,
|
||||
recipient,
|
||||
refund,
|
||||
relayerURL: program.relayer
|
||||
relayerURL: program.relayer,
|
||||
torPort: program.tor
|
||||
})
|
||||
})
|
||||
program
|
||||
.command('balance <address> [token_address]')
|
||||
.description('Check ETH and ERC20 balance')
|
||||
.action(async (address, tokenAddress) => {
|
||||
await init({ rpc: program.rpc })
|
||||
await printETHBalance({ address, name: '' })
|
||||
await init({ rpc: program.rpc, torPort: program.tor, balanceCheck: true })
|
||||
await printETHBalance({ address, name: 'Account', symbol: netSymbol })
|
||||
if (tokenAddress) {
|
||||
await printERC20Balance({ address, name: '', tokenAddress })
|
||||
await printERC20Balance({ address, name: 'Account', tokenAddress })
|
||||
}
|
||||
})
|
||||
program
|
||||
@ -749,33 +965,44 @@ async function main() {
|
||||
)
|
||||
.action(async (noteString) => {
|
||||
const { currency, amount, netId, deposit } = parseNote(noteString)
|
||||
await init({ rpc: program.rpc, noteNetId: netId, currency, amount })
|
||||
const depositInfo = await loadDepositData({ deposit })
|
||||
await init({ rpc: program.rpc, noteNetId: netId, currency, amount, torPort: program.tor })
|
||||
const depositInfo = await loadDepositData({ amount, currency, deposit })
|
||||
const depositDate = new Date(depositInfo.timestamp * 1000)
|
||||
console.log('\n=============Deposit=================')
|
||||
console.log('Deposit :', amount, currency)
|
||||
console.log('Deposit :', amount, currency.toUpperCase())
|
||||
console.log('Date :', depositDate.toLocaleDateString(), depositDate.toLocaleTimeString())
|
||||
console.log('From :', `https://${getCurrentNetworkName()}etherscan.io/address/${depositInfo.from}`)
|
||||
console.log('Transaction :', `https://${getCurrentNetworkName()}etherscan.io/tx/${depositInfo.txHash}`)
|
||||
console.log('From :', `https://${getExplorerLink()}/address/${depositInfo.from}`)
|
||||
console.log('Transaction :', `https://${getExplorerLink()}/tx/${depositInfo.txHash}`)
|
||||
console.log('Commitment :', depositInfo.commitment)
|
||||
if (!deposit.isSpent) {
|
||||
console.log('Spent :', depositInfo.isSpent)
|
||||
if (!depositInfo.isSpent) {
|
||||
console.log('The note was not spent')
|
||||
return
|
||||
}
|
||||
console.log('=====================================','\n')
|
||||
|
||||
const withdrawInfo = await loadWithdrawalData({
|
||||
amount,
|
||||
currency,
|
||||
deposit
|
||||
})
|
||||
const withdrawInfo = await loadWithdrawalData({ amount, currency, deposit })
|
||||
const withdrawalDate = new Date(withdrawInfo.timestamp * 1000)
|
||||
console.log('\n=============Withdrawal==============')
|
||||
console.log('Withdrawal :', withdrawInfo.amount, currency)
|
||||
console.log('Relayer Fee :', withdrawInfo.fee, currency)
|
||||
console.log('Date :', withdrawalDate.toLocaleDateString(), withdrawalDate.toLocaleTimeString())
|
||||
console.log('To :', `https://${getCurrentNetworkName()}etherscan.io/address/${withdrawInfo.to}`)
|
||||
console.log('Transaction :', `https://${getCurrentNetworkName()}etherscan.io/tx/${withdrawInfo.txHash}`)
|
||||
console.log('To :', `https://${getExplorerLink()}/address/${withdrawInfo.to}`)
|
||||
console.log('Transaction :', `https://${getExplorerLink()}/tx/${withdrawInfo.txHash}`)
|
||||
console.log('Nullifier :', withdrawInfo.nullifier)
|
||||
console.log('=====================================','\n')
|
||||
})
|
||||
program
|
||||
.command('syncEvents <type> <currency> <amount>')
|
||||
.description(
|
||||
'Sync the local cache file of deposit / withdrawal events for specific currency.'
|
||||
)
|
||||
.action(async (type, currency, amount) => {
|
||||
console.log("Starting event sync command")
|
||||
currency = currency.toLowerCase()
|
||||
await init({ rpc: program.rpc, type, currency, amount, torPort: program.tor })
|
||||
const cachedEvents = await fetchEvents({ type, currency, amount })
|
||||
console.log("Synced event for",type,amount,currency.toUpperCase(),netName,"Tornado instance to block",cachedEvents[cachedEvents.length - 1].blockNumber)
|
||||
})
|
||||
program
|
||||
.command('test')
|
||||
|
178
config.js
178
config.js
@ -5,10 +5,16 @@ module.exports = {
|
||||
netId1: {
|
||||
'eth': {
|
||||
'instanceAddress': {
|
||||
'0.1': '0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc',
|
||||
'1': '0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936',
|
||||
'10': '0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF',
|
||||
'100': '0xA160cdAB225685dA1d56aa342Ad8841c3b53f291',
|
||||
'0.1': '0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc'
|
||||
'100': '0xA160cdAB225685dA1d56aa342Ad8841c3b53f291'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 9116966,
|
||||
'1': 9117609,
|
||||
'10': 9117720,
|
||||
'100': 9161895
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'symbol': 'ETH',
|
||||
@ -21,6 +27,12 @@ module.exports = {
|
||||
'10000': '0x07687e702b410Fa43f4cB4Af7FA097918ffD2730',
|
||||
'100000': '0x23773E65ed146A459791799d01336DB287f25334'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 9117612,
|
||||
'1000': 9161917,
|
||||
'10000': 12066007,
|
||||
'100000': 12066048
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
||||
'symbol': 'DAI',
|
||||
@ -34,6 +46,12 @@ module.exports = {
|
||||
'500000': '0x2717c5e28cf931547B621a5dddb772Ab6A35B701',
|
||||
'5000000': '0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'5000': 9161938,
|
||||
'50000': 12069037,
|
||||
'500000': 12067606,
|
||||
'5000000': 12066053
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643',
|
||||
'symbol': 'cDAI',
|
||||
@ -47,6 +65,12 @@ module.exports = {
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 9161958,
|
||||
'1000': 9161965,
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'tokenAddress': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
||||
'symbol': 'USDC',
|
||||
@ -60,6 +84,12 @@ module.exports = {
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 9162005,
|
||||
'1000': 9162012,
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'tokenAddress': '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
||||
'symbol': 'USDT',
|
||||
@ -73,6 +103,12 @@ module.exports = {
|
||||
'10': '0xbB93e510BbCD0B7beb5A853875f9eC60275CF498',
|
||||
'100': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 12067529,
|
||||
'1': 12066652,
|
||||
'10': 12067591,
|
||||
'100': ''
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
||||
'symbol': 'WBTC',
|
||||
@ -84,10 +120,16 @@ module.exports = {
|
||||
netId5: {
|
||||
'eth': {
|
||||
'instanceAddress': {
|
||||
'0.1': '0x6Bf694a291DF3FeC1f7e69701E3ab6c592435Ae7',
|
||||
'1': '0x3aac1cC67c2ec5Db4eA850957b967Ba153aD6279',
|
||||
'10': '0x723B78e67497E85279CB204544566F4dC5d2acA0',
|
||||
'100': '0x0E3A09dDA6B20aFbB34aC7cD4A6881493f3E7bf7',
|
||||
'0.1': '0x6Bf694a291DF3FeC1f7e69701E3ab6c592435Ae7'
|
||||
'100': '0x0E3A09dDA6B20aFbB34aC7cD4A6881493f3E7bf7'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 3782581,
|
||||
'1': 3782590,
|
||||
'10': 3782593,
|
||||
'100': 3782596
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'symbol': 'ETH',
|
||||
@ -100,6 +142,12 @@ module.exports = {
|
||||
'10000': '0xD5d6f8D9e784d0e26222ad3834500801a68D027D',
|
||||
'100000': '0x407CcEeaA7c95d2FE2250Bf9F2c105aA7AAFB512'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 4339088,
|
||||
'1000': 4367659,
|
||||
'10000': 4441492,
|
||||
'100000': 4441488
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60',
|
||||
'symbol': 'DAI',
|
||||
@ -113,6 +161,12 @@ module.exports = {
|
||||
'500000': '0x8281Aa6795aDE17C8973e1aedcA380258Bc124F9',
|
||||
'5000000': '0x57b2B8c82F065de8Ef5573f9730fC1449B403C9f'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'5000': 4441443,
|
||||
'50000': 4441489,
|
||||
'500000': 4441493,
|
||||
'5000000': 4441489
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0x822397d9a55d0fefd20F5c4bCaB33C5F65bd28Eb',
|
||||
'symbol': 'cDAI',
|
||||
@ -126,6 +180,12 @@ module.exports = {
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 4441426,
|
||||
'1000': 4441492,
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'tokenAddress': '0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C',
|
||||
'symbol': 'USDC',
|
||||
@ -139,6 +199,12 @@ module.exports = {
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 4441490,
|
||||
'1000': 4441492,
|
||||
'10000': '',
|
||||
'100000': ''
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'tokenAddress': '0xb7FC2023D96AEa94Ba0254AA5Aeb93141e4aad66',
|
||||
'symbol': 'USDT',
|
||||
@ -152,6 +218,12 @@ module.exports = {
|
||||
'10': '0xeDC5d01286f99A066559F60a585406f3878a033e',
|
||||
'100': ''
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 4441488,
|
||||
'1': 4441490,
|
||||
'10': 4441490,
|
||||
'100': ''
|
||||
},
|
||||
'miningEnabled': true,
|
||||
'tokenAddress': '0xC04B0d3107736C32e19F1c62b2aF67BE61d63a05',
|
||||
'symbol': 'WBTC',
|
||||
@ -160,5 +232,103 @@ module.exports = {
|
||||
},
|
||||
proxy: '0x454d870a72e29d5e5697f635128d18077bd04c60',
|
||||
},
|
||||
netId56: {
|
||||
'bnb': {
|
||||
'instanceAddress': {
|
||||
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
|
||||
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
|
||||
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
|
||||
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 8159279,
|
||||
'1': 8159286,
|
||||
'10': 8159290,
|
||||
'100': 8159296
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'symbol': 'BNB',
|
||||
'decimals': 18
|
||||
},
|
||||
proxy: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
netId100: {
|
||||
'xdai': {
|
||||
'instanceAddress': {
|
||||
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
|
||||
'1000': '0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178',
|
||||
'10000': '0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040',
|
||||
'100000': '0xa5C2254e4253490C54cef0a4347fddb8f75A4998'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 17754566,
|
||||
'1000': 17754568,
|
||||
'10000': 17754572,
|
||||
'100000': 17754574
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'symbol': 'xDAI',
|
||||
'decimals': 18
|
||||
},
|
||||
proxy: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
netId137: {
|
||||
'matic': {
|
||||
'instanceAddress': {
|
||||
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
|
||||
'1000': '0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178',
|
||||
'10000': '0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040',
|
||||
'100000': '0xa5C2254e4253490C54cef0a4347fddb8f75A4998'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'100': 16258013,
|
||||
'1000': 16258032,
|
||||
'10000': 16258046,
|
||||
'100000': 16258053
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'symbol': 'MATIC',
|
||||
'decimals': 18
|
||||
},
|
||||
proxy: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
netId42161: {
|
||||
'eth': {
|
||||
'instanceAddress': {
|
||||
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
|
||||
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
|
||||
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
|
||||
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'0.1': 3300000,
|
||||
'1': 3300000,
|
||||
'10': 3300000,
|
||||
'100': 3300000
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'symbol': 'ETH',
|
||||
'decimals': 18
|
||||
},
|
||||
proxy: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
netId43114: {
|
||||
'avax': {
|
||||
'instanceAddress': {
|
||||
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
|
||||
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
|
||||
'500': '0xaf8d1839c3c67cf571aa74B5c12398d4901147B3'
|
||||
},
|
||||
'deployedBlockNumber': {
|
||||
'10': 4429830,
|
||||
'100': 4429851,
|
||||
'500': 4429837
|
||||
},
|
||||
'miningEnabled': false,
|
||||
'symbol': 'AVAX',
|
||||
'decimals': 18
|
||||
},
|
||||
proxy: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
47
local_modules/web3-providers-http/README.md
Normal file
47
local_modules/web3-providers-http/README.md
Normal 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
|
125
local_modules/web3-providers-http/lib/index.js
Normal file
125
local_modules/web3-providers-http/lib/index.js
Normal 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;
|
6
local_modules/web3-providers-http/local_modules/xhr2-cookies/.gitignore
vendored
Normal file
6
local_modules/web3-providers-http/local_modules/xhr2-cookies/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
yarn-error.log
|
||||
.idea
|
||||
**/*.js
|
||||
**/*.js.map
|
||||
!wallaby.js
|
@ -0,0 +1,4 @@
|
||||
*
|
||||
.idea
|
||||
!dist/*
|
||||
!package.json
|
@ -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
|
8
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/errors.d.ts
vendored
Normal file
8
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/errors.d.ts
vendored
Normal 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 {
|
||||
}
|
2
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/index.d.ts
vendored
Normal file
2
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/index.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './xml-http-request';
|
||||
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
11
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/progress-event.d.ts
vendored
Normal file
11
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/progress-event.d.ts
vendored
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
12
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.d.ts
vendored
Normal file
12
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request-upload.d.ts
vendored
Normal 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;
|
||||
}
|
102
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.d.ts
vendored
Normal file
102
local_modules/web3-providers-http/local_modules/xhr2-cookies/dist/xml-http-request.d.ts
vendored
Normal 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();
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
export class SecurityError extends Error {}
|
||||
export class InvalidStateError extends Error {}
|
||||
export class NetworkError extends Error {}
|
||||
export class SyntaxError extends Error {}
|
@ -0,0 +1,2 @@
|
||||
export * from './xml-http-request';
|
||||
export { XMLHttpRequestEventTarget } from './xml-http-request-event-target';
|
@ -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/**/*"
|
||||
]
|
||||
}
|
||||
}
|
@ -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) {}
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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
|
@ -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');
|
||||
});
|
BIN
local_modules/web3-providers-http/local_modules/xhr2-cookies/test/fixtures/hello.png
vendored
Normal file
BIN
local_modules/web3-providers-http/local_modules/xhr2-cookies/test/fixtures/hello.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 119 B |
@ -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
|
||||
// *
|
@ -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-----
|
||||
`;
|
@ -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
|
@ -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-----
|
@ -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-----
|
@ -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-----
|
@ -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 };
|
@ -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 };
|
@ -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');
|
||||
});
|
@ -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();
|
||||
});
|
||||
});
|
@ -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();
|
||||
});
|
||||
});
|
@ -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();
|
||||
});
|
||||
});
|
@ -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();
|
||||
});
|
||||
});
|
@ -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);
|
||||
});
|
||||
});
|
@ -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"
|
||||
]
|
||||
}
|
@ -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');
|
||||
});
|
@ -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"
|
||||
]
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -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']
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
2171
local_modules/web3-providers-http/package-lock.json
generated
Normal file
2171
local_modules/web3-providers-http/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
local_modules/web3-providers-http/package.json
Normal file
24
local_modules/web3-providers-http/package.json
Normal 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"
|
||||
}
|
||||
}
|
142
local_modules/web3-providers-http/src/index.js
Normal file
142
local_modules/web3-providers-http/src/index.js
Normal 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;
|
9
local_modules/web3-providers-http/tsconfig.json
Normal file
9
local_modules/web3-providers-http/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
66
local_modules/web3-providers-http/types/index.d.ts
vendored
Normal file
66
local_modules/web3-providers-http/types/index.d.ts
vendored
Normal 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;
|
||||
}
|
@ -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();
|
17
local_modules/web3-providers-http/types/tsconfig.json
Normal file
17
local_modules/web3-providers-http/types/tsconfig.json
Normal 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": ["."]
|
||||
}
|
||||
}
|
||||
}
|
10
local_modules/web3-providers-http/types/tslint.json
Normal file
10
local_modules/web3-providers-http/types/tslint.json
Normal 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
2267
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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
368
yarn.lock
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user