diff --git a/cyphernodeconf_docker/prompters/040_otsclient.js b/cyphernodeconf_docker/prompters/040_otsclient.js new file mode 100644 index 0000000..e5130d4 --- /dev/null +++ b/cyphernodeconf_docker/prompters/040_otsclient.js @@ -0,0 +1,15 @@ +const chalk = require('chalk'); + +const name = 'otsclient'; + +module.exports = { + name: function() { + return name; + }, + prompts: function( utils ) { + return []; + }, + templates: function( props ) { + return [ 'bitcoin.conf' ]; + } +}; diff --git a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml index 00dc6a5..cddc003 100644 --- a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml +++ b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml @@ -162,6 +162,8 @@ services: - "OTSCLIENT_LISTENING_PORT=6666" volumes: - "<%= otsclient_datapath %>:/otsfiles" + - "<%= otsclient_datapath %>/bitcoin.conf:/.bitcoin/bitcoin.conf" + command: $USER /script/startotsclient.sh networks: - cyphernodenet restart: always diff --git a/cyphernodeconf_docker/templates/otsclient/bitcoin.conf b/cyphernodeconf_docker/templates/otsclient/bitcoin.conf new file mode 100644 index 0000000..bed4730 --- /dev/null +++ b/cyphernodeconf_docker/templates/otsclient/bitcoin.conf @@ -0,0 +1,8 @@ +<% if (net === 'testnet') { %> +# testnet +testnet=1 +<% } %> + +rpcconnect=<%= (bitcoin_mode === 'internal')?'bitcoin':bitcoin_node_ip %> +rpcuser=<%= bitcoin_rpcuser %> +rpcpassword=<%= bitcoin_rpcpassword %> diff --git a/dist/setup.sh b/dist/setup.sh index 7b13290..1f5086d 100755 --- a/dist/setup.sh +++ b/dist/setup.sh @@ -477,6 +477,8 @@ install_docker() { sudo_if_required mkdir -p $OTSCLIENT_DATAPATH next fi + + copy_file $current_path/otsclient/bitcoin.conf $OTSCLIENT_DATAPATH/bitcoin.conf 1 $SUDO_REQUIRED fi docker swarm join-token worker > /dev/null 2>&1 diff --git a/docker-compose-sample.yml b/docker-compose-sample.yml index 59cf487..46d7624 100644 --- a/docker-compose-sample.yml +++ b/docker-compose-sample.yml @@ -105,6 +105,7 @@ services: # constraints: [node.hostname==dev] volumes: - "~/cn-files/cn-otsfiles:/otsfiles" + - "~/cn-files/cn-otsfiles/bitcoin.conf:/.bitcoin/bitcoin.conf" command: $USER /script/startotsclient.sh networks: - cyphernodenet diff --git a/otsclient_docker/script/otsclient.sh b/otsclient_docker/script/otsclient.sh index 1861b6e..1e54af9 100644 --- a/otsclient_docker/script/otsclient.sh +++ b/otsclient_docker/script/otsclient.sh @@ -2,8 +2,7 @@ . ./trace.sh -stamp() -{ +stamp() { trace "Entering stamp()..." local hash=${1} @@ -32,7 +31,7 @@ stamp() # String found data="${data}success\"}" else - # String nor found + # String not found data="${data}error\",\"error\":\"${result}\"}" fi @@ -43,8 +42,7 @@ stamp() return ${returncode} } -upgrade() -{ +upgrade() { trace "Entering upgrade()..." local hash=${1} @@ -81,3 +79,84 @@ upgrade() return ${returncode} } + +verify() { + trace "Entering verify()..." + + local request=${1} + local hash=$(echo "${request}" | jq ".hash" | tr -d '"') + trace "[verify] hash=${hash}" + local base64otsfile=$(echo "${request}" | jq ".base64otsfile" | tr -d '"') + trace "[verify] base64otsfile=${base64otsfile}" + + local result + local returncode + local data + + # Let's create the OTS file locally from the base64 + trace "[verify] Creating /otsfiles/otsfile-$$.ots" + echo "${base64otsfile}" > /otsfiles/otsfile-$$.ots + trace "[verify] ots-cli.js verify -d ${hash} /otsfiles/otsfile-$$.ots" + result=$(ots-cli.js verify -d ${hash} /otsfiles/otsfile-$$.ots 2>&1) + returncode=$? + trace_rc ${returncode} + trace "[verify] result=${result}" + + # /script $ ots-cli.js -v v -d 7d694f669d6da235a5fb9ef8c89da55e30b59eb662a7131f85344d798fc3280c /otsfiles/Order_10019_1543447088465.ots + # Assuming target hash is '7d694f669d6da235a5fb9ef8c89da55e30b59eb662a7131f85344d798fc3280c' + # Success! Bitcoin block 551876 attests existence as of 2018-11-28 GMT + + # /script $ ots-cli.js -v v -d 7d694f669d6da235a5fb9ef8c89da55e30b59eb662a7131f85344d798fc3280c /otsfiles/Order_10019_1543447088465_incomplete.ots + # Assuming target hash is '7d694f669d6da235a5fb9ef8c89da55e30b59eb662a7131f85344d798fc3280c' + # Got 1 attestation(s) from https://bob.btc.calendar.opentimestamps.org + # Got 1 attestation(s) from https://finney.calendar.eternitywall.com + # Got 1 attestation(s) from https://alice.btc.calendar.opentimestamps.org + # Got 1 attestation(s) from https://btc.calendar.catallaxy.com + # Success! Bitcoin block 551876 attests existence as of 2018-11-28 GMT + + # /script # ots-cli.js -v v -d 3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d531 aaa + # Assuming target hash is '3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d531' + # Calendar https://btc.calendar.catallaxy.com: Pending confirmation in Bitcoin blockchain + # Calendar https://alice.btc.calendar.opentimestamps.org: Pending confirmation in Bitcoin blockchain + # Calendar https://bob.btc.calendar.opentimestamps.org: Pending confirmation in Bitcoin blockchain + # Calendar https://finney.calendar.eternitywall.com: Pending confirmation in Bitcoin blockchain + + # /script # ots-cli.js -v v -d 3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d531 allo + # Assuming target hash is '3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d531' + # Error! allo is not a timestamp file. + + # /script # ots-cli.js -v v -d 3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d53 aaa + # Assuming target hash is '3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d53' + # Expected digest 3eb3df18d9f8ee502c77f3b231818988c2c1cd44baa39e663d14708a7053d531 + # File does not match original! + # File does not match original! + + # Let's send one of those possible outcomes: + # - If last line begins with "Success!": Success + block height + # - If "Pending confirmation in Bitcoin blockchain" found: Pending + # - Otherwise: Error + + # - Error! allo is not a timestamp file. + # - File does not match original! + # - Whatever the last line output is + + data="{\"method\":\"verify\",\"hash\":\"${hash}\",\"result\":\"" + + trace "[verify] grepping..." + echo "${result}" | grep "Success!" > /dev/null + returncode=$? + trace_rc ${returncode} + + if [ "${returncode}" -eq "0" ]; then + # String found + data="${data}success\"}" + else + # String not found + data="${data}error\",\"error\":\"${result}\"}" + fi + + trace "[verify] data=${data}" + + echo "${data}" + + return ${returncode} +} diff --git a/otsclient_docker/script/requesthandler.sh b/otsclient_docker/script/requesthandler.sh index 23c1614..22c72f7 100644 --- a/otsclient_docker/script/requesthandler.sh +++ b/otsclient_docker/script/requesthandler.sh @@ -10,76 +10,84 @@ main() { - trace "Entering main()..." + trace "Entering main()..." - local step=0 - local cmd - local http_method - local line - local content_length - local response - local returncode + local step=0 + local cmd + local http_method + local line + local content_length + local response + local returncode - while read line; do - line=$(echo "${line}" | tr -d '\r\n') - trace "[main] line=${line}" + while read line; do + line=$(echo "${line}" | tr -d '\r\n') + trace "[main] line=${line}" - if [ "${cmd}" = "" ]; then - # First line! - # Looking for something like: - # GET /cmd/params HTTP/1.1 - # POST / HTTP/1.1 - cmd=$(echo "${line}" | cut -d '/' -f2 | cut -d ' ' -f1) - trace "[main] cmd=${cmd}" - http_method=$(echo "${line}" | cut -d ' ' -f1) - trace "[main] http_method=${http_method}" - if [ "${http_method}" = "GET" ]; then - step=1 - fi - fi - if [ "${line}" = "" ]; then - trace "[main] empty line" - if [ ${step} -eq 1 ]; then - trace "[main] body part finished, disconnecting" - break - else - trace "[main] headers part finished, body incoming" - step=1 - fi - fi - # line=content-length: 406 - case "${line}" in *[cC][oO][nN][tT][eE][nN][tT]-[lL][eE][nN][gG][tT][hH]*) - content_length=$(echo "${line}" | cut -d ':' -f2) - trace "[main] content_length=${content_length}"; - ;; - esac - if [ ${step} -eq 1 ]; then - trace "[main] step=${step}" - if [ "${http_method}" = "POST" ]; then - read -n ${content_length} line - trace "[main] line=${line}" - fi - case "${cmd}" in - stamp) - # GET http://192.168.111.152:8080/stamp/1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7 + if [ "${cmd}" = "" ]; then + # First line! + # Looking for something like: + # GET /cmd/params HTTP/1.1 + # POST / HTTP/1.1 + cmd=$(echo "${line}" | cut -d '/' -f2 | cut -d ' ' -f1) + trace "[main] cmd=${cmd}" + http_method=$(echo "${line}" | cut -d ' ' -f1) + trace "[main] http_method=${http_method}" + if [ "${http_method}" = "GET" ]; then + step=1 + fi + fi + if [ "${line}" = "" ]; then + trace "[main] empty line" + if [ ${step} -eq 1 ]; then + trace "[main] body part finished, disconnecting" + break + else + trace "[main] headers part finished, body incoming" + step=1 + fi + fi + # line=content-length: 406 + case "${line}" in *[cC][oO][nN][tT][eE][nN][tT]-[lL][eE][nN][gG][tT][hH]*) + content_length=$(echo "${line}" | cut -d ':' -f2) + trace "[main] content_length=${content_length}"; + ;; + esac + if [ ${step} -eq 1 ]; then + trace "[main] step=${step}" + if [ "${http_method}" = "POST" ]; then + read -n ${content_length} line + trace "[main] line=${line}" + fi + case "${cmd}" in + stamp) + # GET http://192.168.111.152:8080/stamp/1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7 - response=$(stamp $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)) - response_to_client "${response}" ${?} - break - ;; - upgrade) - # GET http://192.168.111.152:8080/upgrade/1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7 + response=$(stamp $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)) + response_to_client "${response}" ${?} + break + ;; + upgrade) + # GET http://192.168.111.152:8080/upgrade/1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7 - response=$(upgrade $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)) - response_to_client "${response}" ${?} - break - ;; - esac - break - fi - done - trace "[main] exiting" - return 0 + response=$(upgrade $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)) + response_to_client "${response}" ${?} + break + ;; + verify) + # POST http://192.168.111.152:8080/verify + # BODY {"hash":"1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7","base64otsfile":"AE9wZW5UaW1lc3RhbXBzAABQcm9vZ...gABYiWDXPXGQEDxNch"} + + response=$(verify "${line}") + response_to_client "${response}" ${?} + break + ;; + esac + break + fi + done + trace "[main] exiting" + return 0 } export TRACING diff --git a/otsclient_docker/script/responsetoclient.sh b/otsclient_docker/script/responsetoclient.sh index 6203950..ee2ab28 100644 --- a/otsclient_docker/script/responsetoclient.sh +++ b/otsclient_docker/script/responsetoclient.sh @@ -2,21 +2,23 @@ . ./trace.sh -response_to_client() -{ - trace "Entering response_to_client()..." +response_to_client() { + trace "Entering response_to_client()..." - local response=${1} - local returncode=${2} - local length=$(echo -n "${response}" | wc -c) + local response=${1} + local returncode=${2} + local contenttype=${3} + local length=$(echo -en "${response}" | wc -c) - ([ -z "${returncode}" ] || [ "${returncode}" -eq "0" ]) && echo -ne "HTTP/1.1 200 OK\r\n" - [ -n "${returncode}" ] && [ "${returncode}" -ne "0" ] && echo -ne "HTTP/1.1 400 Bad Request\r\n" + [ -z "${contenttype}" ] && contenttype="application/json" - echo -e "Content-Type: application/json\r\nContent-Length: ${length}\r\n\r\n${response}" + ([ -z "${returncode}" ] || [ "${returncode}" -eq "0" ]) && echo -ne "HTTP/1.1 200 OK\r\n" + [ -n "${returncode}" ] && [ "${returncode}" -ne "0" ] && echo -ne "HTTP/1.1 400 Bad Request\r\n" - # Small delay needed for the data to be processed correctly by peer - sleep 0.2s + echo -en "Content-Type: ${contenttype}\r\nContent-Length: ${length}\r\n\r\n${response}" + + # Small delay needed for the data to be processed correctly by peer + sleep 1 } case "${0}" in *responsetoclient.sh) response_to_client $@;; esac diff --git a/proxy_docker/app/script/ots.sh b/proxy_docker/app/script/ots.sh index 813b926..d30ca04 100644 --- a/proxy_docker/app/script/ots.sh +++ b/proxy_docker/app/script/ots.sh @@ -84,6 +84,7 @@ request_ots_stamp() { local errorstring trace "[request_ots_stamp] Stamping..." + trace "[request_ots_stamp] curl -s ${OTSCLIENT_CONTAINER}/stamp/${hash}" result=$(curl -s ${OTSCLIENT_CONTAINER}/stamp/${hash}) returncode=$? trace_rc ${returncode} @@ -229,3 +230,60 @@ serve_ots_getfile() { return ${returncode} } + +serve_ots_verify() { + + trace "Entering serve_ots_verify()..." + + local request=${1} + local hash=$(echo "${request}" | jq ".hash" | tr -d '"') + trace "[serve_ots_verify] hash=${hash}" + local base64otsfile=$(echo "${request}" | jq ".base64otsfile" | tr -d '"') + trace "[serve_ots_verify] base64otsfile=${base64otsfile}" + + local result + local returncode + + result=$(request_ots_verify "${hash}" "${base64otsfile}") + returncode=$? + trace_rc ${returncode} + + result="{\"method\":\"ots_verify\",\"hash\":\"${hash}\",\"result\":\"${result}\"}" + + trace "[serve_ots_verify] result=${result}" + + # Output response to stdout before exiting with return code + echo "${result}" + + return ${returncode} +} + +request_ots_verify() { + # Request the OTS server to verify + + local hash=${1} + trace "[request_ots_verify] hash=${hash}" + local base64otsfile=${2} + trace "[request_ots_verify] base64otsfile=${base64otsfile}" + local returncode + local result + local data + + # BODY {"hash":"1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7","base64otsfile":"AE9wZW5UaW1lc3RhbXBzAABQcm9vZ...gABYiWDXPXGQEDxNch"} + data="{\"hash\":\"${hash}\",\"base64otsfile\":\"${base64otsfile}\"}" + trace "[request_ots_verify] data=${data}" + + trace "[request_ots_verify] Verifying..." + trace "[request_ots_stamp] curl -s -d \"${data}\" ${OTSCLIENT_CONTAINER}/verify" + result=$(curl -s -d "${data}" ${OTSCLIENT_CONTAINER}/verify) + returncode=$? + trace_rc ${returncode} + trace "[request_ots_verify] Verifying result=${result}" + + if [ "${returncode}" -ne 0 ]; then + trace "[request_ots_verify] Verifying error" + fi + + echo "${result}" + return ${returncode} +} diff --git a/proxy_docker/app/script/requesthandler.sh b/proxy_docker/app/script/requesthandler.sh index 8ddcd37..f5becaa 100644 --- a/proxy_docker/app/script/requesthandler.sh +++ b/proxy_docker/app/script/requesthandler.sh @@ -395,6 +395,14 @@ main() { serve_ots_getfile $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3) break ;; + ots_verify) + # POST http://192.168.111.152:8080/ots_verify + # BODY {"hash":"1ddfb769eb0b8876bc570e25580e6a53afcf973362ee1ee4b54a807da2e5eed7","base64otsfile":"AE9wZW5UaW1lc3RhbXBzAABQcm9vZ...gABYiWDXPXGQEDxNch"} + + response=$(serve_ots_verify "${line}") + response_to_client "${response}" ${?} + break + ;; esac break fi