test_iban.sh (13767B)
1 #!/bin/bash 2 # This file is in the public domain. 3 4 set -eu 5 #set -x 6 7 # Exit, with status code "skip" (no 'real' failure) 8 function exit_skip() { 9 echo " SKIP: $1" 10 exit 77 11 } 12 13 # Exit, with error message (hard failure) 14 function exit_fail() { 15 echo " FAIL: $1" 16 exit 1 17 } 18 19 # Cleanup to run whenever we exit 20 function cleanup() 21 { 22 for n in $(jobs -p) 23 do 24 kill "$n" 2> /dev/null || true 25 done 26 rm -rf "$CONF" "$BANK_CONF" "$R1FILE" "$R2FILE" "$B1FILE" "$B2FILE" 27 wait 28 } 29 30 31 function sync_providers() { 32 infile="$1" 33 outfile="$2" 34 echo "Synchronizing providers" 35 # Sync with providers (up to 3 providers aren't synced here) 36 for x in 1 2 3; do 37 echo "Synchronizing providers (round $x)" 38 anastasis-reducer sync_providers < "$infile" > "$outfile" 2> /dev/null || true 39 CODE=$(jq -r -e ".code // 0" < $outfile) 40 # ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED 41 # FIXME: Temporary workaround for C reducer. See #7227. 42 if [ "$CODE" = "8420" ] 43 then 44 # restore previous non-error state 45 cp "$infile" "$outfile" 46 break 47 fi 48 # ANASTASIS_REDUCER_ACTION_INVALID 49 if [ "$CODE" = "8400" ] 50 then 51 # restore previous non-error state 52 cp "$infile" "$outfile" 53 break 54 fi 55 if [ "$CODE" != "0" ] 56 then 57 exit_fail "Expected no error or 8420/8400, got $CODE" 58 fi 59 cp "$outfile" "$infile" 60 done 61 echo "Providers synced." 62 } 63 64 65 # Install cleanup handler (except for kill -9) 66 trap cleanup EXIT 67 68 69 # Transfer funds from the customer's account to the Anastasis account. 70 # $1 = amount ($CURRENCY:X.Y), $2 = subject. 71 function wire_transfer_to_anastasis() { 72 echo -n "Initiating wire transfer ..." 73 curl -s -X POST \ 74 --user "${DEBIT_USERNAME}:${DEBIT_PASSWORD}" \ 75 -H "Content-Type: application/json" \ 76 -d "{\"payto_uri\":\"${PAYTO_CREDIT}&message=$(echo -n "$2" | jq -sRr @uri)&amount=$1\"}" \ 77 "${BANK_URL}accounts/${DEBIT_USERNAME}/transactions" \ 78 > libeufin-transfer.out 79 echo " OK" 80 } 81 82 # Merely a debug utility: show what Anastasis sees on the credit account. 83 function see_anastasis_transactions() { 84 curl -s --user "${CREDIT_USERNAME}:${CREDIT_PASSWORD}" \ 85 "${BANK_URL}accounts/${CREDIT_USERNAME}/taler-revenue/history?limit=5" | jq 86 } 87 88 # Configuration file will be edited, so we create one 89 # from the template. 90 CONF=$(mktemp test_free_reducerXXXXXX.conf) 91 cp test_free_reducer.conf "$CONF" 92 BANK_CONF=$(mktemp test_iban_bankXXXXXX.conf) 93 94 95 96 B1FILE=$(mktemp test_reducer_stateB1XXXXXX) 97 B2FILE=$(mktemp test_reducer_stateB2XXXXXX) 98 R1FILE=$(mktemp test_reducer_stateR1XXXXXX) 99 R2FILE=$(mktemp test_reducer_stateR2XXXXXX) 100 101 export CONF 102 export B2FILE 103 export B1FILE 104 export R2FILE 105 export R1FILE 106 107 echo -n "Testing for libeufin-bank" 108 libeufin-bank --help > /dev/null || exit_skip "libeufin-bank required" 109 echo " FOUND" 110 111 echo -n "Testing for curl" 112 curl --version > /dev/null || exit_skip "curl required" 113 echo " FOUND" 114 115 # Check we can actually run 116 echo -n "Testing for jq" 117 jq -h > /dev/null || exit_skip "jq required" 118 echo " FOUND" 119 echo -n "Testing for anastasis-reducer ..." 120 anastasis-reducer -h > /dev/null || exit_skip "anastasis-reducer required" 121 echo " FOUND" 122 123 echo -n "Initialize Anastasis database ..." 124 # Name of the Postgres database we will use for the script. 125 # Will be dropped, do NOT use anything that might be used 126 # elsewhere 127 128 TARGET_DB=$(anastasis-config -c "$CONF" -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///") 129 130 dropdb "$TARGET_DB" >/dev/null 2>/dev/null || true 131 createdb "$TARGET_DB" || exit_skip "Could not create database $TARGET_DB" 132 anastasis-dbinit -c "$CONF" 2> anastasis-dbinit.log 133 134 echo " OK" 135 136 137 CURRENCY="EUR" 138 BANK_DB=anastasisbankcheck 139 BANK_PORT=8092 140 BANK_URL="http://localhost:${BANK_PORT}/" 141 # Both IBANs have to pass the IBAN checksum, libeufin-bank rejects the rest. 142 export IBAN_CREDIT="DE89370400440532013000" 143 export IBAN_DEBIT="FR1420041010050500013M02606" 144 PERSON_CREDIT_NAME="Person Credit" 145 CREDIT_USERNAME=anastasis-credit-user 146 CREDIT_PASSWORD=anastasis-credit-password 147 DEBIT_USERNAME=anastasis-debit-user 148 DEBIT_PASSWORD=anastasis-debit-password 149 PAYTO_CREDIT="payto://iban/${IBAN_CREDIT}?receiver-name=Person+Credit" 150 PAYTO_DEBIT="payto://iban/${IBAN_DEBIT}?receiver-name=Person+Debit" 151 152 echo -n "Configuring bank ..." 153 cat > "$BANK_CONF" <<EOF 154 # Generated by test_iban.sh 155 [libeufin-bank] 156 CURRENCY = ${CURRENCY} 157 BASE_URL = ${BANK_URL} 158 SERVE = tcp 159 PORT = ${BANK_PORT} 160 WIRE_TYPE = iban 161 IBAN_PAYTO_BIC = SANDBOXX 162 DEFAULT_CUSTOMER_DEBT_LIMIT = ${CURRENCY}:200 163 DEFAULT_ADMIN_DEBT_LIMIT = ${CURRENCY}:2000 164 ALLOW_REGISTRATION = YES 165 # keep the test fast 166 PWD_HASH_CONFIG = { "cost": 4 } 167 # the Anastasis IBAN helper authenticates with HTTP basic auth 168 PWD_AUTH_COMPAT = yes 169 170 [libeufin-bankdb-postgres] 171 CONFIG = postgres:///${BANK_DB} 172 EOF 173 dropdb "$BANK_DB" >/dev/null 2>/dev/null || true 174 createdb "$BANK_DB" || exit_skip "Could not create database $BANK_DB" 175 libeufin-bank dbinit -c "$BANK_CONF" &> libeufin-bank-dbinit.log 176 echo " OK" 177 178 echo -n "Starting bank ..." 179 libeufin-bank serve -c "$BANK_CONF" &> libeufin-bank.log & 180 OK=0 181 for n in $(seq 1 50) 182 do 183 sleep 0.2 184 wget --tries=1 --timeout=1 "${BANK_URL}config" \ 185 -o /dev/null -O /dev/null >/dev/null || continue 186 OK=1 187 break 188 done 189 if [ 1 != $OK ] 190 then 191 exit_skip "Could not launch libeufin-bank" 192 fi 193 echo " OK" 194 195 echo -n "Preparing accounts ..." 196 libeufin-bank create-account -c "$BANK_CONF" \ 197 -u "$CREDIT_USERNAME" -p "$CREDIT_PASSWORD" \ 198 --name "$PERSON_CREDIT_NAME" \ 199 --payto_uri "$PAYTO_CREDIT" > /dev/null 200 libeufin-bank create-account -c "$BANK_CONF" \ 201 -u "$DEBIT_USERNAME" -p "$DEBIT_PASSWORD" \ 202 --name "Person Debit" \ 203 --payto_uri "$PAYTO_DEBIT" > /dev/null 204 # the customer has to be able to send money it does not have 205 libeufin-bank edit-account -c "$BANK_CONF" \ 206 --debit_threshold="${CURRENCY}:1000" \ 207 "$DEBIT_USERNAME" > /dev/null 208 echo " OK" 209 210 echo -n "Configuring Anastasis IBAN account ..." 211 anastasis-config -c "$CONF" \ 212 -s authorization-iban \ 213 -o CURRENCY \ 214 -V "${CURRENCY}" 215 anastasis-config -c "$CONF" \ 216 -s authorization-iban \ 217 -o CREDIT_IBAN \ 218 -V "${IBAN_CREDIT}" 219 anastasis-config -c "$CONF" \ 220 -s authorization-iban \ 221 -o BUSINESS_NAME \ 222 -V "${PERSON_CREDIT_NAME}" 223 anastasis-config -c "$CONF" \ 224 -s authorization-iban \ 225 -o WIRE_GATEWAY_URL \ 226 -V "${BANK_URL}accounts/${CREDIT_USERNAME}/taler-revenue/" 227 anastasis-config -c "$CONF" \ 228 -s authorization-iban \ 229 -o WIRE_GATEWAY_AUTH_METHOD \ 230 -V "basic" 231 anastasis-config -c "$CONF" \ 232 -s authorization-iban \ 233 -o USERNAME \ 234 -V "${CREDIT_USERNAME}" 235 anastasis-config -c "$CONF" \ 236 -s authorization-iban \ 237 -o PASSWORD \ 238 -V "${CREDIT_PASSWORD}" 239 echo " OK" 240 241 echo -n "Launching Anastasis service ..." 242 PREFIX="" #valgrind 243 $PREFIX anastasis-httpd -c "$CONF" -L INFO 2> anastasis-httpd_1.log & 244 echo " OK" 245 246 echo -n "Waiting for Anastasis service ..." 247 # Wait for Anastasis service to be available 248 for n in $(seq 1 50) 249 do 250 echo -n "." 251 sleep 0.1 252 OK=0 253 # anastasis_01 254 wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue 255 OK=1 256 break 257 done 258 if [ 1 != $OK ] 259 then 260 exit_skip "Failed to launch Anastasis service" 261 fi 262 echo "OK" 263 264 echo -n "Running backup logic ...," 265 anastasis-reducer -b > "$B1FILE" 266 echo -n "." 267 anastasis-reducer -a \ 268 '{"continent": "Demoworld"}' \ 269 select_continent < "$B1FILE" > "$B2FILE" 270 echo -n "." 271 anastasis-reducer -a \ 272 '{"country_code": "xx" }' \ 273 select_country < "$B2FILE" > "$B1FILE" 2>> test_reducer.err 274 echo -n "." 275 276 anastasis-reducer -a \ 277 '{"identity_attributes": { 278 "full_name": "Max Musterman", 279 "sq_number": "4", 280 "birthdate": "2000-01-01"}}' \ 281 enter_user_attributes < "$B1FILE" > "$B2FILE" 2>> test_reducer.err 282 echo -n "," 283 cat "$B2FILE" > "$B1FILE" 284 sync_providers "$B1FILE" "$B2FILE" 285 echo -n "," 286 BASEIBAN=$(echo -n $IBAN_DEBIT | gnunet-base32) 287 anastasis-reducer -a \ 288 "$(jq -n '{ authentication_method: { 289 type: "iban", 290 instructions: "Send me your money!", 291 challenge: $CHALLENGE 292 } }' \ 293 --arg CHALLENGE "$BASEIBAN" 294 )" \ 295 add_authentication < "$B2FILE" > "$B1FILE" 2>> test_reducer.err 296 echo -n "." 297 298 # "91GPWWR" encodes "Hans" 299 anastasis-reducer -a \ 300 '{"authentication_method": { 301 "type": "question", 302 "instructions": "What is your name?", 303 "challenge": "91GPWWR" 304 } }' \ 305 add_authentication < "$B1FILE" > "$B2FILE" 2>> test_reducer.err 306 echo -n "." 307 308 mv "$B2FILE" "$B1FILE" 309 310 # Finished adding authentication methods 311 anastasis-reducer \ 312 next < "$B1FILE" > "$B2FILE" 2>> test_reducer.err 313 314 echo -n "," 315 # Finished policy review 316 anastasis-reducer \ 317 next < "$B2FILE" > "$B1FILE" 2>> test_reducer.err 318 echo -n "." 319 # Note: 'secret' must here be a Crockford base32-encoded value 320 anastasis-reducer -a \ 321 '{"secret": { "value" : "VERYHARDT0GVESSSECRET", "mime" : "text/plain" }}' \ 322 enter_secret < "$B1FILE" > "$B2FILE" 2>> test_reducer.err 323 mv "$B2FILE" "$B1FILE" 324 anastasis-reducer next < "$B1FILE" > "$B2FILE" 2>> test_reducer.err 325 echo " OK" 326 327 echo -n "Final backup checks ..." 328 STATE=$(jq -r -e .backup_state < "$B2FILE") 329 if [ "$STATE" != "BACKUP_FINISHED" ] 330 then 331 exit_fail "Expected new state to be 'BACKUP_FINISHED', got '$STATE'" 332 fi 333 jq -r -e .core_secret < "$B2FILE" > /dev/null && exit_fail "'core_secret' was not cleared upon success" 334 echo " OK" 335 336 echo -n "Running recovery basic logic ..." 337 anastasis-reducer -r > "$R1FILE" 338 anastasis-reducer -a \ 339 '{"continent": "Demoworld"}' \ 340 select_continent < "$R1FILE" > "$R2FILE" 341 anastasis-reducer -a \ 342 '{"country_code": "xx", 343 "currencies":["TESTKUDOS"]}' \ 344 select_country < "$R2FILE" > "$R1FILE" 2>> test_reducer.err 345 anastasis-reducer -a '{"identity_attributes": { "full_name": "Max Musterman", "sq_number": "4", "birthdate": "2000-01-01" }}' enter_user_attributes < "$R1FILE" > "$R2FILE" 2>> test_reducer.err 346 347 348 STATE=$(jq -r -e .recovery_state < "$R2FILE") 349 if [ "$STATE" != "SECRET_SELECTING" ] 350 then 351 exit_fail "Expected new state to be 'SECRET_SELECTING', got '$STATE'" 352 fi 353 echo " OK" 354 355 echo -n "Adding provider (to ensure it is loaded)" 356 anastasis-reducer -a '{"provider_url" : "http://localhost:8086/" }' add_provider < "$R2FILE" > "$R1FILE" 357 echo " OK" 358 359 echo -n "Selecting secret to recover" 360 anastasis-reducer -a '{"attribute_mask": 0, "providers" : [ { "version": 1, "url" : "http://localhost:8086/" } ] }' \ 361 select_version < "$R1FILE" > "$R2FILE" 2>> test_reducer.err 362 363 STATE=$(jq -r -e .recovery_state < "$R2FILE") 364 if [ "$STATE" != "CHALLENGE_SELECTING" ] 365 then 366 exit_fail "Expected new state to be 'CHALLENGE_SELECTING', got '$STATE'" 367 fi 368 echo " OK" 369 370 cp "$R2FILE" "$R1FILE" 371 sync_providers "$R1FILE" "$R2FILE" 372 373 echo -n "Running challenge selection logic ..." 374 375 UUID0=$(jq -r -e .recovery_information.challenges[0].uuid < "$R2FILE") 376 UUID1=$(jq -r -e .recovery_information.challenges[1].uuid < "$R2FILE") 377 UUID0Q=$(jq -r -e .recovery_information.challenges[0].instructions < "$R2FILE") 378 UUID1Q=$(jq -r -e .recovery_information.challenges[1].instructions < "$R2FILE") 379 380 if [ "$UUID1Q" = 'What is your name?' ] 381 then 382 NAME_UUID=$UUID1 383 IBAN_UUID=$UUID0 384 else 385 NAME_UUID=$UUID0 386 IBAN_UUID=$UUID1 387 fi 388 389 echo "OK" 390 echo -n "Solving first challenge ..." 391 anastasis-reducer -a \ 392 "$(jq -n ' 393 { 394 uuid: $UUID 395 }' \ 396 --arg UUID "$NAME_UUID" 397 )" \ 398 select_challenge < "$R2FILE" > "$R1FILE" 2>> test_reducer.err 399 400 anastasis-reducer -a '{"answer": "Hans"}' \ 401 solve_challenge < "$R1FILE" > "$R2FILE" 402 403 echo "OK" 404 echo -n "Solving IBAN challenge ..." 405 406 anastasis-reducer -a \ 407 "$(jq -n ' 408 { 409 uuid: $UUID 410 }' \ 411 --arg UUID "$IBAN_UUID" 412 )" \ 413 select_challenge < "$R2FILE" > "$R1FILE" 2>> test_reducer.err 414 echo "OK" 415 416 417 METHOD=$(jq -r -e .challenge_feedback.\"$IBAN_UUID\".state < "$R1FILE") 418 if [ "$METHOD" != "iban-instructions" ] 419 then 420 exit_fail "Expected method to be 'iban-instructions', got ${METHOD}" 421 fi 422 423 ACC=$(jq -r -e .challenge_feedback.\"$IBAN_UUID\".target_iban < "$R1FILE") 424 if [ "$ACC" != "${IBAN_CREDIT}" ] 425 then 426 exit_fail "Expected account to be ${IBAN_CREDIT}, got ${ACC}" 427 fi 428 429 anastasis-reducer \ 430 back < "$R1FILE" > "$R2FILE" 2>> test_reducer.err 431 432 433 AMOUNT=$(jq -r -e .challenge_feedback.\"$IBAN_UUID\".challenge_amount < "$R1FILE") 434 SUBJECT=$(jq -r -e .challenge_feedback.\"$IBAN_UUID\".wire_transfer_subject < "$R1FILE") 435 436 echo -n "Performing authorization wire transfer ${SUBJECT} ..." 437 wire_transfer_to_anastasis "${AMOUNT}" "${SUBJECT}" 438 439 echo " OK" 440 441 echo -n "Triggering inbound check ..." 442 anastasis-helper-authorization-iban -c "$CONF" -t -L INFO 443 echo " OK" 444 445 # Now we should get the secret... 446 echo -n "Polling for recovery ..." 447 anastasis-reducer poll -L INFO < "$R2FILE" > "$R1FILE" 448 echo " OK" 449 450 echo -n "Checking recovered secret ..." 451 # finally: check here that we recovered the secret... 452 453 STATE=$(jq -r -e .recovery_state < "$R1FILE") 454 if [ "$STATE" != "RECOVERY_FINISHED" ] 455 then 456 jq -e . "$R1FILE" 457 exit_fail "Expected new state to be 'RECOVERY_FINISHED', got '$STATE'" 458 fi 459 460 SECRET=$(jq -r -e .core_secret.value < "$R1FILE") 461 if [ "$SECRET" != "VERYHARDT0GVESSSECRET" ] 462 then 463 jq -e . "$R1FILE" 464 exit_fail "Expected recovered secret to be 'VERYHARDT0GVESSSECRET', got '$SECRET'" 465 fi 466 467 MIME=$(jq -r -e .core_secret.mime < "$R1FILE") 468 if [ "$MIME" != "text/plain" ] 469 then 470 jq -e . "$R1FILE" 471 exit_fail "Expected recovered mime to be 'text/plain', got '$MIME'" 472 fi 473 474 echo " OK" 475 476 exit 0