anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

test_anastasis_reducer_recovery_enter_user_attributes.sh (14061B)


      1 #!/bin/bash
      2 # This file is in the public domain.
      3 
      4 # shellcheck disable=SC2317
      5 
      6 set -eu
      7 
      8 # Replace with 0 for nexus...
      9 USE_FAKEBANK=1
     10 if [ 1 = "$USE_FAKEBANK" ]
     11 then
     12     ACCOUNT="exchange-account-2"
     13     WIRE_METHOD="x-taler-bank"
     14     BANK_FLAGS="-f -d $WIRE_METHOD -u $ACCOUNT"
     15     BANK_URL="http://localhost:18082/"
     16     MERCHANT_PAYTO="payto://x-taler-bank/localhost/anastasis?receiver-name=anastasis"
     17 else
     18     ACCOUNT="exchange-account-1"
     19     WIRE_METHOD="iban"
     20     BANK_FLAGS="-ns -d $WIRE_METHOD -u $ACCOUNT"
     21     BANK_URL="http://localhost:18082/"
     22     MERCHANT_PAYTO="payto://iban/SANDBOXX/DE648226?receiver-name=anastasis"
     23 fi
     24 
     25 # Check we can actually run
     26 echo -n "Testing for jq"
     27 jq -h > /dev/null || exit_skip "jq required"
     28 echo " FOUND"
     29 echo -n "Testing for anastasis-reducer ..."
     30 anastasis-reducer -h > /dev/null || exit_skip "anastasis-reducer required"
     31 echo " FOUND"
     32 
     33 echo -n "Testing for taler"
     34 taler-exchange-httpd -h > /dev/null || exit_skip " taler-exchange required"
     35 taler-merchant-httpd -h > /dev/null || exit_skip " taler-merchant required"
     36 echo " FOUND"
     37 
     38 echo -n "Testing for taler-wallet-cli"
     39 taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
     40 echo " FOUND"
     41 
     42 echo -n "Testing for anastasis-httpd"
     43 anastasis-httpd -h >/dev/null </dev/null || exit_skip " MISSING"
     44 echo " FOUND"
     45 
     46 . setup.sh
     47 # Launch exchange, merchant and bank.
     48 # shellcheck disable=SC2086
     49 setup -c "test_reducer.conf" \
     50       -emw \
     51       -r merchant-exchange-default \
     52       $BANK_FLAGS
     53 
     54 # Cleanup to run whenever we exit
     55 function cleanup()
     56 {
     57     exit_cleanup
     58     for n in $(jobs -p)
     59     do
     60         kill "$n" 2> /dev/null || true
     61     done
     62     rm -rf "$CONF" "$WALLET_DB" "$R1FILE" "$R2FILE" "$B1FILE" "$B2FILE" "$TMP_DIR"
     63     wait
     64 }
     65 
     66 function sync_providers() {
     67   infile=$1
     68   outfile=$2
     69   echo "Synchronizing providers"
     70   # Sync with providers (up to 3 providers aren't synced here)
     71   for x in 1 2 3; do
     72     echo "Synchronizing providers (round $x)"
     73     anastasis-reducer sync_providers < "$infile" > "$outfile" 2> /dev/null || true
     74     CODE=$(jq -r -e ".code // 0" < "$outfile")
     75     # ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED
     76     # FIXME: Temporary workaround for C reducer. See #7227.
     77     if [ "$CODE" = "8420" ]
     78     then
     79       # restore previous non-error state
     80       cat "$infile" > "$outfile"
     81       break
     82     fi
     83     # ANASTASIS_REDUCER_ACTION_INVALID
     84     if [ "$CODE" = "8400" ]
     85     then
     86       # restore previous non-error state
     87       cat "$infile" > "$outfile"
     88       break
     89     fi
     90     if [ "$CODE" != "0" ]
     91     then
     92       exit_fail "Expected no error or 8420/8400, got $CODE"
     93     fi
     94     cat "$outfile" > "$infile"
     95   done
     96   echo "Providers synced."
     97 }
     98 
     99 
    100 CONF_1="test_anastasis_reducer_1.conf"
    101 CONF_2="test_anastasis_reducer_2.conf"
    102 CONF_3="test_anastasis_reducer_3.conf"
    103 CONF_4="test_anastasis_reducer_4.conf"
    104 
    105 
    106 # Configuration file will be edited, so we create one
    107 # from the template.
    108 CONF="$(mktemp -p "${TMPDIR:-/tmp}" test_reducerXXXXXX.conf)"
    109 cp test_reducer.conf "$CONF"
    110 
    111 TMP_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d keys-tmp-XXXXXX)
    112 WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_walletXXXXXX.json)
    113 B1FILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_stateB1XXXXXX)
    114 B2FILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_stateB2XXXXXX)
    115 R1FILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_stateR1XXXXXX)
    116 R2FILE=$(mktemp -p "${TMPDIR:-/tmp}" test_reducer_stateR2XXXXXX)
    117 
    118 # Install cleanup handler (except for kill -9)
    119 trap cleanup EXIT
    120 
    121 echo -n "Initialize anastasis database ..."
    122 # Name of the Postgres database we will use for the script.
    123 # Will be dropped, do NOT use anything that might be used
    124 # elsewhere
    125 TARGET_DB_1=$(anastasis-config -c $CONF_1 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
    126 TARGET_DB_2=$(anastasis-config -c $CONF_2 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
    127 TARGET_DB_3=$(anastasis-config -c $CONF_3 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
    128 TARGET_DB_4=$(anastasis-config -c $CONF_4 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///")
    129 
    130 dropdb "$TARGET_DB_1" >/dev/null 2>/dev/null || true
    131 createdb "$TARGET_DB_1" || exit_skip "Could not create database $TARGET_DB_1"
    132 anastasis-dbinit -c "$CONF_1" 2> anastasis-dbinit_1.log
    133 dropdb "$TARGET_DB_2" >/dev/null 2>/dev/null || true
    134 createdb "$TARGET_DB_2" || exit_skip "Could not create database $TARGET_DB_2"
    135 anastasis-dbinit -c "$CONF_2" 2> anastasis-dbinit_2.log
    136 dropdb "$TARGET_DB_3" >/dev/null 2>/dev/null || true
    137 createdb "$TARGET_DB_3" || exit_skip "Could not create database $TARGET_DB_3"
    138 anastasis-dbinit -c "$CONF_3" 2> anastasis-dbinit_3.log
    139 dropdb "$TARGET_DB_4" >/dev/null 2>/dev/null || true
    140 createdb "$TARGET_DB_4" || exit_skip "Could not create database $TARGET_DB_4"
    141 anastasis-dbinit -c "$CONF_4" 2> anastasis-dbinit_4.log
    142 
    143 echo " OK"
    144 
    145 echo -n "Launching anastasis services ..."
    146 PREFIX="" #valgrind
    147 $PREFIX anastasis-httpd -c "$CONF_1" 2> anastasis-httpd_1.log &
    148 $PREFIX anastasis-httpd -c "$CONF_2" 2> anastasis-httpd_2.log &
    149 $PREFIX anastasis-httpd -c "$CONF_3" 2> anastasis-httpd_3.log &
    150 $PREFIX anastasis-httpd -c "$CONF_4" 2> anastasis-httpd_4.log &
    151 
    152 echo "OK"
    153 
    154 echo -n "Waiting for anastasis services ..."
    155 
    156 # Wait for anastasis services to be available
    157 for n in $(seq 1 50)
    158 do
    159     echo -n "."
    160     sleep 0.1
    161     OK=0
    162    # anastasis_01
    163     wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue
    164     # anastasis_02
    165     wget --tries=1 --timeout=1 http://localhost:8087/ -o /dev/null -O /dev/null >/dev/null || continue
    166     # anastasis_03
    167     wget --tries=1 --timeout=1 http://localhost:8088/ -o /dev/null -O /dev/null >/dev/null || continue
    168     # anastasis_04
    169     wget --tries=1 --timeout=1 http://localhost:8089/ -o /dev/null -O /dev/null >/dev/null || continue
    170     OK=1
    171     break
    172 done
    173 
    174 if [ 1 != "$OK" ]
    175 then
    176     exit_skip "Failed to launch anastasis services"
    177 fi
    178 echo "OK"
    179 
    180 echo -n "Configuring merchant instance ..."
    181 # Setup merchant
    182 
    183 curl -H "Content-Type: application/json" -X POST -d '{"auth":{"method":"external"},"id":"admin","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' http://localhost:9966/management/instances
    184 
    185 curl -H "Content-Type: application/json" -X POST -d '{"payto_uri":"'"$MERCHANT_PAYTO"'"}' http://localhost:9966/private/accounts
    186 
    187 echo " DONE"
    188 
    189 echo -n "Running backup logic ...,"
    190 anastasis-reducer -b > "$B1FILE"
    191 echo -n "."
    192 anastasis-reducer -a \
    193   '{"continent": "Demoworld"}' \
    194   select_continent < "$B1FILE" > "$B2FILE"
    195 echo -n "."
    196 anastasis-reducer -a \
    197   '{"country_code": "xx"}' \
    198   select_country < "$B2FILE" > "$B1FILE"
    199 echo -n "."
    200 anastasis-reducer -a \
    201   '{"identity_attributes": {
    202     "full_name": "Max Musterman",
    203     "sq_number": "4",
    204     "birthdate": "2000-01-01"}}' \
    205   enter_user_attributes < "$B1FILE" > "$B2FILE"
    206 cat "$B2FILE" > "$B1FILE"
    207 echo -n ","
    208 sync_providers "$B1FILE" "$B2FILE"
    209 echo -n ","
    210 # "91GPWWR" encodes "Hans"
    211 anastasis-reducer -a \
    212   '{"authentication_method": {
    213     "type": "question",
    214     "instructions": "What is your name?",
    215     "challenge": "91GPWWR"
    216     } }' \
    217   add_authentication < "$B2FILE" > "$B1FILE"
    218 echo -n "."
    219 # "64S36" encodes "123"
    220 anastasis-reducer -a \
    221   '{"authentication_method": {
    222     "type": "question",
    223     "instructions": "How old are you?",
    224     "challenge": "64S36"
    225     } }' \
    226   add_authentication < "$B1FILE" > "$B2FILE"
    227 echo -n "."
    228 # "9NGQ4WR" encodes "Mars"
    229 anastasis-reducer -a \
    230   '{"authentication_method": {
    231     "type": "question",
    232     "instructions": "Where do you live?",
    233     "challenge": "9NGQ4WR"
    234     } }' \
    235   add_authentication < "$B2FILE" > "$B1FILE"
    236 echo -n "."
    237 # Finished adding authentication methods
    238 anastasis-reducer \
    239     next < "$B1FILE" > "$B2FILE"
    240 
    241 
    242 echo -n ","
    243 # Finished policy review
    244 anastasis-reducer \
    245   next < "$B2FILE" > "$B1FILE"
    246 echo -n "."
    247 
    248 # Note: 'secret' must here be a Crockford base32-encoded value
    249 anastasis-reducer -a \
    250   '{"secret": { "value" : "VERYHARDT0GVESSSECRET", "mime" : "text/plain" }}' \
    251   enter_secret < "$B1FILE" > "$B2FILE"
    252 mv "$B2FILE" "$B1FILE"
    253 anastasis-reducer next "$B1FILE" "$B2FILE"
    254 echo " OK"
    255 
    256 
    257 echo -n "Preparing wallet"
    258 
    259 EXCHANGE_URL="$(taler-exchange-config -c "$CONF" -s exchange -o BASE_URL)"
    260 
    261 rm -f "$WALLET_DB"
    262 taler-wallet-cli --no-throttle --wallet-db="$WALLET_DB" api --expect-success 'withdrawTestBalance' \
    263   "$(jq -n '
    264     {
    265         amount: "TESTKUDOS:100",
    266         corebankApiBaseUrl: $BANK_URL,
    267         exchangeBaseUrl: $EXCHANGE_URL
    268     }' \
    269     --arg BANK_URL "${BANK_URL}" \
    270     --arg EXCHANGE_URL "$EXCHANGE_URL"
    271   )" 2> wallet-withdraw.err > wallet-withdraw.out
    272 taler-wallet-cli \
    273     --wallet-db="$WALLET_DB" \
    274     run-until-done \
    275     2>wallet-withdraw-finish.err \
    276     >wallet-withdraw-finish.out
    277 echo " OK"
    278 
    279 echo -en "Making payments for truth uploads ... "
    280 OBJECT_SIZE=$(jq -r -e '.payments | length' < "$B2FILE")
    281 for ((INDEX=0; INDEX < "$OBJECT_SIZE"; INDEX++))
    282 do
    283     PAY_URI=$(jq --argjson INDEX $INDEX -r -e '.payments[$INDEX]' < "$B2FILE")
    284     # run wallet CLI
    285     echo -n "$INDEX"
    286     taler-wallet-cli \
    287         --wallet-db="$WALLET_DB" \
    288         handle-uri "$PAY_URI" \
    289         -y \
    290         2>"wallet-pay-truth-$INDEX.err" \
    291         >"wallet-pay-truth-$INDEX.out"
    292     echo -n ", "
    293 done
    294 echo "OK"
    295 echo -e "Running wallet run-until-done..."
    296 taler-wallet-cli \
    297     --wallet-db="$WALLET_DB" \
    298     run-until-done \
    299     2>"wallet-pay-truth-finish-$INDEX.err" \
    300     >"wallet-pay-truth-finish-$INDEX.out"
    301 echo -e "Payments done"
    302 
    303 echo -en "Try to upload again ..."
    304 $PREFIX anastasis-reducer pay "$B2FILE" "$B1FILE"
    305 mv "$B1FILE" "$B2FILE"
    306 echo " OK"
    307 
    308 echo -en "Making payments for policy uploads ... "
    309 OBJECT_SIZE=$(jq -r -e '.policy_payment_requests | length' < "$B2FILE")
    310 for ((INDEX=0; INDEX < "$OBJECT_SIZE"; INDEX++))
    311 do
    312     PAY_URI=$(jq --argjson INDEX $INDEX -r -e '.policy_payment_requests[$INDEX].payto' < "$B2FILE")
    313     # run wallet CLI
    314     echo -n "$INDEX"
    315     taler-wallet-cli \
    316         --wallet-db="$WALLET_DB" \
    317         handle-uri "$PAY_URI" \
    318         -y \
    319         2>"wallet-pay-policy-$INDEX.err" \
    320         >"wallet-pay-policy-$INDEX.out"
    321     echo -n ", "
    322 done
    323 echo " OK"
    324 echo -en "Running wallet run-until-done..."
    325 taler-wallet-cli \
    326     --wallet-db="$WALLET_DB" \
    327     run-until-done \
    328     2>wallet-pay-policy-finish.err \
    329     >wallet-pay-policy-finish.out
    330 echo -e " payments DONE"
    331 
    332 echo -en "Try to upload again ..."
    333 anastasis-reducer \
    334   pay < "$B2FILE" > "$B1FILE"
    335 echo " OK: Backup finished"
    336 echo -n "Final backup checks ..."
    337 STATE=$(jq -r -e .backup_state < "$B1FILE")
    338 if [ "$STATE" != "BACKUP_FINISHED" ]
    339 then
    340     exit_fail "Expected new state to be 'BACKUP_FINISHED', got '$STATE'"
    341 fi
    342 
    343 jq -r -e .core_secret < "$B1FILE" > /dev/null && exit_fail "'core_secret' was not cleared upon success"
    344 
    345 echo " OK"
    346 
    347 echo -n "Running recovery basic logic ..."
    348 anastasis-reducer -r > "$R1FILE"
    349 anastasis-reducer -a \
    350   '{"continent": "Demoworld"}' \
    351   select_continent < "$R1FILE" > "$R2FILE"
    352 anastasis-reducer -a \
    353   '{"country_code": "xx"}' \
    354   select_country < "$R2FILE" > "$R1FILE"
    355 anastasis-reducer -a '{"identity_attributes": { "full_name": "Max Musterman", "sq_number": "4", "birthdate": "2000-01-01" }}' enter_user_attributes < "$R1FILE" > "$R2FILE"
    356 
    357 
    358 STATE=$(jq -r -e .recovery_state < "$R2FILE")
    359 if [ "$STATE" != "SECRET_SELECTING" ]
    360 then
    361     exit_fail "Expected new state to be 'SECRET_SELECTING', got '$STATE'"
    362 fi
    363 echo " OK"
    364 
    365 echo -n "Adding provider (to ensure it is loaded)"
    366 anastasis-reducer -a '{"provider_url" : "http://localhost:8086/" }' add_provider < "$R2FILE" > "$R1FILE"
    367 echo " OK"
    368 
    369 echo -n "Selecting secret to recover"
    370 anastasis-reducer -a '{"attribute_mask": 0, "providers" : [ { "version": 1, "url" : "http://localhost:8086/" } ] }' select_version < "$R1FILE" > "$R2FILE"
    371 
    372 STATE=$(jq -r -e .recovery_state < "$R2FILE")
    373 if [ "$STATE" != "CHALLENGE_SELECTING" ]
    374 then
    375     exit_fail "Expected new state to be 'CHALLENGE_SELECTING', got '$STATE'"
    376 fi
    377 echo " OK"
    378 
    379 cat "$R2FILE" > "$R1FILE"
    380 
    381 sync_providers "$R1FILE" "$R2FILE"
    382 
    383 echo -n "Running challenge logic ..."
    384 
    385 UUID0=$(jq -r -e .recovery_information.challenges[0].uuid < "$R2FILE")
    386 UUID1=$(jq -r -e .recovery_information.challenges[1].uuid < "$R2FILE")
    387 UUID2=$(jq -r -e .recovery_information.challenges[2].uuid < "$R2FILE")
    388 #UUID0Q=$(jq -r -e .recovery_information.challenges[0].instructions < "$R2FILE")
    389 UUID1Q=$(jq -r -e .recovery_information.challenges[1].instructions < "$R2FILE")
    390 UUID2Q=$(jq -r -e .recovery_information.challenges[2].instructions < "$R2FILE")
    391 
    392 if [ "$UUID2Q" = 'How old are you?' ]
    393 then
    394     AGE_UUID=$UUID2
    395 elif [ "$UUID1Q" = 'How old are you?' ]
    396 then
    397     AGE_UUID=$UUID1
    398 else
    399     AGE_UUID=$UUID0
    400 fi
    401 
    402 if [ "$UUID2Q" = 'What is your name?' ]
    403 then
    404     NAME_UUID=$UUID2
    405 elif [ "$UUID1Q" = 'What is your name?' ]
    406 then
    407     NAME_UUID=$UUID1
    408 else
    409     NAME_UUID=$UUID0
    410 fi
    411 
    412 anastasis-reducer -a \
    413   "$(jq -n '
    414     {
    415         uuid: $UUID
    416     }' \
    417     --arg UUID "$NAME_UUID"
    418   )" \
    419   select_challenge < "$R2FILE" > "$R1FILE"
    420 
    421 anastasis-reducer -a '{"answer": "Hans"}' \
    422   solve_challenge < "$R1FILE" > "$R2FILE"
    423 
    424 anastasis-reducer -a \
    425   "$(jq -n '
    426     {
    427         uuid: $UUID
    428     }' \
    429     --arg UUID "$AGE_UUID"
    430   )" \
    431   select_challenge < "$R2FILE" > "$R1FILE"
    432 
    433 anastasis-reducer -a '{"answer": "123"}' \
    434   solve_challenge < "$R1FILE" > "$R2FILE"
    435 
    436 echo " OK"
    437 
    438 echo -n "Checking recovered secret ..."
    439 # finally: check here that we recovered the secret...
    440 
    441 STATE=$(jq -r -e .recovery_state < "$R2FILE")
    442 if [ "$STATE" != "RECOVERY_FINISHED" ]
    443 then
    444     jq -e . "$R2FILE"
    445     exit_fail "Expected new state to be 'RECOVERY_FINISHED', got '$STATE'"
    446 fi
    447 
    448 SECRET=$(jq -r -e .core_secret.value < "$R2FILE")
    449 if [ "$SECRET" != "VERYHARDT0GVESSSECRET" ]
    450 then
    451     jq -e . "$R2FILE"
    452     exit_fail "Expected recovered secret to be 'VERYHARDT0GVESSSECRET', got '$SECRET'"
    453 fi
    454 
    455 MIME=$(jq -r -e .core_secret.mime < "$R2FILE")
    456 if [ "$MIME" != "text/plain" ]
    457 then
    458     jq -e . "$R2FILE"
    459     exit_fail "Expected recovered mime to be 'text/plain', got '$MIME'"
    460 fi
    461 
    462 echo " OK"
    463 
    464 exit 0