diff --git a/README.md b/README.md
index 786e3f3..2a36035 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ It provides in a single command the setup of a full Samourai backend composed of
* the backend modules with an API accessible as a static Tor hidden service,
* a maintenance tool accessible through a Tor web browser,
* a block explorer ([BTC RPC Explorer](https://github.com/janoside/btc-rpc-explorer)) accessible through a Tor web browser,
-* an optional indexer of Bitcoin addresses ([addrindexrs](https://github.com/Samourai-Wallet/addrindexrs)) providing fast and private rescans of HD accounts and loose addresses.
+* an optional indexer of Bitcoin addresses ([addrindexrs](hhttps://code.samourai.io/dojo/addrindexrs)) providing fast and private rescans of HD accounts and loose addresses.
See [the documentation](./doc/DOCKER_setup.md) for detailed setup instructions.
diff --git a/RELEASES.md b/RELEASES.md
index ee9a9c8..8ec57a7 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3,6 +3,7 @@
## Releases ##
+- [v1.7.0](#1_7_0)
- [v1.6.0](#1_6_0)
- [v1.5.0](#1_5_0)
- [v1.4.1](#1_4_1)
@@ -12,6 +13,51 @@
- [v1.1.0](#1_1_0)
+
+
+## Samourai Dojo v1.7.0 ##
+
+
+### Notable changes ###
+
+
+#### New optional strict_mode_vouts added to PushTx endpoints ####
+
+A new optional "strict mode" is added to the /pushtx and /pushtx/schedule endpoints of the API.
+
+This strict mode enforces a few additional checks on a selected subset of the outputs of a transaction before it's pushed on the P2P network or before it's scheduled for a delayed push.
+
+See this [doc](https://code.samourai.io/dojo/samourai-dojo/-/blob/develop/doc/POST_pushtx.md) for detailed information.
+
+
+#### Upgrade of whirlpool to v0.10.8 ####
+
+Upgrade to [whirlpool-cli](https://code.samourai.io/whirlpool/whirlpool-client-cli) v0.10.8
+
+A new config parameter `WHIRLPOOL_RESYNC` is added to docker-whirlpool.conf. When set to `on`, mix counters are resynchronized on startup of whirlpool-cli.
+
+
+### Change log ###
+
+
+#### MyDojo ####
+
+- [#mr142](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/142) add setup of explorer in keys.index.js
+- [#mr143](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/143) update doc and package.json with url of new repository
+- [#mr144](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/144) switch addrindexrs repo to gitlab
+- [#mr145](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/145) explicitely set algo used for jwt signatures
+- [#mr146](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/146) upgrade whirlpool to whirlpool-cli 0.10.7
+- [#mr147](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/147) add new optional strict_mode_vouts to pushtx endpoints
+- [#mr148](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/148) status code pushtx endpoints
+- [#mr149](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/149) upgrade whirlpool to whirlpool-cli 0.10.8
+
+
+#### Credits ###
+
+- kenshin-samourai
+- zeroleak
+
+
## Samourai Dojo v1.6.0 ##
diff --git a/accounts/support-rest-api.js b/accounts/support-rest-api.js
index 8b18b5d..34cf985 100644
--- a/accounts/support-rest-api.js
+++ b/accounts/support-rest-api.js
@@ -312,20 +312,11 @@ class SupportRestApi {
*/
async getPairingExplorer(req, res) {
try {
- let url = ''
- if (process.env.EXPLORER_INSTALL == 'on') {
- try {
- url = fs.readFileSync('/var/lib/tor/hsv3explorer/hostname', 'utf8')
- url = url.replace('\n', '')
- } catch(e) {
- Logger.error(e, 'API : SupportRestApi.getPairing() : Cannot read explorer onion address')
- }
- }
const ret = {
'pairing': {
- 'type': 'explorer.btcRpcExplorer',
- 'url': url,
- 'key': process.env.EXPLORER_KEY
+ 'type': `explorer.${keys.explorer.active}`,
+ 'url': keys.explorer.uri,
+ 'key': keys.explorer.password
}
}
HttpServer.sendRawData(res, JSON.stringify(ret, null, 2))
diff --git a/doc/DOCKER_advanced_setups.md b/doc/DOCKER_advanced_setups.md
index 4f13e39..2369eb9 100644
--- a/doc/DOCKER_advanced_setups.md
+++ b/doc/DOCKER_advanced_setups.md
@@ -21,7 +21,7 @@ A word of caution, though, the default values of these options try to maximize y
## Local indexer of Bitcoin addresses ##
-By default, Dojo uses the local full node as its data source for imports and rescans of HD accounts and addresses. While private, this default option has many limitations. MyDojo allows to install a local indexer ([addrindexrs](https://github.com/Samourai-Wallet/addrindexrs)) providing the best of both worlds (no request sent to a third party, fast and real time rescans, complete transactional history is retrieved).
+By default, Dojo uses the local full node as its data source for imports and rescans of HD accounts and addresses. While private, this default option has many limitations. MyDojo allows to install a local indexer ([addrindexrs](https://code.samourai.io/dojo/addrindexrs)) providing the best of both worlds (no request sent to a third party, fast and real time rescans, complete transactional history is retrieved).
### Requirements ###
@@ -122,7 +122,7 @@ nano ./conf/docker-node.conf
## Local Whirlpool client ##
-This setup allows to install and run a [Whirlpool client](https://github.com/Samourai-Wallet/whirlpool-client-cli) inside MyDojo.
+This setup allows to install and run a [Whirlpool client](https://code.samourai.io/whirlpool/whirlpool-client-cli) inside MyDojo.
The client can be configured and controlled through a REST API exposed as a Tor hidden service.
@@ -144,7 +144,7 @@ nano ./conf/docker-whirlpool.conf
### Installation of Whirlpool GUI ###
-The [Whirlpool GUI application]((https://github.com/Samourai-Wallet/whirlpool-gui)) provides a graphical interface for your Whirlpool client.
+The [Whirlpool GUI application]((https://code.samourai.io/whirlpool/whirlpool-gui)) provides a graphical interface for your Whirlpool client.
These steps describe how to install the Whirlpool GUI application how a computer and how to connect it to your Whirlpool client.
diff --git a/doc/DOCKER_mac_setup.MD b/doc/DOCKER_mac_setup.MD
index 47b3279..300c9eb 100644
--- a/doc/DOCKER_mac_setup.MD
+++ b/doc/DOCKER_mac_setup.MD
@@ -22,7 +22,7 @@ Follow the instructions in this [video](https://www.youtube.com/watch?v=6M1DivpQ
Also, remember to install the virtual box at a directory where you have __enough free space__ to install the Dojo. Specially if you are running a full node.
-After the setup is complete, start the virtual box and open a terminal window then proceed to install the Dojo following these [instructions](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_setup.md#install).
+After the setup is complete, start the virtual box and open a terminal window then proceed to install the Dojo following these [instructions](https://code.samourai.io/dojo/samourai-dojo/-/blob/master/doc/DOCKER_setup.md#install).
@@ -73,7 +73,7 @@ Note: _This is an important step, otherwise, it's probable that when you run the
(_At 4 CPUs, 8GB of RAM and a 4GiB Swap - the initial block download took 4.5 days at the time of writing_).
### Install the DOJO
-Follow the instructions [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_setup.md) starting at the step:
+Follow the instructions [here](https://code.samourai.io/dojo/samourai-dojo/-/blob/master/doc/DOCKER_setup.md) starting at the step:
__"Download the most recent release of Dojo from Github"__
_Note: For tracking progress, open Kitematic and follow the bitcoind logs. You'll be able to see the Blockchain verification process under the _progress_ log variable (1.00 = fully validated). This process takes a long time. Just let it do its thing. In my system it took 3 days._
@@ -105,11 +105,11 @@ This installation was tested on an iMac (late 2014) with a 3.5GHz i5 processor w
4. Click __Advanced__ and increase the CPU count, Memory and Swap sizes. Adjusting these will speed up the blockchain validation process
### Install the DOJO Pointing and Existing bitcoind
-Follow the instructions [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_setup.md) starting at the step:
+Follow the instructions [here](hhttps://code.samourai.io/dojo/samourai-dojo/-/blob/master/doc/DOCKER_setup.md) starting at the step:
__"Download the most recent release of Dojo from Github"__ until you reach __"Launch the Installation of Your Dojo with"__ ***DO NOT LAUNCH DOJO YET***
-Once you Reach Step __"Launch the Installation of Your Dojo with"__ from above you will need to read and follow the instructions from [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_advanced_setups.md)
-Once adjustments are made to your external bitcoind bitcoin.conf __(location dependent on what device you have bitcoind)__ and docker-bitcoind.conf.tpl __(dojo_dir > docker > my-dojo > conf)__ you can proceed with Install and revert back to original instructions [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_setup.md) at section __"Launch the Installation of Your Dojo with"__
+Once you Reach Step __"Launch the Installation of Your Dojo with"__ from above you will need to read and follow the instructions from [here](https://code.samourai.io/dojo/samourai-dojo/-/blob/master/doc/DOCKER_advanced_setups.md)
+Once adjustments are made to your external bitcoind bitcoin.conf __(location dependent on what device you have bitcoind)__ and docker-bitcoind.conf.tpl __(dojo_dir > docker > my-dojo > conf)__ you can proceed with Install and revert back to original instructions [here](https://code.samourai.io/dojo/samourai-dojo/-/blob/master/doc/DOCKER_setup.md) at section __"Launch the Installation of Your Dojo with"__
_Note: For tracking progress, open terminal, change directory to my-dojo and run /dojo.sh logs nodejs
__Some possible optimization tips:__
diff --git a/doc/DOCKER_setup.md b/doc/DOCKER_setup.md
index b90a4a2..150d9aa 100644
--- a/doc/DOCKER_setup.md
+++ b/doc/DOCKER_setup.md
@@ -6,7 +6,7 @@ MyDojo is a set of Docker containers providing a full Samourai backend composed
* backend modules with an API accessible as a static Tor hidden service,
* a maintenance tool accessible through a Tor web browser,
* a block explorer ([BTC RPC Explorer](https://github.com/janoside/btc-rpc-explorer)) accessible as a static Tor hidden service.
-* an optional indexer of Bitcoin addresses ([addrindexrs](https://github.com/Samourai-Wallet/addrindexrs)) providing fast and private rescans of HD accounts and loose addresses.
+* an optional indexer of Bitcoin addresses ([addrindexrs](https://code.samourai.io/dojo/addrindexrs)) providing fast and private rescans of HD accounts and loose addresses.
## Table of Content ##
@@ -113,7 +113,7 @@ For MacOS, see this detailed [installation guide](./DOCKER_mac_setup.MD).
For Synology, see this detailed [installation guide](./DOCKER_synology_setup.md).
-For Raspberry Pi4 and Odroid N2, see the [Ronin Dojo Project](https://github.com/RoninDojo/RoninDojo)
+For Raspberry Pi4 and Odroid N2, see the [Ronin Dojo Project](https://code.samourai.io/ronindojo/RoninDojo)
This procedure allows to install a new Dojo from scratch.
@@ -122,7 +122,7 @@ This procedure allows to install a new Dojo from scratch.
* Install [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en) on the host machine.
-* Download the most recent release of Dojo from [Github](https://github.com/Samourai-Wallet/samourai-dojo/archive/master.zip)
+* Download the most recent release of Dojo from [Gitlab](https://code.samourai.io/dojo/samourai-dojo/-/archive/master/samourai-dojo-master.zip)
* Uncompress the archive on the host machine in a temporary directory of your choice (named `` in this doc)
@@ -209,7 +209,7 @@ This procedure allows to upgrade your Dojo with a new version.
./dojo.sh stop
```
-* Download the most recent release of Dojo from [Github](https://github.com/Samourai-Wallet/samourai-dojo/releases)
+* Download the most recent release of Dojo from [Gitlab](https://code.samourai.io/dojo/samourai-dojo/-/releases)
* Uncompress the archive on the host machine in a temporary directory of your choice (named `` in this doc)
diff --git a/doc/DOCKER_synology_setup.md b/doc/DOCKER_synology_setup.md
index 7d18a94..9aef60e 100644
--- a/doc/DOCKER_synology_setup.md
+++ b/doc/DOCKER_synology_setup.md
@@ -76,13 +76,13 @@ cd
```
cp -r ./ ../dojo-backup
```
-- Download latest Dojo from [GitHub releases](https://github.com/Samourai-Wallet/samourai-dojo/releases)
+- Download latest Dojo from [Gitlab releases](https://code.samourai.io/dojo/samourai-dojo/-/releases)
```
mkdir newDojo
cd newDojo
- wget https://github.com/Samourai-Wallet/samourai-dojo/archive/v1.5.0.tar.gz
- tar xzvf v1.5.0.tar.gz
- cp -r samourai-dojo-1.5.0/* ../
+ wget https://code.samourai.io/dojo/samourai-dojo/-/archive/v1.7.0/samourai-dojo-v1.7.0.tar.gz
+ tar xzvf samourai-dojo-v1.7.0.tar.gz
+ cp -r samourai-dojo-v1.7.0/* ../
cd ..
```
- Upgrade
diff --git a/doc/GET_multiaddr.md b/doc/GET_multiaddr.md
index 08b9a96..49b1956 100644
--- a/doc/GET_multiaddr.md
+++ b/doc/GET_multiaddr.md
@@ -135,4 +135,4 @@ Status code 400 with JSON response:
```
## Notes
-Multiaddr response is consumed by the wallet in the [APIFactory](https://github.com/Samourai-Wallet/samourai-wallet-android/blob/master/app/src/main/java/com/samourai/wallet/api/APIFactory.java)
+Multiaddr response is consumed by the wallet in the [APIFactory](https://code.samourai.io/wallet/samourai-wallet-android/-/blob/master/app/src/main/java/com/samourai/wallet/api/APIFactory.java)
diff --git a/doc/GET_unspent.md b/doc/GET_unspent.md
index 1e81758..b4fcd9f 100644
--- a/doc/GET_unspent.md
+++ b/doc/GET_unspent.md
@@ -79,4 +79,4 @@ Status code 400 with JSON response:
```
## Notes
-Unspent response is consumed by the wallet in the [APIFactory](https://github.com/Samourai-Wallet/samourai-wallet-android/blob/master/app/src/main/java/com/samourai/wallet/api/APIFactory.java)
+Unspent response is consumed by the wallet in the [APIFactory](https://code.samourai.io/wallet/samourai-wallet-android/-/blob/master/app/src/main/java/com/samourai/wallet/api/APIFactory.java)
diff --git a/doc/POST_pushtx.md b/doc/POST_pushtx.md
index 029fe37..aa6de56 100644
--- a/doc/POST_pushtx.md
+++ b/doc/POST_pushtx.md
@@ -10,6 +10,7 @@ Parameters must be passed in the body of the request as url encoded arguments.
## Parameters
* **tx** - `hex string` - The raw transaction hex
* **at** - `string` (optional) - Access Token (json web token). Required if authentication is activated. Alternatively, the access token can be passed through the `Authorization` HTTP header (with the `Bearer` scheme).
+* **strict_mode_vouts** (optional) - `string` - A pipe-separated list of outpoints indices. A strict verification is enforced on these outpoints before the transaction is pushed. Strict mode checks that addresses associated to these outputs aren't reused. If verifications fail, push is aborted and an error is returned.
### Example
@@ -18,6 +19,7 @@ Parameters must be passed in the body of the request as url encoded arguments.
POST /pushtx/
tx=abcdef0123456789
+strict_mode_vouts=0|2|3
```
#### Success
@@ -32,11 +34,19 @@ Status code 200 with JSON response:
#### Failure
Status code 400 with JSON response:
```json
+{
+ "status": "error",
+ "error": ""
+}
+```
+
+or status code 200 with JSON response:
+```json
{
"status": "error",
"error": {
- "message": "",
- "code": ""
+ "message": [],
+ "code": "VIOLATION_STRICT_MODE_VOUTS"
}
}
```
diff --git a/doc/POST_pushtx_schedule.md b/doc/POST_pushtx_schedule.md
index 69d56b1..5ea4a55 100644
--- a/doc/POST_pushtx_schedule.md
+++ b/doc/POST_pushtx_schedule.md
@@ -29,6 +29,7 @@ If step A and step B have the same **hop** value, then they MAY HAVE different *
The transaction MUST HAVE its nLockTime field filled with the height of a block.
The height of the block MUST BE equal to the value of the **nlocktime** field of the ScriptStep object.
+* **strict_mode_vouts** (optional) - `int[]` - An array of outpoints indices. A strict verification is enforced on these outpoints before the transaction is pushed. Strict mode checks that addresses associated to these outputs aren't reused. If verifications fail, the scheduled push is aborted and an error is returned.
### Examples
@@ -45,7 +46,8 @@ Request Body (JSON-encoded)
"script": [{
"hop": 0,
"nlocktime": 549817,
- "tx": ""
+ "tx": "",
+ "strict_mode_vouts": [0,1]
}, {
"hop": 1,
"nlocktime": 549818,
@@ -122,3 +124,18 @@ Status code 400 with JSON response:
"error": ""
}
```
+
+or status code 200 with JSON response:
+```json
+{
+ "status": "error",
+ "error": {
+ "message": [{
+ "txid": "",
+ "hop": ,
+ "vouts": []
+ }, ...],
+ "code": "VIOLATION_STRICT_MODE_VOUTS"
+ }
+}
+```
diff --git a/docker/my-dojo/.env b/docker/my-dojo/.env
index 53794e8..5352e51 100644
--- a/docker/my-dojo/.env
+++ b/docker/my-dojo/.env
@@ -10,15 +10,15 @@
COMPOSE_CONVERT_WINDOWS_PATHS=1
-DOJO_VERSION_TAG=1.6.0
+DOJO_VERSION_TAG=1.7.0
DOJO_DB_VERSION_TAG=1.2.0
DOJO_BITCOIND_VERSION_TAG=1.6.0
-DOJO_NODEJS_VERSION_TAG=1.6.0
+DOJO_NODEJS_VERSION_TAG=1.7.0
DOJO_NGINX_VERSION_TAG=1.5.0
DOJO_TOR_VERSION_TAG=1.4.0
DOJO_EXPLORER_VERSION_TAG=1.3.0
DOJO_INDEXER_VERSION_TAG=1.1.0
-DOJO_WHIRLPOOL_VERSION_TAG=1.0.0
+DOJO_WHIRLPOOL_VERSION_TAG=1.1.0
#########################################
diff --git a/docker/my-dojo/conf/docker-whirlpool.conf.tpl b/docker/my-dojo/conf/docker-whirlpool.conf.tpl
index 2ec295a..762681f 100644
--- a/docker/my-dojo/conf/docker-whirlpool.conf.tpl
+++ b/docker/my-dojo/conf/docker-whirlpool.conf.tpl
@@ -6,6 +6,10 @@
# Value: on | off
WHIRLPOOL_INSTALL=off
+# Resynchronize mix counters on startup (startup will be slower)
+# Value: on | off
+WHIRLPOOL_RESYNC=off
+
#
# EXPERT SETTINGS
diff --git a/docker/my-dojo/indexer/Dockerfile b/docker/my-dojo/indexer/Dockerfile
index 8fd258a..b838a13 100644
--- a/docker/my-dojo/indexer/Dockerfile
+++ b/docker/my-dojo/indexer/Dockerfile
@@ -2,7 +2,7 @@ FROM rust:1.42.0-slim-buster
ENV INDEXER_HOME /home/indexer
ENV INDEXER_VERSION 0.3.0
-ENV INDEXER_URL https://github.com/Samourai-Wallet/addrindexrs.git
+ENV INDEXER_URL https://code.samourai.io/dojo/addrindexrs.git
RUN apt-get update && \
apt-get install -y clang cmake git && \
diff --git a/docker/my-dojo/node/keys.index.js b/docker/my-dojo/node/keys.index.js
index 3c2ca42..e37a1f3 100644
--- a/docker/my-dojo/node/keys.index.js
+++ b/docker/my-dojo/node/keys.index.js
@@ -2,11 +2,27 @@
* keys/index-example.js
* Copyright (c) 2016-2018, Samourai Wallet (CC BY-NC-ND 4.0 License).
*/
+const fs = require('fs')
+
+// Retrieve active bitcoin network from conf files
const bitcoinNetwork = (process.env.COMMON_BTC_NETWORK == 'testnet')
? 'testnet'
: 'bitcoin'
+// Retrieve explorer config from conf files
+let explorerActive = 'oxt'
+let explorerUrl = 'https://oxt.me'
+let explorerPassword = ''
+if (process.env.EXPLORER_INSTALL == 'on') {
+ try {
+ explorerUrl = fs.readFileSync('/var/lib/tor/hsv3explorer/hostname', 'utf8').replace('\n', '')
+ explorerPassword = process.env.EXPLORER_KEY
+ explorerActive = 'btc_rpc_explorer'
+ } catch(e) {}
+}
+
+
/**
* Desired structure of /keys/index.js, which is ignored in the repository.
*/
@@ -180,6 +196,18 @@ module.exports = {
// Esplora (testnet)
esplora: process.env.NODE_URL_ESPLORA_API,
},
+ /*
+ * Explorer recommended by this Dojo
+ */
+ explorer: {
+ // Active explorer
+ // Values: oxt | btc_rpc_explorer
+ active: explorerActive,
+ // URI of the explorer
+ uri: explorerUrl,
+ // Password (value required for btc_rpc_explorer)
+ password: explorerPassword
+ },
/*
* Max number of transactions per address
* accepted during fast scan
diff --git a/docker/my-dojo/whirlpool/Dockerfile b/docker/my-dojo/whirlpool/Dockerfile
index 4808b6d..2aee4a0 100644
--- a/docker/my-dojo/whirlpool/Dockerfile
+++ b/docker/my-dojo/whirlpool/Dockerfile
@@ -51,10 +51,10 @@ RUN set -ex && \
# Install whirlpool-cli
ENV WHIRLPOOL_URL https://code.samourai.io/whirlpool/whirlpool-client-cli/uploads
-ENV WHIRLPOOL_VERSION 0.10.6
-ENV WHIRLPOOL_VERSION_HASH a05b443bf9d266702327c99fd8bad5da
+ENV WHIRLPOOL_VERSION 0.10.8
+ENV WHIRLPOOL_VERSION_HASH 7998ea5a9bb180451616809bc346b9ac
ENV WHIRLPOOL_JAR "whirlpool-client-cli-$WHIRLPOOL_VERSION-run.jar"
-ENV WHIRLPOOL_SHA256 eb07ef5637c2bb52b1be57b62941120a689b0c02600c38dbda3b8dd701d03cc8
+ENV WHIRLPOOL_SHA256 62e17b6020d0821a98e99ebb773b46191770ec186ceaa3e616a428f5cafe9f49
RUN set -ex && \
cd "$WHIRLPOOL_DIR" && \
diff --git a/docker/my-dojo/whirlpool/restart.sh b/docker/my-dojo/whirlpool/restart.sh
index 94d9181..ee0469e 100644
--- a/docker/my-dojo/whirlpool/restart.sh
+++ b/docker/my-dojo/whirlpool/restart.sh
@@ -22,6 +22,10 @@ else
whirlpool_options+=(--cli.dojo.url="http://172.30.1.3:80/v2/")
fi
+if [ "$WHIRLPOOL_RESYNC" == "on" ]; then
+ whirlpool_options+=(--resync)
+fi
+
if [ "$WHIRLPOOL_DEBUG" == "on" ]; then
whirlpool_options+=(--debug)
fi
diff --git a/keys/index-example.js b/keys/index-example.js
index cd72820..b001627 100644
--- a/keys/index-example.js
+++ b/keys/index-example.js
@@ -174,6 +174,18 @@ module.exports = {
// OXT
oxt: 'https://api.oxt.me'
},
+ /*
+ * Explorer recommended by this Dojo
+ */
+ explorer: {
+ // Active explorer
+ // Values: oxt | btc_rpc_explorer
+ active: 'oxt',
+ // URI of the explorer
+ uri: 'https://oxt.me',
+ // Password (value required for btc_rpc_explorer)
+ password: ''
+ },
/*
* Max number of transactions per address
* accepted during fast scan
@@ -295,6 +307,11 @@ module.exports = {
socks5Proxy: null,
esplora: 'https://blockstream.info/testnet'
},
+ explorer: {
+ active: 'none',
+ uri: '',
+ password: ''
+ },
addrFilterThreshold: 1000,
addrDerivationPool: {
minNbChildren: 1,
diff --git a/lib/auth/authorizations-manager.js b/lib/auth/authorizations-manager.js
index 82cbc41..fb830a9 100644
--- a/lib/auth/authorizations-manager.js
+++ b/lib/auth/authorizations-manager.js
@@ -23,6 +23,7 @@ class AuthorizationsManager {
constructor() {
try {
// Constants
+ this.JWT_ALGO = 'HS256'
this.ISS = 'Samourai Wallet backend'
this.TOKEN_TYPE_ACCESS = 'access-token'
this.TOKEN_TYPE_REFRESH = 'refresh-token'
@@ -210,7 +211,10 @@ class AuthorizationsManager {
return jwt.sign(
claims,
this._secret,
- {expiresIn: this.accessTokenExpires}
+ {
+ expiresIn: this.accessTokenExpires,
+ algorithm: this.JWT_ALGO
+ }
)
}
@@ -239,7 +243,11 @@ class AuthorizationsManager {
* @returns {Object} payload of the json web token
*/
_verifyAccessToken(token) {
- const payload = jwt.verify(token, this._secret, {})
+ const payload = jwt.verify(
+ token,
+ this._secret,
+ {algorithms: [this.JWT_ALGO]}
+ )
if (payload['type'] != this.TOKEN_TYPE_ACCESS)
throw errors.auth.INVALID_JWT
@@ -263,7 +271,10 @@ class AuthorizationsManager {
return jwt.sign(
claims,
this._secret,
- {expiresIn: this.refreshTokenExpires}
+ {
+ expiresIn: this.refreshTokenExpires,
+ algorithm: this.JWT_ALGO
+ }
)
}
@@ -292,7 +303,11 @@ class AuthorizationsManager {
* @returns {Object} payload of the json web token
*/
_verifyRefreshToken(token) {
- const payload = jwt.verify(token, this._secret, {})
+ const payload = jwt.verify(
+ token,
+ this._secret,
+ {algorithms: [this.JWT_ALGO]}
+ )
if (payload['type'] != this.TOKEN_TYPE_REFRESH)
throw errors.auth.INVALID_JWT
diff --git a/lib/errors.js b/lib/errors.js
index 10b4a92..b8bef58 100644
--- a/lib/errors.js
+++ b/lib/errors.js
@@ -75,6 +75,7 @@ module.exports = {
pushtx: {
NLOCK_MISMATCH: 'nLockTime in script does not match nLockTime in transaction',
SCHEDULED_TOO_FAR: 'nLockTime is set to far in the future',
- SCHEDULED_BAD_ORDER: 'Order of hop and nLockTime values must be consistent'
+ SCHEDULED_BAD_ORDER: 'Order of hop and nLockTime values must be consistent',
+ VIOLATION_STRICT_MODE_VOUTS: 'VIOLATION_STRICT_MODE_VOUTS'
}
}
diff --git a/package-lock.json b/package-lock.json
index c22196a..2a84bca 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "samourai-dojo",
- "version": "1.6.0",
+ "version": "1.7.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 94a30c1..9ea48f6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "samourai-dojo",
- "version": "1.6.0",
+ "version": "1.7.0",
"description": "Backend server for Samourai Wallet",
"main": "accounts/index.js",
"scripts": {
@@ -8,11 +8,11 @@
},
"repository": {
"type": "git",
- "url": "git+ssh://git@github.com:Samourai-Wallet/samourai-dojo.git"
+ "url": "git+ssh://git@code.samourai.io:dojo/samourai-dojo.git"
},
"author": "Katana Cryptographic Ltd.",
"license": "AGPL-3.0-only",
- "homepage": "https://github.com/Samourai-Wallet/samourai-dojo",
+ "homepage": "https://code.samourai.io/dojo/samourai-dojo",
"dependencies": {
"async-sema": "2.1.2",
"bip39": "2.4.0",
diff --git a/pushtx/pushtx-processor.js b/pushtx/pushtx-processor.js
index cfe0ecb..0ba6d4c 100644
--- a/pushtx/pushtx-processor.js
+++ b/pushtx/pushtx-processor.js
@@ -8,11 +8,20 @@ const bitcoin = require('bitcoinjs-lib')
const zmq = require('zeromq')
const Logger = require('../lib/logger')
const errors = require('../lib/errors')
+const db = require('../lib/db/mysql-db-wrapper')
const RpcClient = require('../lib/bitcoind-rpc/rpc-client')
const network = require('../lib/bitcoin/network')
+const activeNet = network.network
const keys = require('../keys')[network.key]
const status = require('./status')
+let Sources
+if (network.key == 'bitcoin') {
+ Sources = require('../lib/remote-importer/sources-mainnet')
+} else {
+ Sources = require('../lib/remote-importer/sources-testnet')
+}
+
/**
* A singleton providing a wrapper
@@ -25,6 +34,7 @@ class PushTxProcessor {
*/
constructor() {
this.notifSock = null
+ this.sources = new Sources()
// Initialize the rpc client
this.rpcClient = new RpcClient()
}
@@ -38,6 +48,45 @@ class PushTxProcessor {
this.notifSock.bindSync(config.uriSocket)
}
+ /**
+ * Enforce a strict verification mode on a list of outputs
+ * @param {string} rawtx - raw bitcoin transaction in hex format
+ * @param {array} vouts - output indices (integer)
+ * @returns {array} returns the indices of the faulty outputs
+ */
+ async enforceStrictModeVouts(rawtx, vouts) {
+ const faultyOutputs = []
+ const addrMap = {}
+ let tx
+ try {
+ tx = bitcoin.Transaction.fromHex(rawtx)
+ } catch(e) {
+ throw errors.tx.PARSE
+ }
+ // Check in db if addresses are known and have been used
+ for (let vout of vouts) {
+ if (vout >= tx.outs.length)
+ throw errors.txout.VOUT
+ const output = tx.outs[vout]
+ const address = bitcoin.address.fromOutputScript(output.script, activeNet)
+ const nbTxs = await db.getAddressNbTransactions(address)
+ if (nbTxs == null || nbTxs > 0)
+ faultyOutputs.push(vout)
+ else
+ addrMap[address] = vout
+ }
+ // Checks with indexer if addresses are known and have been used
+ if (Object.keys(addrMap).length > 0) {
+ if (keys.indexer.active != 'local_bitcoind') {
+ const results = await this.sources.getAddresses(Object.keys(addrMap))
+ for (let r of results)
+ if (r.ntx > 0)
+ faultyOutputs.push(addrMap[r.address])
+ }
+ }
+ return faultyOutputs
+ }
+
/**
* Push transactions to the Bitcoin network
* @param {string} rawtx - raw bitcoin transaction in hex format
diff --git a/pushtx/pushtx-rest-api.js b/pushtx/pushtx-rest-api.js
index 7c9dcbd..b05dd5b 100644
--- a/pushtx/pushtx-rest-api.js
+++ b/pushtx/pushtx-rest-api.js
@@ -152,6 +152,27 @@ class PushTxRestApi {
if (!validator.isHexadecimal(query.tx))
return this._traceError(res, errors.body.INVDATA)
+ if (query.strict_mode_vouts) {
+ try {
+ const vouts = query.strict_mode_vouts.split('|').map(v => parseInt(v, 10))
+ if (vouts.some(isNaN))
+ throw errors.txout.VOUT
+ if (vouts.length > 0) {
+ let faults = await pushTxProcessor.enforceStrictModeVouts(query.tx, vouts)
+ if (faults.length > 0) {
+ return this._traceError(res, {
+ 'message': JSON.stringify({
+ 'message': faults,
+ 'code': errors.pushtx.VIOLATION_STRICT_MODE_VOUTS
+ })
+ }, 200)
+ }
+ }
+ } catch(e) {
+ return this._traceError(res, e)
+ }
+ }
+
try {
const txid = await pushTxProcessor.pushTx(query.tx)
HttpServer.sendOkData(res, txid)
@@ -177,7 +198,13 @@ class PushTxRestApi {
await this.scheduler.schedule(req.body.script)
HttpServer.sendOk(res)
} catch(e) {
- this._traceError(res, e)
+ // Returns code 200 if VIOLATION_STRICT_MODE_VOUTS
+ if (e.message && e.message.code && e.message.code == errors.pushtx.VIOLATION_STRICT_MODE_VOUTS) {
+ e.message = JSON.stringify(e.message)
+ this._traceError(res, e, 200)
+ } else {
+ this._traceError(res, e)
+ }
}
}
@@ -185,10 +212,13 @@ class PushTxRestApi {
* Trace an error during push
* @param {object} res - http response object
* @param {object} err - error object
+ * @param {int} errorCode - error code (optional)
*/
- _traceError(res, err) {
+ _traceError(res, err, errorCode) {
let ret = null
+ errorCode = errorCode == null ? 400 : errorCode
+
try {
if (err.message) {
let msg = {}
@@ -198,10 +228,7 @@ class PushTxRestApi {
if (msg.code && msg.message) {
Logger.error(null, 'PushTx : Error ' + msg.code + ': ' + msg.message)
- ret = {
- message: msg.message,
- code: msg.code
- }
+ ret = msg
} else {
Logger.error(err.message, 'PushTx : ')
ret = err.message
@@ -214,7 +241,7 @@ class PushTxRestApi {
Logger.error(e, 'PushTx : ')
ret = e
} finally {
- HttpServer.sendError(res, ret)
+ HttpServer.sendError(res, ret, errorCode)
}
}
diff --git a/pushtx/transactions-scheduler.js b/pushtx/transactions-scheduler.js
index 68425c2..11f085c 100644
--- a/pushtx/transactions-scheduler.js
+++ b/pushtx/transactions-scheduler.js
@@ -57,6 +57,7 @@ class TransactionsScheduler {
// Iterate over the transactions for a few validations
let lastHopProcessed = -1
let lastLockTimeProcessed = -1
+ const faults = []
for (let entry of script) {
// Compute delta height (entry.nlocktime - nltTx0)
@@ -77,6 +78,30 @@ class TransactionsScheduler {
if (entry.nlocktime < lastLockTimeProcessed)
throw errors.pushtx.SCHEDULED_BAD_ORDER
}
+ // Enforce strcit_mode_vouts if required
+ const vouts = entry.strict_mode_vouts
+ if (vouts) {
+ try {
+ if (vouts.some(isNaN))
+ throw errors.txout.VOUT
+ if (vouts.length > 0) {
+ let faultsTx = await pushTxProcessor.enforceStrictModeVouts(entry.tx, vouts)
+ if (faultsTx.length > 0) {
+ const txid = bitcoin.Transaction.fromHex(entry.tx).getId()
+ for (let vout of faultsTx) {
+ faults.push({
+ "txid": txid,
+ "hop": entry.hop,
+ "vouts": vout
+ })
+ }
+ }
+ }
+ } catch(e) {
+ throw e
+ }
+ }
+ // Prepare verification of next hop
lastHopProcessed = entry.hop
lastLockTimeProcessed = entry.nlocktime
// Update scheduled height if needed
@@ -84,6 +109,16 @@ class TransactionsScheduler {
entry.nlocktime = baseHeight + entry.delta
}
+ // Return if strict_mode_vout has detected errors
+ if (faults.length > 0) {
+ throw {
+ 'message': {
+ 'message': faults,
+ 'code': errors.pushtx.VIOLATION_STRICT_MODE_VOUTS
+ }
+ }
+ }
+
let parentTxid = null
let parentNlocktime = baseHeight