setup.sh (8387B)
1 #!/bin/sh 2 # This file is in the public domain 3 4 # Script to be inlined into the main test scripts. Defines function 'setup()' 5 # which wraps around 'taler-unified-setup.sh' to launch GNU Taler services. 6 # Call setup() with the arguments to pass to 'taler-unified-setup'. setup() 7 # will then launch GNU Taler, wait for the process to be complete before 8 # returning. The script will also install an exit handler to ensure the GNU 9 # Taler processes are stopped when the shell exits. 10 11 set -eu 12 13 unset XDG_DATA_HOME 14 unset XDG_CONFIG_HOME 15 16 17 # Cleanup to run whenever we exit 18 function exit_cleanup() 19 { 20 if [ ! -z ${SETUP_PID+x} ] 21 then 22 echo "Killing taler-unified-setup ($SETUP_PID)" >&2 23 kill -TERM "$SETUP_PID" 2> /dev/null || true 24 wait "$SETUP_PID" 2> /dev/null || true 25 fi 26 } 27 28 # Install cleanup handler (except for kill -9) 29 trap exit_cleanup EXIT 30 31 function setup() 32 { 33 echo "Starting test system ..." >&2 34 # Create a named pipe in a temp directory we own. 35 FIFO_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d fifo-XXXXXX) 36 FIFO_OUT=$(echo "$FIFO_DIR/out") 37 mkfifo "$FIFO_OUT" 38 # Open pipe as FD 3 (RW) and FD 4 (RO) 39 exec 3<> "$FIFO_OUT" 4< "$FIFO_OUT" 40 rm -rf "$FIFO_DIR" 41 # We require '-W' for our termination logic to work. 42 taler-unified-setup.sh -W "$@" >&3 & 43 SETUP_PID=$! 44 # Close FD3 45 exec 3>&- 46 # Wait for the 'READY:' line. Reading until EOF instead of using 47 # 'sed -u /READY:/ q' lets us tell "the system came up" apart from 48 # "taler-unified-setup.sh died first": on EOF without READY the test 49 # would otherwise carry on against services that are not running and 50 # fail much later with a confusing error. 51 READY=0 52 while IFS= read -r LINE <&4 53 do 54 printf '%s\n' "$LINE" 55 case "$LINE" in 56 READY:*) 57 READY=1 58 break 59 ;; 60 esac 61 done 62 # Close FD4 63 exec 4>&- 64 if [ "$READY" != "1" ] 65 then 66 SETUP_STATUS=0 67 wait "$SETUP_PID" || SETUP_STATUS=$? 68 unset SETUP_PID 69 if [ "$SETUP_STATUS" = "77" ] 70 then 71 exit_skip "taler-unified-setup.sh could not launch the test system" 72 fi 73 exit_fail "taler-unified-setup.sh died with status $SETUP_STATUS before the test system was ready" 74 fi 75 echo "Test system ready" >&2 76 } 77 78 # Exit, with status code "skip" (no 'real' failure) 79 function exit_fail() { 80 echo "$@" >&2 81 exit 1 82 } 83 84 # Exit, with status code "skip" (no 'real' failure) 85 function exit_skip() { 86 echo "SKIPPING: $1" 87 exit 77 88 } 89 90 function get_payto_uri() { 91 libeufin-bank create-account -u "$1" -p "$2" --name "$1" 2> /dev/null 92 } 93 94 # Print the base URL of merchant instance $1 of the backend under test. 95 function merchant_instance_url() 96 { 97 if [ "$1" = "admin" ] 98 then 99 echo "http://localhost:9966/" 100 else 101 echo "http://localhost:9966/instances/$1/" 102 fi 103 } 104 105 # Log in to merchant instance $1 with password $2 (Basic authentication 106 # at POST /private/token) and print the access token. $3 is the scope 107 # of the token, "all" by default. Instances that require MFA for the 108 # login need merchant_login_mfa() instead. 109 function merchant_login() 110 { 111 local RESPONSE 112 local STATUS 113 114 RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" merchant-login-XXXXXX) 115 STATUS=$(curl -s -X POST \ 116 -H "Content-Type: application/json" \ 117 -H "Authorization: Basic $(printf '%s:%s' "$1" "$2" | base64 -w0)" \ 118 "$(merchant_instance_url "$1")private/token" \ 119 -d '{"scope":"'"${3:-all}"'","duration":{"d_us":86400000000}}' \ 120 -w "%{http_code}" \ 121 -o "$RESPONSE") 122 if [ "$STATUS" != "200" ] 123 then 124 jq < "$RESPONSE" >&2 || true 125 rm -f "$RESPONSE" 126 exit_fail "Expected 200 OK for the login to instance $1. Got: $STATUS" 127 fi 128 jq -er .access_token < "$RESPONSE" 129 rm -f "$RESPONSE" 130 } 131 132 # Directory where test_email_helper.sh and test_sms_helper.sh store the 133 # last TAN and the address it was sent to. Tests set 134 # TALER_MERCHANT_TEST_TAN_DIR before setup() so that the merchant passes 135 # it on to the helpers. 136 function tan_dir() 137 { 138 echo "${TALER_MERCHANT_TEST_TAN_DIR:-/tmp}" 139 } 140 141 # Have the merchant transmit challenge $1 and solve it with the TAN the 142 # helper received. $2 is the channel ("email" or "sms"), $3 the address 143 # the TAN must have been sent to. 144 function solve_challenge() 145 { 146 local RESPONSE 147 local STATUS 148 local TAN 149 local ADDRESS 150 151 RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" merchant-challenge-XXXXXX) 152 rm -f "$(tan_dir)/test-merchant-$2-tan.txt" \ 153 "$(tan_dir)/test-merchant-$2-address.txt" 154 STATUS=$(curl -s -X POST \ 155 -H "Content-Type: application/json" \ 156 "http://localhost:9966/challenge/$1" \ 157 -d '{}' \ 158 -w "%{http_code}" \ 159 -o "$RESPONSE") 160 if [ "$STATUS" != "200" ] 161 then 162 jq < "$RESPONSE" >&2 || true 163 exit_fail "Expected challenge transmission to return 200 OK. Got: $STATUS" 164 fi 165 TAN=$(head -n1 "$(tan_dir)/test-merchant-$2-tan.txt" | awk '{print $1}') 166 ADDRESS=$(cat "$(tan_dir)/test-merchant-$2-address.txt") 167 if [ "$ADDRESS" != "$3" ] 168 then 169 exit_fail "Expected $2 address '$3'. Got: $ADDRESS" 170 fi 171 STATUS=$(curl -s -X POST \ 172 -H "Content-Type: application/json" \ 173 "http://localhost:9966/challenge/$1/confirm" \ 174 -d '{"tan":"'"$TAN"'"}' \ 175 -w "%{http_code}" \ 176 -o "$RESPONSE") 177 if [ "$STATUS" != "204" ] 178 then 179 jq < "$RESPONSE" >&2 || true 180 exit_fail "Expected challenge confirmation to return 204 No Content. Got: $STATUS" 181 fi 182 rm -f "$RESPONSE" 183 } 184 185 # Solve the challenges listed in the 202 response in file $1: all of them 186 # if the response says "combi_and", otherwise only the first. $2 and $3 187 # are the e-mail address and the phone number the TANs must go to. 188 # Prints the comma-separated IDs of the solved challenges. 189 function solve_response_challenges() 190 { 191 local IDS="" 192 local CHALLENGE_ID 193 local CHANNEL 194 local ADDRESS 195 local FILTER='.challenges[]' 196 197 if [ "$(jq -r .combi_and < "$1")" != "true" ] 198 then 199 FILTER='.challenges[0]' 200 fi 201 while IFS=$'\t' read -r CHALLENGE_ID CHANNEL 202 do 203 case "$CHANNEL" in 204 email) 205 ADDRESS="$2" 206 ;; 207 sms) 208 ADDRESS="$3" 209 ;; 210 *) 211 exit_fail "Unexpected TAN channel: $CHANNEL" 212 ;; 213 esac 214 solve_challenge "$CHALLENGE_ID" "$CHANNEL" "$ADDRESS" 215 IDS="${IDS:+$IDS,}$CHALLENGE_ID" 216 done < <(jq -r "$FILTER"' | [.challenge_id, .tan_channel] | @tsv' "$1") 217 echo "$IDS" 218 } 219 220 # Log in to MFA-protected merchant instance $1 with password $2, solving 221 # the challenges the login asks for, and print the access token. $3 and 222 # $4 are the e-mail address and the phone number of the instance. 223 function merchant_login_mfa() 224 { 225 local RESPONSE 226 local STATUS 227 local BASIC 228 local BODY='{"scope":"all","duration":{"d_us":86400000000}}' 229 local IDS 230 231 RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" merchant-login-XXXXXX) 232 BASIC="Authorization: Basic $(printf '%s:%s' "$1" "$2" | base64 -w0)" 233 STATUS=$(curl -s -X POST \ 234 -H "Content-Type: application/json" \ 235 -H "$BASIC" \ 236 "$(merchant_instance_url "$1")private/token" \ 237 -d "$BODY" \ 238 -w "%{http_code}" \ 239 -o "$RESPONSE") 240 if [ "$STATUS" != "202" ] 241 then 242 jq < "$RESPONSE" >&2 || true 243 exit_fail "Expected 202 Accepted for the login to instance $1. Got: $STATUS" 244 fi 245 IDS=$(solve_response_challenges "$RESPONSE" "$3" "$4") 246 STATUS=$(curl -s -X POST \ 247 -H "Content-Type: application/json" \ 248 -H "$BASIC" \ 249 -H "Taler-Challenge-Ids: $IDS" \ 250 "$(merchant_instance_url "$1")private/token" \ 251 -d "$BODY" \ 252 -w "%{http_code}" \ 253 -o "$RESPONSE") 254 if [ "$STATUS" != "200" ] 255 then 256 jq < "$RESPONSE" >&2 || true 257 rm -f "$RESPONSE" 258 exit_fail "Expected 200 OK for the login to instance $1 with solved challenges. Got: $STATUS" 259 fi 260 jq -er .access_token < "$RESPONSE" 261 rm -f "$RESPONSE" 262 } 263 264 echo -n "Checking for curl ..." 265 curl --version 2> /dev/null > /dev/null || exit_skip " no curl" 266 echo " OK" 267 echo -n "Checking for jq ..." 268 jq --version 2> /dev/null > /dev/null || exit_skip " no jq" 269 echo " OK"