#!/bin/bash # This file is in the public domain. . initialize_taler_system.sh echo -n "First prepare wallet with coins..." rm $WALLET_DB taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api 'withdrawTestBalance' \ "$(jq -n ' { amount: "TESTKUDOS:99", bankBaseUrl: $BANK_URL, exchangeBaseUrl: $EXCHANGE_URL }' \ --arg BANK_URL "$BANK_URL" \ --arg EXCHANGE_URL "$EXCHANGE_URL" )" 2>wallet-withdraw-1.err >wallet-withdraw-1.out taler-wallet-cli --wallet-db=$WALLET_DB run-until-done 2>wallet-withdraw-finish-1.err >wallet-withdraw-finish-1.out echo " OK" # # CREATE INSTANCE FOR TESTING # echo -n "Configuring merchant instance ..." # create with 2 address STATUS=$(curl -H "Content-Type: application/json" -X POST \ -H 'Authorization: Bearer secret-token:super_secret' \ http://localhost:9966/private/instances \ -d '{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:8082/43","payto://x-taler-bank/localhost:8082/44"],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_ms" : 50000},"default_pay_delay":{"d_ms": 60000}}' \ -w "%{http_code}" -s -o /dev/null) if [ "$STATUS" != "204" ] then echo 'should respond ok, instance created. got:' $STATUS exit 1 fi # remove one account address STATUS=$(curl -H "Content-Type: application/json" -X PATCH \ -H 'Authorization: Bearer secret-token:super_secret' \ http://localhost:9966/instances/default/private/ \ -d '{"auth":{"method":"external"},"payto_uris":["payto://x-taler-bank/localhost:8082/43"],"id":"default","name":"default","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_ms" : 50000},"default_pay_delay":{"d_ms": 60000}}' \ -w "%{http_code}" -s -o /dev/null) if [ "$STATUS" != "204" ] then echo 'should respond ok, instance updated. got:' $STATUS exit 1 fi echo OK RANDOM_IMG='data:image/png;base64,abcdefg' # # CREATE AN ORDER WITHOUT TOKEN # echo -n "Creating order without TOKEN..." STATUS=$(curl 'http://localhost:9966/instances/default/private/orders' \ -d '{"create_token":false,"order":{"amount":"TESTKUDOS:7","summary":"3","products":[{"description":"desct","image":"'$RANDOM_IMG'","price":"TESTKUDOS:1","taxes":[],"unit":"u","quantity":1}]}}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order created. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_ID=`jq -r .order_id < $LAST_RESPONSE` TOKEN=`jq -r .token < $LAST_RESPONSE` if [ "$TOKEN" != "null" ] then echo 'token should be null, got:' $TOKEN fi STATUS=$(curl http://localhost:9966/orders/$ORDER_ID \ -w "%{http_code}" -s -o $LAST_RESPONSE) PAY_URI=`jq -r .taler_pay_uri < $LAST_RESPONSE` if [ "$PAY_URI" == "null" ] then echo 'should have a payuri. got:' $PAY_URI `cat $LAST_RESPONSE` exit 1 fi echo OK # # CREATE AN ORDER WITHOUT TOKEN WITH FULLFILMENT URL # echo -n "Creating order without TOKEN and fullfilment URL..." STATUS=$(curl 'http://localhost:9966/instances/default/private/orders' \ -d '{"create_token":false,"order":{"fulfillment_url":"go_here_please", "amount":"TESTKUDOS:7","summary":"3","products":[{"description":"desct","image":"'$RANDOM_IMG'","price":"TESTKUDOS:1","taxes":[],"unit":"u","quantity":1}]}}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order created. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_ID=`jq -r .order_id < $LAST_RESPONSE` TOKEN=`jq -r .token < $LAST_RESPONSE` if [ "$TOKEN" != "null" ] then echo 'token should be null, got:' $TOKEN fi STATUS=$(curl http://localhost:9966/orders/$ORDER_ID \ -w "%{http_code}" -s -o $LAST_RESPONSE) PAY_URI=`jq -r .taler_pay_uri < $LAST_RESPONSE` FULLFILMENT_URL=`jq -r .fulfillment_url < $LAST_RESPONSE` if [ "$FULLFILMENT_URL" != "go_here_please" ] then echo 'should have a payuri. got:' $PAY_URI `cat $LAST_RESPONSE` exit 1 fi if [ "$PAY_URI" == "null" ] then echo 'should have a payuri. got:' $PAY_URI `cat $LAST_RESPONSE` exit 1 fi echo OK # # CREATE ORDER WITH NON-INVENTORY AND CHECK # echo -n "Creating order with non-inventory products..." STATUS=$(curl 'http://localhost:9966/instances/default/private/orders' \ -d '{"order":{"amount":"TESTKUDOS:7","summary":"3","products":[{"description":"desct","image":"'$RANDOM_IMG'","price":"TESTKUDOS:1","taxes":[],"unit":"u","quantity":1}]}}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order created. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_ID=`jq -r .order_id < $LAST_RESPONSE` TOKEN=`jq -r .token < $LAST_RESPONSE` STATUS=$(curl http://localhost:9966/orders/$ORDER_ID/claim \ -d '{"nonce":"","token":"'$TOKEN'"}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order claimed. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi QUANTITY=`jq -r .contract_terms.products[0].quantity < $LAST_RESPONSE` if [ "$QUANTITY" != "1" ] then echo 'should get quantity 1. got:' $QUANTITY # `jq .contract_terms.products[0] < $LAST_RESPONSE` exit 1 fi IMAGE=`jq -r .contract_terms.products[0].image < $LAST_RESPONSE` if [ "$IMAGE" != "$RANDOM_IMG" ] then echo 'should get image but got something else. got:' $IMAGE exit 1 fi echo OK # # CREATE INVENTORY PRODUCT AND CLAIM IT # echo -n "Creating product..." STATUS=$(curl 'http://localhost:9966/instances/default/private/products' \ -d '{"product_id":"2","description":"product with id 2 and price :15","price":"TESTKUDOS:15","total_stock":2,"description_i18n":{},"unit":"","image":"'$RANDOM_IMG'","taxes":[],"address":{},"next_restock":{"t_ms":"never"}}' \ -w "%{http_code}" -s -o /dev/null) if [ "$STATUS" != "204" ] then echo 'should respond ok, product created. got:' $STATUS exit 1 fi echo OK echo -n "Creating order with inventory products..." STATUS=$(curl 'http://localhost:9966/instances/default/private/orders' \ -d '{"order":{"amount":"TESTKUDOS:7","summary":"3"},"inventory_products":[{"product_id":"2","quantity":1}]}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order created. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_ID=`jq -e -r .order_id < $LAST_RESPONSE` TOKEN=`jq -e -r .token < $LAST_RESPONSE` STATUS=$(curl http://localhost:9966/orders/$ORDER_ID/claim \ -d '{"nonce":"","token":"'$TOKEN'"}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order claimed. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi QUANTITY=`jq -r .contract_terms.products[0].quantity < $LAST_RESPONSE` if [ "$QUANTITY" != "1" ] then echo 'should get quantity 1. got:' $QUANTITY #`jq .contract_terms.products[0] < $LAST_RESPONSE` exit 1 fi echo "OK" # # CREATE INVALID ORDER # STATUS=$(curl 'http://localhost:9966/instances/default/private/products' \ -d '{"product_id":"1","description":"product with id 1 and price :15","price":"USD:15","total_stock":1,"description_i18n":{},"unit":"","image":"","taxes":[],"address":{},"next_restock":{"t_ms":"never"}}' \ -w "%{http_code}" -s -o /dev/null) if [ "$STATUS" != "409" ] then echo 'should respond conflict, product price is in another currency. got:' $STATUS exit 1 fi # # CREATE ORDER AND SELL IT # echo -n "Creating order to be paid..." STATUS=$(curl 'http://localhost:9966/instances/default/private/orders' \ -d '{"order":{"amount":"TESTKUDOS:1","summary":"payme"},"inventory_products":[{"product_id":"2","quantity":1}]}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, order created. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_ID=`jq -e -r .order_id < $LAST_RESPONSE` TOKEN=`jq -e -r .token < $LAST_RESPONSE` STATUS=$(curl "http://localhost:9966/instances/default/private/orders/${ORDER_ID}" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, getting order info before claming it. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi PAY_URL=`jq -e -r .taler_pay_uri < $LAST_RESPONSE` echo OK NOW=`date +%s` echo -n "Pay first order ..." taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB handle-uri "${PAY_URL}" -y 2> wallet-pay1.err > wallet-pay1.log NOW2=`date +%s` echo " OK (took $( echo -n $(($NOW2 - $NOW)) ) secs )" STATUS=$(curl "http://localhost:9966/instances/default/private/orders/${ORDER_ID}" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then echo 'should response ok, after pay. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi ORDER_STATUS=`jq -r .order_status < $LAST_RESPONSE` if [ "$ORDER_STATUS" != "paid" ] then echo 'order should be paid. got:' $ORDER_STATUS `cat $LAST_RESPONSE` exit 1 fi # # WIRE TRANSFER TO MERCHANT AND NOTIFY BACKEND # PAY_DEADLINE=`jq -r .contract_terms.pay_deadline.t_ms < $LAST_RESPONSE` WIRE_DEADLINE=`jq -r .contract_terms.wire_transfer_deadline.t_ms < $LAST_RESPONSE` NOW=`date +%s` TO_SLEEP=`echo $(( ($WIRE_DEADLINE /1000) - $NOW ))` echo waiting $TO_SLEEP secs for wire transfer echo -n "Perform wire transfers ..." taler-exchange-aggregator -c $CONF -T ${TO_SLEEP}000000 -t -L INFO &> aggregator.log taler-exchange-transfer -c $CONF -t -L INFO &> transfer.log echo " DONE" echo -n "Obtaining wire transfer details from bank..." # First, extract the wire transfer data from the bank. # As there is no "nice" API, we do this by dumping the # bank database and grabbing the 'right' wire transfer, # which is the one outgoing from the exchange (account 2). BANKDATA=`taler-bank-manage -c $CONF django dumpdata 2>/dev/null | tail -n1 | jq '.[] | select(.model=="app.banktransaction")' | jq 'select(.fields.debit_account==2)'` SUBJECT=`echo $BANKDATA | jq -r .fields.subject` WTID=`echo $SUBJECT | awk '{print $1}'` WURL=`echo $SUBJECT | awk '{print $2}'` CREDIT_AMOUNT=`echo $BANKDATA | jq -r .fields.amount` TARGET=`echo $BANKDATA | jq -r .fields.credit_account` # 'TARGET' is now the numeric value of the account, we need to get the actual account *name*: BANKADATA=`taler-bank-manage -c $CONF django dumpdata 2>/dev/null | tail -n1 | jq '.[] | select(.model=="auth.user")' | jq 'select(.pk=='$TARGET')'` ACCOUNT_NAME=`echo $BANKADATA | jq -r .fields.username` TARGET_PAYTO="payto://x-taler-bank/localhost:8082/$ACCOUNT_NAME" if [ "$EXCHANGE_URL" != "$WURL" ] then exit_fail "Wrong exchange URL in subject '$SUBJECT', expected $EXCHANGE_URL" fi echo " OK" set +e export TARGET_PAYTO export WURL export WTID export CREDIT_AMOUNT export LAST_RESPONSE echo -n "Notifying merchant of bogus wire transfer ..." STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'1","wtid":"'$WTID'","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -m 3 \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "409" ] then jq . < $LAST_RESPONSE exit_fail "Expected to fail since the amount is not valid. got: $STATUS" fi echo "OK" echo -n "Notifying merchant of bogus wire transfer AGAIN ..." STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'1","wtid":"'$WTID'","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -m 3 \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "409" ] then jq . < $LAST_RESPONSE exit_fail "Expected to fail since the amount is not valid. got: $STATUS" fi echo " OK" echo -n "Notifying merchant of correct wire transfer (conflicting with old data)..." STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'","wtid":"'$WTID'","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -m 3 \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "409" ] then jq . < $LAST_RESPONSE exit_fail "Expected response conflict, after providing conflicting transfer data. got: $STATUS" fi echo " OK" echo -n "Deleting bogus wire transfer ..." TID=`curl -s http://localhost:9966/instances/default/private/transfers | jq -r .transfers[0].transfer_serial_id` STATUS=$(curl -H "Content-Type: application/json" -X DELETE \ "http://localhost:9966/instances/default/private/transfers/$TID" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "204" ] then jq . < $LAST_RESPONSE exit_fail "Expected response 204 No Content, after deleting valid TID. got: $STATUS" fi STATUS=$(curl -H "Content-Type: application/json" -X DELETE \ "http://localhost:9966/instances/default/private/transfers/$TID" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "404" ] then jq . < $LAST_RESPONSE exit_fail "Expected response 404 Not found, after deleting TID again. got: $STATUS" fi echo " OK" echo -n "Notifying merchant of correct wire transfer (now working)..." STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'","wtid":"'$WTID'","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -m 3 \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then jq . < $LAST_RESPONSE exit_fail "Expected response ok, after providing transfer data. got: $STATUS" fi echo " OK" echo -n "Testing idempotence ..." set -e # Test idempotence: do it again! STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'","wtid":"'$WTID'","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then jq . < $LAST_RESPONSE exit_fail "Expected response ok, after providing transfer data. got: $STATUS" fi echo " OK" echo -n "Sending bogus WTID ..." # # CHECK TRANSFER API # STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'","wtid":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "502" ] then jq . < $LAST_RESPONSE exit_fail "Expected response invalid since the WTID is fake. got: $STATUS" fi echo "OK" echo -n "Fetching wire transfers ..." STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then jq . < $LAST_RESPONSE exit_fail "Expected response 200 Ok. got: $STATUS" fi TRANSFERS_LIST_SIZE=`jq -r '.transfers | length' < $LAST_RESPONSE` if [ "$TRANSFERS_LIST_SIZE" != "2" ] then jq . < $LAST_RESPONSE exit_fail "Expected response ok. got: $STATUS" fi echo "OK" echo -n "Fetching wire transfer details of bogus WTID ..." # Test for #6854: use a bogus WTID, causing the exchange to fail to # find the WTID. STATUS=$(curl 'http://localhost:9966/instances/default/private/transfers' \ -d '{"credit_amount":"'$CREDIT_AMOUNT'","wtid":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","payto_uri":"'$TARGET_PAYTO'","exchange_url":"'$WURL'"}' \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "502" ] then jq . < $LAST_RESPONSE exit_fail "Expected response invalid since the WTID is fake. got: $STATUS" fi echo " OK" echo -n "Checking order status ..." STATUS=$(curl "http://localhost:9966/instances/default/private/orders/${ORDER_ID}?transfer=YES" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then jq . < $LAST_RESPONSE exit_fail 'should response ok, after order inquiry. got:' $STATUS `cat $LAST_RESPONSE` exit 1 fi DEPOSIT_TOTAL=`jq -r .deposit_total < $LAST_RESPONSE` if [ "$DEPOSIT_TOTAL" == "TESTKUDOS:0" ] then echo 'deposit total is zero, expected greater than zero. got:' $DEPOSIT_TOTAL `cat $LAST_RESPONSE` exit 1 fi echo " OK" echo -n "Removing password from account 43 ..." taler-bank-manage -c $CONF --with-db postgres:///$TALER_DB django changepassword_unsafe 43 x >/dev/null 2>/dev/null ACCOUNT_PASSWORD="43:x" BANK_HOST="localhost:8082" STATUS=$(curl "http://$ACCOUNT_PASSWORD@$BANK_HOST/accounts/43" \ -w "%{http_code}" -s -o $LAST_RESPONSE) if [ "$STATUS" != "200" ] then jq . < $LAST_RESPONSE echo "Expected response 200 Ok, getting account status. Got: $STATUS" exit 1 fi BALANCE=`jq -r .balance.amount < $LAST_RESPONSE` if [ "$BALANCE" == "TESTKUDOS:0" ] then jq . < $LAST_RESPONSE echo "Wire transfer did not happen. Got: $BALANCE" exit 1 fi echo " OK" exit 0