generate-revoke-basedb.sh (12288B)
1 #!/bin/bash 2 # Script to test revocation. 3 # 4 # Requires the wallet CLI to be installed and in the path. Furthermore, the 5 # user running this script must be Postgres superuser and be allowed to 6 # create/drop databases. 7 # 8 set -eu 9 # set -x 10 11 # The revocation test depends on the wallet picking specific coins (it 12 # revokes the denomination of a particular coin), so coin selection has to 13 # be deterministic. See generate-auditor-basedb.sh and 14 # https://bugs.gnunet.org/view.php?id=11272. 15 export TALER_WALLET_COINSEL="legacy-2024" 16 17 . setup.sh 18 19 echo -n "Testing for curl ..." 20 curl --help >/dev/null </dev/null || exit_skip " MISSING" 21 echo " FOUND" 22 23 echo "Testing for taler-merchant-config" 24 taler-merchant-config -h > /dev/null || exit_skip "taler-merchant-config required" 25 echo "Testing for taler-merchant-httpd" 26 taler-merchant-httpd -h > /dev/null || exit_skip "taler-merchant-httpd required" 27 28 # reset database 29 echo -n "Reset 'auditor-basedb' database ..." 30 dropdb "auditor-basedb" >/dev/null 2>/dev/null || true 31 createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB'" 32 echo " DONE" 33 34 # Launch exchange, merchant and bank. 35 setup -c generate-auditor-basedb.conf \ 36 -abemw \ 37 -d "iban" 38 CONF="generate-auditor-basedb.conf.edited" 39 40 # obtain key configuration data 41 EXCHANGE_URL=$(taler-exchange-config -c "$CONF" -s EXCHANGE -o BASE_URL) 42 MERCHANT_PORT=$(taler-merchant-config -c "$CONF" -s MERCHANT -o PORT) 43 MERCHANT_URL="http://localhost:${MERCHANT_PORT}/" 44 BANK_PORT=$(taler-exchange-config -c "$CONF" -s BANK -o HTTP_PORT) 45 BANK_URL="http://localhost:${BANK_PORT}/" 46 47 48 # Setup merchant 49 export MERCHANT_URL 50 echo -n "Setting up merchant ..." 51 curl -H "Content-Type: application/json" -X POST -d '{"auth": {"method": "external"},"id":"admin","name":"admin","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000},"use_stefan":true}' "${MERCHANT_URL}management/instances" 52 echo " DONE" 53 54 echo -n "Setting up merchant account ..." 55 FORTYTHREE="payto://iban/DE12500105170648489890?receiver-name=Merchant43" 56 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 57 "${MERCHANT_URL}private/accounts" \ 58 -d '{"payto_uri":"'"$FORTYTHREE"'"}' \ 59 -w "%{http_code}" -s -o /dev/null) 60 if [ "$STATUS" != "200" ] 61 then 62 exit_fail "Expected 200 OK. Got: $STATUS" 63 fi 64 echo " DONE" 65 66 echo -n "Setting up libeufin merchant account ..." 67 libeufin-bank create-account \ 68 --config="${CONF}" \ 69 --name="Merchant43" \ 70 --username="Merchant43" \ 71 --password="password" \ 72 --payto_uri="payto://iban/DE12500105170648489890?receiver-name=Merchant43" 73 echo " DONE" 74 75 76 # run wallet CLI 77 echo "Running wallet" 78 79 export WALLET_DB="wallet.wdb" 80 rm -f "$WALLET_DB" 81 82 wlog="taler-wallet-cli-withdraw.log" 83 taler-wallet-cli \ 84 --no-throttle \ 85 --wallet-db="$WALLET_DB" \ 86 api \ 87 --expect-success 'withdrawTestBalance' \ 88 "$(jq -n ' 89 { 90 amount: "TESTKUDOS:8", 91 corebankApiBaseUrl: $BANK_URL, 92 exchangeBaseUrl: $EXCHANGE_URL, 93 }' \ 94 --arg BANK_URL "$BANK_URL" \ 95 --arg EXCHANGE_URL "$EXCHANGE_URL" 96 )" &> $wlog || { 97 echo " FAILED(withdraw)! Last entries in $wlog:" 98 tail $wlog 99 exit 2 100 } 101 102 taler-wallet-cli \ 103 --no-throttle \ 104 --wallet-db="$WALLET_DB" \ 105 run-until-done \ 106 &> taler-wallet-cli-withdraw-finish.log 107 108 export COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins) 109 110 echo -n "COINS are:" 111 echo "$COINS" 112 113 export COINS 114 # Find coin we want to revoke 115 export rc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .coinPub') 116 # Find the denom 117 export rd=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .denomPubHash') 118 119 # This database is all about recoup. The exchange implements the batch 120 # recoup protocol (POST /recoup-withdraw and /recoup-refresh, vRECOUP, see 121 # https://bugs.gnunet.org/view.php?id=9828), but taler-wallet-cli does not 122 # yet: after the revocation below the wallet would never recoup the coins of 123 # the revoked denomination and we would spin until the test times out. 124 # Remove this skip once wallet-core supports vRECOUP. 125 exit_skip "taler-wallet-cli does not implement the batch recoup protocol (vRECOUP, #9828) yet" 126 127 echo -n "Revoking denomination ${rd} (to affect coin ${rc}) ..." 128 # Find all other coins, which will be suspended 129 export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coinPub != $rc) | .coinPub]') 130 131 # Do the revocation 132 taler-exchange-offline \ 133 -c "$CONF" \ 134 revoke-denomination "${rd}" \ 135 upload \ 136 &> taler-exchange-offline-revoke.log 137 echo "DONE" 138 139 echo -n "Signing replacement keys ..." 140 sleep 1 # Give exchange time to create replacmenent key 141 142 # Re-sign replacement keys 143 taler-auditor-offline \ 144 -c "$CONF" \ 145 download \ 146 sign \ 147 upload \ 148 &> taler-auditor-offline-reinit.log 149 echo " DONE" 150 151 # Now we suspend the other coins, so later we will pay with the recouped coin 152 taler-wallet-cli \ 153 --wallet-db="$WALLET_DB" \ 154 advanced \ 155 suspend-coins "$susp" 156 157 # Update exchange /keys so recoup gets scheduled 158 taler-wallet-cli \ 159 --wallet-db="$WALLET_DB" \ 160 exchanges \ 161 update \ 162 -f "$EXCHANGE_URL" 163 164 # Block until scheduled operations are done 165 taler-wallet-cli \ 166 --wallet-db="$WALLET_DB"\ 167 run-until-done 168 169 # Now we buy something, only the coins resulting from recoup will be 170 # used, as other ones are suspended 171 taler-wallet-cli \ 172 --no-throttle \ 173 --wallet-db="$WALLET_DB" \ 174 api \ 175 'testPay' \ 176 "$(jq -n ' 177 { 178 amount: "TESTKUDOS:1", 179 merchantBaseUrl: $MERCHANT_URL, 180 summary: "foo", 181 }' \ 182 --arg MERCHANT_URL "$MERCHANT_URL" 183 )" 184 185 taler-wallet-cli \ 186 --wallet-db="$WALLET_DB" \ 187 run-until-done 188 189 echo "Purchase with recoup'ed coin (via reserve) done" 190 191 # Re-read the coins: the recoup and the purchase above changed the wallet's 192 # coin set, so the dump taken before the first revocation is stale. 193 COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins) 194 export COINS 195 196 # Find coin we want to refresh, then revoke 197 export rrc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .coinPub') 198 # Find the denom 199 export zombie_denom=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .denomPubHash') 200 201 echo "Will refresh coin ${rrc} of denomination ${zombie_denom}" 202 # Find all other coins, which will be suspended 203 export susp=$(echo "$COINS" | jq --arg rrc "$rrc" '[.coins[] | select(.coinPub != $rrc) | .coinPub]') 204 205 # Travel into the future! (must match DURATION_WITHDRAW option) 206 export TIMETRAVEL="--timetravel=604800000000" 207 208 echo "Launching exchange 1 week in the future" 209 # The exchange and its security modules were started by 210 # taler-unified-setup.sh, so we do not have their PIDs; stop them by name 211 # and bring them back up with the time offset applied. 212 for proc in taler-exchange-httpd \ 213 taler-exchange-secmod-rsa \ 214 taler-exchange-secmod-cs \ 215 taler-exchange-secmod-eddsa 216 do 217 pkill -x -u "$(id -u)" -TERM "$proc" || true 218 done 219 # Give them a moment to release their sockets 220 sleep 1 221 taler-exchange-secmod-eddsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log" & 222 SIGNKEY_HELPER_PID=$! 223 taler-exchange-secmod-rsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-rsa.log" & 224 RSA_DENOM_HELPER_PID=$! 225 taler-exchange-secmod-cs $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-cs.log" & 226 CS_DENOM_HELPER_PID=$! 227 export SIGNKEY_HELPER_PID RSA_DENOM_HELPER_PID CS_DENOM_HELPER_PID 228 taler-exchange-httpd $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-httpd.log" & 229 export EXCHANGE_PID=$! 230 231 # Wait for exchange to be available 232 OK=0 233 for n in `seq 1 100` 234 do 235 echo -n "." 236 sleep 0.2 237 # exchange 238 wget "${EXCHANGE_URL}config" -o /dev/null -O /dev/null >/dev/null || continue 239 OK=1 240 break 241 done 242 if [ 1 != "$OK" ] 243 then 244 exit_fail "Failed to restart exchange in the future" 245 fi 246 echo " DONE" 247 248 echo "Refreshing coin $rrc" 249 taler-wallet-cli \ 250 "$TIMETRAVEL" \ 251 --wallet-db="$WALLET_DB" \ 252 advanced force-refresh \ 253 "$rrc" 254 taler-wallet-cli \ 255 "$TIMETRAVEL" \ 256 --wallet-db="$WALLET_DB" \ 257 run-until-done 258 259 # Update our list of the coins 260 export coins=$(taler-wallet-cli "$TIMETRAVEL" --wallet-db="$WALLET_DB" advanced dump-coins) 261 262 # Find resulting refreshed coin 263 export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" \ 264 '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .coinPub' 265 ) 266 267 # Find the denom of freshc 268 export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" \ 269 '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .denomPubHash' 270 ) 271 272 echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh" 273 274 # Find all other coins, which will be suspended 275 export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coinPub != $freshc) | .coinPub]') 276 277 278 # Do the revocation of freshc 279 echo "Revoking ${fresh_denom} (to affect coin ${freshc})" 280 taler-exchange-offline \ 281 -c "$CONF" \ 282 revoke-denomination \ 283 "${fresh_denom}" \ 284 upload &> taler-exchange-offline-revoke-2.log 285 286 sleep 1 # Give exchange time to create replacmenent key 287 288 # Re-sign replacement keys 289 taler-auditor-offline \ 290 -c "$CONF" \ 291 download \ 292 sign \ 293 upload &> taler-auditor-offline.log 294 295 # Now we suspend the other coins, so later we will pay with the recouped coin 296 taler-wallet-cli \ 297 "$TIMETRAVEL" \ 298 --wallet-db="$WALLET_DB" \ 299 advanced \ 300 suspend-coins "$susp" 301 302 # Update exchange /keys so recoup gets scheduled 303 taler-wallet-cli \ 304 "$TIMETRAVEL"\ 305 --wallet-db="$WALLET_DB" \ 306 exchanges update \ 307 -f "$EXCHANGE_URL" 308 309 # Block until scheduled operations are done 310 taler-wallet-cli \ 311 "$TIMETRAVEL" \ 312 --wallet-db="$WALLET_DB" \ 313 run-until-done 314 315 echo "Restarting merchant (so new keys are known)" 316 pkill -x -u "$(id -u)" -TERM taler-merchant-httpd || true 317 sleep 1 318 taler-merchant-httpd \ 319 -c "$CONF" \ 320 -L INFO \ 321 2> ${MY_TMP_DIR}/taler-merchant-httpd.log & 322 MERCHANT_PID=$! 323 export MERCHANT_PID 324 325 # Wait for merchant to be again available 326 OK=0 327 for n in `seq 1 100` 328 do 329 echo -n "." 330 sleep 0.2 331 # merchant 332 wget "${MERCHANT_URL}config" -o /dev/null -O /dev/null >/dev/null || continue 333 OK=1 334 break 335 done 336 if [ 1 != "$OK" ] 337 then 338 exit_fail "Failed to restart merchant" 339 fi 340 echo " DONE" 341 342 # Now we buy something, only the coins resulting from recoup+refresh will be 343 # used, as other ones are suspended 344 taler-wallet-cli $TIMETRAVEL --no-throttle --wallet-db=$WALLET_DB api 'testPay' \ 345 "$(jq -n ' 346 { 347 amount: "TESTKUDOS:0.02", 348 merchantBaseUrl: $MERCHANT_URL, 349 summary: "bar", 350 }' \ 351 --arg MERCHANT_URL $MERCHANT_URL 352 )" 353 taler-wallet-cli \ 354 "$TIMETRAVEL" \ 355 --wallet-db="$WALLET_DB" \ 356 run-until-done 357 358 echo "Bought something with refresh-recouped coin" 359 360 echo "Shutting down services" 361 # Stop the exchange/merchant processes we restarted ourselves first: they 362 # are not children of taler-unified-setup.sh, so its teardown misses them 363 # and a bare 'wait' below would block forever. 364 for pid in "${EXCHANGE_PID:-}" \ 365 "${MERCHANT_PID:-}" \ 366 "${RSA_DENOM_HELPER_PID:-}" \ 367 "${CS_DENOM_HELPER_PID:-}" \ 368 "${SIGNKEY_HELPER_PID:-}" 369 do 370 if [ -n "$pid" ] 371 then 372 kill -TERM "$pid" 2> /dev/null || true 373 wait "$pid" 2> /dev/null || true 374 fi 375 done 376 exit_cleanup 377 unset SETUP_PID 378 379 380 # Where do we write the result? 381 export BASEDB=${1:-"revoke-basedb"} 382 383 384 # Dump database 385 mkdir -p "$(dirname "$BASEDB")" 386 echo "Dumping database ${BASEDB}.sql" 387 pg_dump -O "auditor-basedb" | sed -e '/AS integer/d' > "${BASEDB}.sql" 388 cp "${CONF}" "${BASEDB}.conf" 389 cp "$(taler-exchange-config -c "${CONF}" -s exchange-offline -o MASTER_PRIV_FILE -f)" "${BASEDB}.mpriv" 390 391 # clean up 392 echo -n "Final clean up ..." 393 dropdb "auditor-basedb" 394 echo " DONE" 395 396 echo "=====================================" 397 echo "Finished generation of ${BASEDB}.sql" 398 echo "=====================================" 399 400 exit 0