#!/bin/bash # Configure merchant bank account credit facade for automatic settlement import. # # Root cause (2026-07-09): merchant wirewatch must call the **Taler Revenue API** # (`…/taler-revenue/`), not the exchange wire-gateway (`…/taler-wire-gateway/`). # On this bank, history endpoints accept **Bearer** tokens only (Basic → 401). # # Usage (as root on koopa host): # setup_credit_facade.sh # MERCHANT_INSTANCE=goa-demo-cp4zqk setup_credit_facade.sh # BANK_USER=… BANK_PW_FILE=… MERCHANT_PW_FILE=… setup_credit_facade.sh # # Effects: # - PATCH /instances/$INST/private/accounts/$H_WIRE with credit_facade_* # - long-lived refreshable bank token (1y) # - restarts taler-merchant-wirewatch (once, after facade is set) set -euo pipefail INST="${MERCHANT_INSTANCE:-goa-demo-cp4zqk}" BANK_USER="${BANK_USER:-$INST}" MERCHANT_PW_FILE="${MERCHANT_PW_FILE:-/root/merchant-${INST}-password.txt}" BANK_PW_FILE="${BANK_PW_FILE:-/root/bank-${BANK_USER}-password.txt}" MER_URL="${MERCHANT_URL:-https://127.0.0.1:9010}" BANK_URL="${BANK_URL:-http://127.0.0.1:9012}" PUBLIC_BANK="${PUBLIC_BANK_BASE:-https://bank.hacktivism.ch}" FACADE_URL="${CREDIT_FACADE_URL:-${PUBLIC_BANK}/accounts/${BANK_USER}/taler-revenue/}" if [ "$(id -un)" != "root" ]; then echo "run as root on koopa host" >&2 exit 1 fi if [ ! -r "$MERCHANT_PW_FILE" ] || [ ! -r "$BANK_PW_FILE" ]; then echo "need readable $MERCHANT_PW_FILE and $BANK_PW_FILE" >&2 exit 1 fi MPW=$(tr -d '\n' <"$MERCHANT_PW_FILE") BPW=$(tr -d '\n' <"$BANK_PW_FILE") AUTH="Authorization: Bearer secret-token:${MPW}" echo "=== bank token for $BANK_USER ===" TOK=$(curl -sS -u "${BANK_USER}:${BPW}" -H 'Content-Type: application/json' \ -d '{"scope":"readwrite","refreshable":true,"duration":{"d_us":31536000000000}}' \ "${BANK_URL}/accounts/${BANK_USER}/token" \ | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])') echo "tok_len=${#TOK}" echo "=== verify revenue history ===" code=$(curl -sS -m 15 -o /tmp/rev-check.json -w "%{http_code}" \ -H "Authorization: Bearer ${TOK}" \ "${BANK_URL}/accounts/${BANK_USER}/taler-revenue/history?delta=-3") echo "revenue_history_http=$code" python3 -c 'import json;d=json.load(open("/tmp/rev-check.json"));print("incoming",len(d.get("incoming_transactions")or[]))' [ "$code" = "200" ] || { echo "FAIL revenue history"; exit 1; } echo "=== PATCH credit_facade ($FACADE_URL) ===" H_WIRE=$(curl -sk -H "$AUTH" "${MER_URL}/instances/${INST}/private/accounts" \ | python3 -c 'import sys,json;print(json.load(sys.stdin)["accounts"][0]["h_wire"])') export FACADE_URL TOK BODY=$(python3 - <<'PY' import json, os print(json.dumps({ "credit_facade_url": os.environ["FACADE_URL"], "credit_facade_credentials": {"type": "bearer", "token": os.environ["TOK"]}, })) PY ) curl -sk -X PATCH -H "$AUTH" -H 'Content-Type: application/json' -d "$BODY" \ "${MER_URL}/instances/${INST}/private/accounts/${H_WIRE}" \ -w "PATCH_HTTP=%{http_code}\n" -o /dev/null echo "=== restart wirewatch in merchant container ===" su - hernani -c 'podman exec taler-hacktivism bash -c " set +e for p in \$(ps -eo pid=,args= | awk \"\\\$0 ~ /\\/usr\\/bin\\/taler-merchant-wirewatch/ {print \\\$1}\"); do kill \$p 2>/dev/null || true done sleep 1 runuser -u taler-merchant-httpd -- nohup /usr/bin/taler-merchant-wirewatch \ -c /etc/taler-merchant/taler-merchant.conf -L INFO \ >>/var/log/taler-merchant/wirewatch.log 2>&1 & sleep 2 ps -eo pid,etime,args | grep -E \"[t]aler-merchant-wirewatch\" || echo FAIL_no_wirewatch tail -8 /var/log/taler-merchant/wirewatch.log "' echo "=== private/transfers (sample) ===" curl -sk -H "$AUTH" "${MER_URL}/instances/${INST}/private/transfers" \ | python3 -c 'import sys,json;d=json.load(sys.stdin);t=d.get("transfers")or[];print("transfers",len(t))' echo OK_credit_facade