setup-sandcastle.sh (47723B)
1 #!/usr/bin/env bash 2 3 # This scripts provisions all configuration and 4 # services for the Taler sandcastle container. 5 # 6 # Important: This script needs to be completely 7 # idempotent, nothing must break if it is executed 8 # multiple times. 9 10 set -eu 11 set -x 12 export LC_ALL="C.UTF-8" 13 14 if [[ -n ${SANDCASTLE_SKIP_SETUP:-} ]]; then 15 echo "skipping sandcastle setup, requested by environment var SANDCASTLE_SKIP_SETUP" 16 exit 1 17 fi 18 19 20 # Helper to replace a comment-delimited block of lines in a config file with 21 # the desired content. If the block doesn't exist yet, append it. 22 update_config_block() { 23 local config_file="$1" 24 local marker_tag="$2" 25 local new_content="$3" 26 local begin_marker="# begin ${marker_tag}" 27 local end_marker="# end ${marker_tag}" 28 if [[ ! -f "$config_file" ]]; then 29 echo "Error: Config file '$config_file' not found." >&2 30 return 1 31 fi 32 if grep -qF "$begin_marker" "$config_file"; then 33 # Markers exist. Replace the block. 34 # Escape newlines in the content so sed processes it as a single block 35 local escaped_content="${new_content//$'\n'/\\n}" 36 sed -i "/$begin_marker/,/$end_marker/c\\$begin_marker\n$escaped_content\n$end_marker" "$config_file" 37 else 38 # Markers do not exist. Append to the end. 39 printf "\n%s\n%s\n%s\n" "$begin_marker" "$new_content" "$end_marker" >> "$config_file" 40 fi 41 } 42 43 echo "Provisioning sandcastle" 44 45 # General configuration. 46 # Might eventually be moved to an external file. 47 48 # Source any overrides from external file 49 if [[ -e /overrides ]]; then 50 source /overrides 51 fi 52 53 # When serving on an external port (for localhost deployments), 54 # we use http. 55 if [[ ${EXTERNAL_PORT:-} =~ ^[0-9]+$ ]]; then 56 PROTO=http 57 PORT_SUFFIX=:$EXTERNAL_PORT 58 else 59 PROTO=https 60 PORT_SUFFIX= 61 fi 62 63 : ${CURRENCY:="KUDOS"} 64 : ${WIRE_METHOD:=x-taler-bank} 65 66 67 if [[ $WIRE_METHOD = iban ]]; then 68 EXCHANGE_IBAN=DE159593 69 EXCHANGE_PAYTO="payto://iban/$EXCHANGE_IBAN?receiver-name=Sandcastle+Echange+Inc" 70 71 # Randomly generated IBANs for the merchants 72 MERCHANT_IBAN_ADMIN=DE85500105175178585583 73 MERCHANT_IBAN_POS=DE4218710 74 MERCHANT_IBAN_BLOG=DE8292195 75 MERCHANT_IBAN_GNUNET=DE9709960 76 MERCHANT_IBAN_TALER=DE1740597 77 MERCHANT_IBAN_TOR=DE2648777 78 MERCHANT_IBAN_SANDBOX=DE949115029592 79 MERCHANT_IBAN_UMAMI=DE358841382499 80 MERCHANT_IBAN_PAIVANA=DE5183926 81 MERCHANT_IBAN_TESTING=DE38936850270207298566 82 83 MERCHANT_PAYTO_ADMIN="payto://iban/$MERCHANT_IBAN_ADMIN?receiver-name=Default+Merchant" 84 MERCHANT_PAYTO_TESTING="payto://iban/$MERCHANT_IBAN_TESTING?receiver-name=Testing+Merchant" 85 MERCHANT_PAYTO_POS="payto://iban/$MERCHANT_IBAN_POS?receiver-name=PoS+Merchant" 86 MERCHANT_PAYTO_BLOG="payto://iban/$MERCHANT_IBAN_BLOG?receiver-name=Blog+Merchant" 87 MERCHANT_PAYTO_GNUNET="payto://iban/$MERCHANT_IBAN_GNUNET?receiver-name=GNUnet+Merchant" 88 MERCHANT_PAYTO_TALER="payto://iban/$MERCHANT_IBAN_TALER?receiver-name=Taler+Merchant" 89 MERCHANT_PAYTO_TOR="payto://iban/$MERCHANT_IBAN_TOR?receiver-name=Tor+Merchant" 90 MERCHANT_PAYTO_UMAMI="payto://iban/$MERCHANT_IBAN_UMAMI?receiver-name=Umami" 91 MERCHANT_PAYTO_PAIVANA="payto://iban/$MERCHANT_IBAN_PAIVANA?receiver-name=Paivana+Merchant" 92 MERCHANT_PAYTO_SANDBOX="payto://iban/$MERCHANT_IBAN_SANDBOX?receiver-name=Sandbox+Merchant" 93 elif [[ $WIRE_METHOD = x-taler-bank ]]; then 94 XTBHOST=sandcastle 95 EXCHANGE_PAYTO="payto://x-taler-bank/$XTBHOST/exchange?receiver-name=Sandcastle+Exchange+Inc" 96 MERCHANT_PAYTO_ADMIN="payto://x-taler-bank/$XTBHOST/merchant-admin?receiver-name=Admin+Merchant" 97 MERCHANT_PAYTO_TESTING="payto://x-taler-bank/$XTBHOST/merchant-testing?receiver-name=Default+Merchant" 98 MERCHANT_PAYTO_POS="payto://x-taler-bank/$XTBHOST/merchant-pos?receiver-name=PoS+Merchant" 99 MERCHANT_PAYTO_BLOG="payto://x-taler-bank/$XTBHOST/merchant-blog?receiver-name=Blog+Merchant" 100 MERCHANT_PAYTO_GNUNET="payto://x-taler-bank/$XTBHOST/merchant-gnunet?receiver-name=GNUnet+Merchant" 101 MERCHANT_PAYTO_TALER="payto://x-taler-bank/$XTBHOST/merchant-taler?receiver-name=Taler+Merchant" 102 MERCHANT_PAYTO_TOR="payto://x-taler-bank/$XTBHOST/merchant-tor?receiver-name=Tor+Merchant" 103 MERCHANT_PAYTO_UMAMI="payto://x-taler-bank/$XTBHOST/merchant-umami?receiver-name=Umami" 104 MERCHANT_PAYTO_PAIVANA="payto://x-taler-bank/$XTBHOST/merchant-paivana?receiver-name=Paivana+Merchant" 105 MERCHANT_PAYTO_SANDBOX="payto://x-taler-bank/$XTBHOST/merchant-sandbox?receiver-name=Sandbox+Merchant" 106 else 107 echo "wire method $WIRE_METHOD not supported" 108 exit 1 109 fi 110 111 MYDOMAIN=${MYDOMAIN:="demo.taler.net"} 112 LANDING_DOMAIN=$MYDOMAIN 113 BANK_DOMAIN=bank.$MYDOMAIN 114 EXCHANGE_DOMAIN=exchange.$MYDOMAIN 115 MERCHANT_DOMAIN=backend.$MYDOMAIN 116 DONAU_DOMAIN=donau.$MYDOMAIN 117 BLOG_DOMAIN=shop.$MYDOMAIN 118 DONATIONS_DOMAIN=donations.$MYDOMAIN 119 DRUPAL_DOMAIN=drupal.$MYDOMAIN 120 CHALLENGER_DOMAIN=challenger.$MYDOMAIN 121 AUDITOR_DOMAIN=auditor.$MYDOMAIN 122 PAIVANA_DOMAIN=paivana.$MYDOMAIN 123 124 # Website that is put behind the Paivana paywall. 125 # Note that this is an *upstream* server, it is not 126 # served by the sandcastle itself. 127 PAIVANA_DESTINATION=${PAIVANA_DESTINATION:-https://docs.taler.net/} 128 129 # Ports of the services running inside the container. 130 # Should be synchronized with the sandcastle-run script. 131 PORT_INTERNAL_EXCHANGE=8201 132 PORT_INTERNAL_MERCHANT=8301 133 PORT_INTERNAL_LIBEUFIN_BANK=8080 134 PORT_INTERNAL_LANDING=8501 135 PORT_INTERNAL_BLOG=8502 136 PORT_INTERNAL_DONATIONS=8503 137 PORT_INTERNAL_BANK_SPA=8505 138 PORT_INTERNAL_CHALLENGER=8506 139 PORT_INTERNAL_AUDITOR=8507 140 PORT_INTERNAL_DONAU=8508 141 PORT_INTERNAL_DRUPAL=8509 142 PORT_INTERNAL_PAIVANA=8510 143 144 145 ENABLE_AUDITOR=0 146 147 # Just make sure the services are stopped 148 systemctl stop postgresql.service 149 systemctl stop taler-auditor.target 150 systemctl stop taler-exchange.target 151 systemctl stop taler-exchange-offline.timer 152 systemctl stop taler-merchant-httpd.service 153 systemctl stop taler-merchant.target 154 systemctl stop taler-demo-landing.service 155 systemctl stop taler-demo-blog.service 156 systemctl stop taler-demo-donations.service 157 systemctl stop libeufin-bank.service 158 systemctl stop donau-httpd.service 159 systemctl stop paivana-httpd.service 160 systemctl stop paivana-httpd.socket 161 162 # libeufin-nexus is not used 163 systemctl stop libeufin-nexus-ebics-fetch.service 164 systemctl disable libeufin-nexus-ebics-fetch.service 165 systemctl stop libeufin-nexus-ebics-submit.service 166 systemctl disable libeufin-nexus-ebics-submit.service 167 168 systemctl reset-failed 169 170 # We now make sure that some important locations are symlinked to 171 # the persistent storage volume. 172 # Files that already exist in this location are moved to the storage volume 173 # and then symlinked. 174 # These locations are: 175 # /etc/taler 176 # /etc/libeufin 177 # /var/lib/taler 178 # postgres DB directory 179 180 function lift_dir() { 181 where=$1 182 src=$2 183 target=$3 184 if [[ -L $src ]]; then 185 # be idempotent 186 echo "$src is already a symlink" 187 elif [[ -d /$where/$target ]]; then 188 echo "symlinking existing /$where/$target" 189 rm -rf "$src" 190 ln -s "/$where/$target" "$src" 191 else 192 echo "symlinking new /$where/$target" 193 mv "$src" "/$where/$target" 194 ln -s "/$where/$target" "$src" 195 fi 196 } 197 198 lift_dir talerdata /var/lib/taler-exchange var-lib-taler-exchange 199 lift_dir talerdata /etc/taler-merchant etc-taler-merchant 200 lift_dir talerdata /etc/taler-exchange etc-taler-exchange 201 lift_dir talerdata /etc/taler-exchange etc-taler-auditor 202 lift_dir talerdata /etc/donau etc-donau 203 lift_dir talerdata /etc/libeufin etc-libeufin 204 # lift both config and data 205 lift_dir talerdata /etc/postgresql etc-postgresql 206 lift_dir talerdata /var/lib/postgresql var-lib-postgresql 207 # offline keys are in a separate volume 208 lift_dir talerdata_persistent /var/lib/taler-exchange/offline exchange-offline 209 210 # Usage: get_credential_pw COMPONENT/ACCOUNT 211 function get_credential_pw() { 212 if [[ ${USE_INSECURE_SANDBOX_PASSWORDS:-0} = 1 ]]; then 213 echo "sandbox" 214 return 215 fi 216 p=/credentials/$1 217 if [[ ! -f $p ]]; then 218 mkdir -p $(dirname "$p") 219 uuidgen -r >$p 220 fi 221 cat "$p" 222 } 223 224 import_instr=none 225 if [[ -d /exported && -e /exported/import-request ]]; then 226 import_instr=$(cat /exported/import-request) 227 fi 228 229 # If necessary, import the offline key. 230 # Done before everything else, as we need the key 231 # to generate the config. 232 233 if [[ $import_instr = all ]]; then 234 echo "Importing exchange offline key" 235 rm -rf /var/lib/taler-exchange/offline/* 236 cp -r /exported/taler-exchange/offline/* /var/lib/taler-exchange/offline/ 237 fi 238 239 # Adjust ownership. 240 # Necessary when the container is rebuilt with different user IDs. 241 chown --recursive taler-exchange-offline:taler-exchange-offline /var/lib/taler-exchange/offline/. || true 242 chown root:taler-exchange-db /etc/taler-exchange/secrets/exchange-db.secret.conf 243 chown taler-exchange-wire:root /etc/taler-exchange/secrets/exchange-accountcredentials-*.conf 244 chown taler-merchant-httpd:root /etc/taler-merchant/secrets/merchant-db.secret.conf 245 chown root:donau-db /etc/donau/secrets/donau-db.secret.conf 246 247 248 MASTER_PUBLIC_KEY=$(sudo -u taler-exchange-offline taler-exchange-offline -LDEBUG setup) 249 250 251 # 252 # Create the basic configuration files 253 # 254 255 mkdir -p /etc/challenger/conf.d 256 cat <<EOF >/etc/challenger/conf.d/setup-sandcastle.conf 257 [challenger] 258 BASE_URL = $PROTO://$CHALLENGER_DOMAIN$PORT_SUFFIX/ 259 ADDRESS_TYPE = email 260 AUTH_COMMAND = /data/sandcastle-challenger-auth 261 ADDRESS_RESTRICTIONS = {"email":{"hint":"not an e-mail address","regex":"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$"}} 262 EOF 263 264 mkdir -p /etc/paivana 265 cat <<EOF >/etc/paivana/paivana.conf 266 [paivana] 267 # Serve on the socket provided by paivana-httpd.socket. 268 SERVE = systemd 269 270 # Public base URL of the paywall. 271 BASE_URL = $PROTO://$PAIVANA_DOMAIN$PORT_SUFFIX/ 272 273 # Upstream site that is protected by the paywall. 274 DESTINATION_BASE_URL = $PAIVANA_DESTINATION 275 276 # Merchant instance that sells access to the site. 277 MERCHANT_BACKEND_URL = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/paivana/ 278 MERCHANT_ACCESS_TOKEN = secret-token:$(get_credential_pw merchant/paivana) 279 280 # Stable key for the access cookie MAC, so that paid clients 281 # survive a restart of paivana-httpd. 282 SECRET = $(get_credential_pw paivana/secret) 283 284 # Static resources are served without payment, as the 285 # protected site is otherwise unusable after paying. 286 WHITELIST = ^/(favicon\.ico|robots\.txt|.*\.(css|js|png|jpe?g|gif|svg|ico|webp|woff2?|ttf|eot))\$ 287 EOF 288 289 # The config contains the merchant access token and the cookie secret. 290 chown paivana-httpd:root /etc/paivana/paivana.conf 291 chmod 640 /etc/paivana/paivana.conf 292 293 # The paywall runs behind the caddy reverse proxy, so we need 294 # '-f' to get the client address from X-Forwarded-For. With '-g' 295 # a single payment unlocks the entire site instead of just the 296 # URL that was paid for. 297 mkdir -p /etc/systemd/system/paivana-httpd.service.d 298 cat <<EOF >/etc/systemd/system/paivana-httpd.service.d/sandcastle.conf 299 [Unit] 300 # Paywall templates are fetched from the merchant backend on 301 # startup, so keep retrying until the merchant is up. 302 After=taler-merchant-httpd.service 303 StartLimitIntervalSec=0 304 305 [Service] 306 ExecStart= 307 ExecStart=/usr/bin/paivana-httpd -c /etc/paivana/paivana.conf -f -g -L INFO 308 EOF 309 310 systemctl daemon-reload 311 312 cat <<EOF >/etc/libeufin/libeufin-bank.conf 313 [libeufin-bank] 314 BASE_URL = $PROTO://$BANK_DOMAIN$PORT_SUFFIX/ 315 CURRENCY = $CURRENCY 316 DEFAULT_DEBT_LIMIT = $CURRENCY:500 317 REGISTRATION_BONUS = $CURRENCY:100 318 SPA_CAPTCHA_URL = $PROTO://$BANK_DOMAIN$PORT_SUFFIX/webui/#/operation/{woid} 319 SUGGESTED_WITHDRAWAL_EXCHANGE = $PROTO://$EXCHANGE_DOMAIN$PORT_SUFFIX/ 320 ALLOW_REGISTRATION = yes 321 SERVE = tcp 322 PORT = 8080 323 # Bind address. 324 # Option soon to be deprecated! 325 ADDRESS = 0.0.0.0 326 WIRE_TYPE = $WIRE_METHOD 327 328 # Compat mode for now 329 PWD_CHECK = no 330 PWD_AUTH_COMPAT = yes 331 332 [currency-$CURRENCY] 333 ENABLED = YES 334 name = "${NAME:=Kudos}" 335 code = "$CURRENCY" 336 decimal_separator = "." 337 fractional_input_digits = ${FRACTIONALS:=2} 338 fractional_normal_digits = ${FRACTIONALS:=2} 339 fractional_trailing_zero_digits = ${FRACTIONALS:=2} 340 is_currency_name_leading = NO 341 alt_unit_names = {"0":"${ALT_UNIT_NAME:=ク}"} 342 EOF 343 344 cat <<EOF >/etc/libeufin/settings.json 345 { 346 "topNavSites": { 347 "Landing": "$PROTO://$LANDING_DOMAIN$PORT_SUFFIX/", 348 "Bank": "$PROTO://$BANK_DOMAIN$PORT_SUFFIX", 349 "Essay Shop": "$PROTO://$BLOG_DOMAIN$PORT_SUFFIX", 350 "Donations": "$PROTO://$DONATIONS_DOMAIN$PORT_SUFFIX", 351 } 352 } 353 EOF 354 355 # Generate /tmp/sandcastle-setup.conf 356 cat <<EOF >/tmp/sandcastle-setup.conf 357 [currency-$CURRENCY] 358 ENABLED = YES 359 name = "${NAME:=Kudos}" 360 code = "$CURRENCY" 361 decimal_separator = "." 362 fractional_input_digits = ${FRACTIONALS:=2} 363 fractional_normal_digits = ${FRACTIONALS:=2} 364 fractional_trailing_zero_digits = ${FRACTIONALS:=2} 365 is_currency_name_leading = NO 366 alt_unit_names = {"0":"${ALT_UNIT_NAME:=ク}"} 367 EOF 368 369 cp /tmp/sandcastle-setup.conf /etc/taler-exchange/conf.d/sandcastle-setup.conf 370 cp /tmp/sandcastle-setup.conf /etc/taler-merchant/conf.d/sandcastle-setup.conf 371 372 373 cat <<EOF >/etc/taler-exchange/conf.d/sandcastle-exchange.conf 374 [exchange] 375 CURRENCY = $CURRENCY 376 CURRENCY_ROUND_UNIT = $CURRENCY:0.01 377 TINY_AMOUNT = $CURRENCY:0.01 378 AML_THRESHOLD = $CURRENCY:1000000 379 MASTER_PUBLIC_KEY = $MASTER_PUBLIC_KEY 380 BASE_URL = $PROTO://$EXCHANGE_DOMAIN$PORT_SUFFIX/ 381 382 [taler-exchange-secmod-rsa] 383 LOOKAHEAD_SIGN = 4 weeks 384 385 [taler-exchange-secmod-eddsa] 386 LOOKAHEAD_SIGN = 4 weeks 387 388 [taler-exchange-secmod-cs] 389 LOOKAHEAD_SIGN = 4 weeks 390 391 [exchange-account-default] 392 PAYTO_URI = $EXCHANGE_PAYTO 393 ENABLE_DEBIT = YES 394 ENABLE_CREDIT = YES 395 @inline-secret@ exchange-accountcredentials-default ../secrets/exchange-accountcredentials-default.secret.conf 396 EOF 397 398 399 cat <<EOF >/etc/taler-exchange/secrets/exchange-accountcredentials-default.secret.conf 400 [exchange-accountcredentials-default] 401 WIRE_GATEWAY_URL = $PROTO://$BANK_DOMAIN$PORT_SUFFIX/accounts/exchange/taler-wire-gateway/ 402 WIRE_GATEWAY_AUTH_METHOD = basic 403 USERNAME = exchange 404 PASSWORD = $(get_credential_pw bank/exchange) 405 EOF 406 407 if [[ $ENABLE_AUDITOR = 1 ]]; then 408 # Make sandcastle exchange config available to auditor 409 cp /etc/taler-exchange/conf.d/sandcastle-exchange.conf /etc/taler-auditor/conf.d/sandcastle-exchange.conf 410 411 # We run the offline tooling as root, maybe in the future there should be 412 # a separate user created by the Debian package for that. 413 AUDITOR_PUB=$(taler-auditor-offline setup) 414 415 cat <<EOF >/etc/taler-auditor/conf.d/sandcastle-auditor.conf 416 [auditor] 417 PUBLIC_KEY = $AUDITOR_PUB 418 419 [exchangedb] 420 421 $(dup_exchange_opt exchangedb IDLE_RESERVE_EXPIRATION_TIME) 422 $(dup_exchange_opt exchangedb LEGAL_RESERVE_EXPIRATION_TIME) 423 $(dup_exchange_opt exchangedb AGGREGATOR_SHIFT) 424 $(dup_exchange_opt exchangedb DEFAULT_PURSE_LIMIT) 425 426 [exchangedb-postgres] 427 $(dup_exchange_opt exchangedb-postgres CONFIG) 428 429 [exchange] 430 $(dup_exchange_opt exchange CURRENCY) 431 $(dup_exchange_opt exchange CURRENCY_ROUND_UNIT) 432 $(dup_exchange_opt exchange DB) 433 434 435 EOF 436 fi 437 438 # The config shipped with the package can conflict with the 439 # trusted sandcastle exchange if the currency is KUDOS. 440 rm -f /usr/share/taler-exchange/config.d/kudos.conf 441 rm -f /usr/share/taler-merchant/config.d/kudos.conf 442 443 MY_HELPER_EMAIL=${OVERRIDE_MERCHANT_HELPER_EMAIL:-/data/sandcastle-merchant-email-helper} 444 445 # We need to define the default currency for the UI. 446 cat <<EOF >/etc/taler-merchant/conf.d/sandcastle-merchant.conf 447 [merchant] 448 # Default currency 449 CURRENCY = $CURRENCY 450 ENABLE_SELF_PROVISIONING = YES 451 MANDATORY_TAN_CHANNELS = email 452 HELPER_EMAIL = $MY_HELPER_EMAIL 453 454 BASE_URL = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/ 455 456 # Will be the default in future merchant versions 457 # => Can be removed after 1.6 release 458 BACKOFFICE_SPA_DIR = /usr/share/taler-merchant-webui/ 459 460 EOF 461 462 cat <<EOF >/etc/taler-merchant/conf.d/sandcastle-merchant-exchanges.conf 463 [merchant-exchange-sandcastle] 464 EXCHANGE_BASE_URL = $PROTO://$EXCHANGE_DOMAIN$PORT_SUFFIX/ 465 MASTER_KEY = $MASTER_PUBLIC_KEY 466 CURRENCY = $CURRENCY 467 EOF 468 469 # Allow overrides to modify merchant config 470 [[ $(type -t hook_merchant_config) == function ]] && hook_merchant_config 471 472 # FIXME: This is a workaround, fix the packaging of taler-merchant-frontends here! 473 mkdir -p /etc/taler 474 475 cat <<EOF >/etc/taler/taler-merchant-frontends.conf 476 # Different entry point, we need to repeat some settings. 477 # In the future, taler-merchant-demos should become 478 # robust enough to read from the main config. 479 [taler] 480 CURRENCY = $CURRENCY 481 482 [frontend-demo-landing] 483 SERVE = http 484 HTTP_PORT = $PORT_INTERNAL_LANDING 485 486 [frontend-demo-blog] 487 SERVE = http 488 HTTP_PORT = $PORT_INTERNAL_BLOG 489 BACKEND_URL = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/blog/ 490 BACKEND_APIKEY = secret-token:$(get_credential_pw merchant/blog) 491 ENABLE_TOKENS = ${ENABLE_SUBSCRIPTIONS:-no} 492 493 [frontend-demo-donations] 494 DONAU_URL = $PROTO://$DONAU_DOMAIN$PORT_SUFFIX/ 495 SERVE = http 496 HTTP_PORT = $PORT_INTERNAL_DONATIONS 497 BACKEND_URL_TOR = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/tor/ 498 BACKEND_APIKEY_TOR = secret-token:$(get_credential_pw merchant/tor) 499 BACKEND_URL_TALER = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/taler/ 500 BACKEND_APIKEY_TALER = secret-token:$(get_credential_pw merchant/taler) 501 BACKEND_URL_GNUNET = $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/gnunet/ 502 BACKEND_APIKEY_GNUNET = secret-token:$(get_credential_pw merchant/gnunet) 503 EOF 504 505 # This really should not exist, the taler-merchant-frontends 506 # should be easier to configure! 507 cat <<EOF >/etc/taler/taler-merchant-frontends.env 508 TALER_ENV_URL_INTRO=$PROTO://$LANDING_DOMAIN$PORT_SUFFIX/ 509 TALER_ENV_URL_LANDING=$PROTO://$LANDING_DOMAIN$PORT_SUFFIX/ 510 TALER_ENV_URL_BANK=$PROTO://$BANK_DOMAIN$PORT_SUFFIX/ 511 TALER_ENV_URL_MERCHANT_BLOG=$PROTO://$BLOG_DOMAIN$PORT_SUFFIX/ 512 TALER_ENV_URL_MERCHANT_DONATIONS=$PROTO://$DONATIONS_DOMAIN$PORT_SUFFIX/ 513 EOF 514 515 # 516 # Create databases 517 # 518 519 function wait_pg_ready() { 520 while true; do 521 ret=0 522 pg_isready || ret=$? 523 case "$ret" in 524 0) 525 echo "Postgres is ready" >&2 526 break 527 ;; 528 1|2) 529 echo "pg_isready returned status $ret, waiting" >&2 530 sleep 1 531 ;; 532 3) 533 echo "pg_isready returned status $ret, giving up" >&2 534 exit 3 535 ;; 536 esac 537 done 538 } 539 540 PG_VERSION="17" 541 542 # Since the sandcastle is a test system, we turn fsync off for performance 543 # reasons (especially with the drupal setup). 544 # CAUTION: You do not want to set this in production, 545 # especially not for the taler-exchange. 546 pg_conftool $PG_VERSION main set fsync off 547 # Higher limits needed for migration 548 pg_conftool $PG_VERSION main set max_locks_per_transaction 512 549 pg_conftool $PG_VERSION main set max_pred_locks_per_transaction 512 550 551 backup_file=/exported/postgres-backup.sql 552 if [[ $import_instr = singledump ]]; then 553 echo "Importing database dump" 554 if [[ ! -e "$backup_file" ]]; then 555 echo "Requested import, but backup file does not exist" >&2 556 exit 1 557 fi 558 pg_dropcluster --stop 17 main || true 559 pg_createcluster 17 main 560 systemctl start postgresql.service 561 wait_pg_ready 562 sudo -u postgres psql postgres -f "$backup_file" 563 else 564 systemctl start postgresql.service 565 wait_pg_ready 566 fi 567 568 # Set up databases. 569 # Do that *before* we potentially do a per-service restore-from-backup. 570 571 challenger-dbconfig 572 573 # Sets up the database for both libeufin-bank and libeufin-nexus. We only need 574 # the libeufin-bank DB though. 575 libeufin-dbconfig 576 577 if [[ $ENABLE_AUDITOR = 1 ]]; then 578 # Add auditor user to DB group *before* running taler-exchange-dbconfig, 579 # so that DB permissions are adjusted accordingly. 580 usermod taler-auditor-httpd -aG taler-exchange-db 581 taler-auditor-dbconfig 582 fi 583 584 taler-exchange-dbconfig 585 586 taler-merchant-dbconfig 587 588 589 # 590 # Import backup if necessary. 591 # 592 593 if [[ $import_instr = all ]]; then 594 echo "Importing databases" 595 596 # FIXME: Consider backing up old DB before importing new one 597 # FIXME: This is rather hacky, it would be better to use "pg_dump -Fc" and "pg_restore" 598 sudo -u postgres dropdb taler-exchange 599 sudo -u postgres dropdb taler-merchant 600 sudo -u postgres dropdb libeufin 601 602 sudo -u postgres createdb taler-exchange 603 sudo -u postgres createdb taler-merchant 604 sudo -u postgres createdb libeufin 605 606 sudo -u postgres psql taler-exchange -f /exported/taler-exchange/taler-exchange.sql 607 sudo -u postgres psql taler-merchant -f /exported/taler-merchant/taler-merchant.sql 608 sudo -u postgres psql libeufin -f /exported/libeufin/libeufin.sql 609 610 libeufin-dbconfig 611 taler-exchange-dbconfig 612 taler-merchant-dbconfig 613 614 rm -rf /var/lib/taler-exchange/secmod-eddsa/* 615 cp -r /exported/taler-exchange/secmod-eddsa/* /var/lib/taler-exchange/secmod-eddsa/ 616 617 rm -rf /var/lib/taler-exchange/secmod-rsa/* 618 cp -r /exported/taler-exchange/secmod-rsa/* /var/lib/taler-exchange/secmod-rsa/ 619 620 rm -rf /var/lib/taler-exchange/secmod-cs/* 621 cp -r /exported/taler-exchange/secmod-cs/* /var/lib/taler-exchange/secmod-cs/ 622 fi 623 624 if [[ $import_instr != none ]]; then 625 echo "Marking import as done" 626 rm /exported/import-request 627 fi 628 629 # We need to adjust file ownership, as the container might have different user and group 630 # IDs than the volume. That can happen when the packages in the container are installed 631 # in a different order. 632 # This is only relevant for non-root ownership. 633 chown --recursive taler-exchange-offline:taler-exchange-offline /var/lib/taler-exchange/offline/* || true 634 chown --recursive taler-exchange-secmod-cs:taler-exchange-secmod /var/lib/taler-exchange/secmod-cs 635 chown --recursive taler-exchange-secmod-rsa:taler-exchange-secmod /var/lib/taler-exchange/secmod-rsa 636 chown --recursive taler-exchange-secmod-eddsa:taler-exchange-secmod /var/lib/taler-exchange/secmod-eddsa 637 chown root:taler-exchange-db /etc/taler-exchange/secrets/exchange-db.secret.conf 638 chown root:taler-auditor-httpd /etc/taler-auditor/secrets/auditor-db.secret.conf 639 chmod 440 /etc/taler-merchant/secrets/merchant-db.secret.conf 640 chown taler-merchant-httpd:root /etc/taler-merchant/secrets/merchant-db.secret.conf 641 chown root:taler-exchange-db /etc/taler-exchange/secrets/exchange-db.secret.conf 642 chown taler-exchange-wire:taler-exchange-db /etc/taler-exchange/secrets/exchange-accountcredentials-default.secret.conf 643 644 645 # Caddy configuration. 646 # We use the caddy reverse proxy with automatic 647 # internal TLS setup to ensure that the services are 648 # reachable inside the container without any external 649 # DNS setup under the same domain name and with TLS 650 # from inside the container. 651 652 systemctl stop caddy.service 653 654 cat <<EOF >/etc/caddy/Caddyfile 655 { 656 servers { 657 trusted_proxies static private_ranges 658 } 659 } 660 661 # Services that only listen on unix domain sockets 662 # are reverse-proxied to serve on a TCP port. 663 664 :$PORT_INTERNAL_EXCHANGE { 665 reverse_proxy unix//run/taler-exchange/httpd/exchange-http.sock 666 } 667 668 :$PORT_INTERNAL_MERCHANT { 669 reverse_proxy unix//run/taler-merchant/httpd/merchant-http.sock { 670 # Set this, or otherwise wrong taler://pay URIs will be generated. 671 header_up X-Forwarded-Proto "https" 672 } 673 } 674 675 :$PORT_INTERNAL_DONAU { 676 reverse_proxy unix//run/donau/httpd/http.sock { 677 header_up X-Forwarded-Proto "https" 678 } 679 } 680 681 :$PORT_INTERNAL_BANK_SPA { 682 root * /usr/share/libeufin/spa 683 root /settings.json /etc/libeufin/ 684 file_server 685 } 686 687 :$PORT_INTERNAL_DRUPAL { 688 root * /talerdata/sandcastle-drupal/web/ 689 php_fastcgi unix/var/run/php/php8.4-fpm.sock 690 file_server 691 } 692 693 :$PORT_INTERNAL_AUDITOR { 694 reverse_proxy unix//run/taler-auditor/httpd/auditor-http.sock 695 } 696 697 :$PORT_INTERNAL_PAIVANA { 698 reverse_proxy unix//run/paivana/httpd/paivana-http.sock 699 } 700 701 :$PORT_INTERNAL_CHALLENGER { 702 handle { 703 reverse_proxy unix//run/challenger/httpd/challenger.http { 704 # Set this, or otherwise wrong taler://pay URIs will be generated. 705 header_up X-Forwarded-Proto "https" 706 } 707 } 708 709 # Serve challenges via HTTP. 710 # This is obviously completely insecure, but fine 711 # for the demo sandcastle. 712 handle_path /challenges/* { 713 root * /tmp/challenges/ 714 file_server { 715 browse 716 } 717 } 718 } 719 EOF 720 721 if [[ $PROTO = https ]]; then 722 cat <<EOF >>/etc/caddy/Caddyfile 723 724 # Internally reverse-proxy https://, 725 # so that service can talk to each other via 726 # https:// inside the container. 727 728 https://$BANK_DOMAIN { 729 tls internal 730 reverse_proxy :8080 { 731 # libeufin-bank should eventually not require this anymore, 732 # but currently doesn't work without this header. 733 header_up X-Forwarded-Prefix "" 734 } 735 } 736 737 https://$EXCHANGE_DOMAIN { 738 tls internal 739 reverse_proxy unix//run/taler-exchange/httpd/exchange-http.sock 740 } 741 742 https://$MERCHANT_DOMAIN { 743 tls internal 744 reverse_proxy unix//run/taler-merchant/httpd/merchant-http.sock { 745 # Set this, or otherwise wrong taler://pay URIs will be generated. 746 header_up X-Forwarded-Proto "https" 747 } 748 } 749 750 https://$DONAU_DOMAIN { 751 tls internal 752 reverse_proxy unix//run/donau/httpd/http.sock { 753 header_up X-Forwarded-Proto "https" 754 } 755 } 756 757 https://$AUDITOR_DOMAIN { 758 tls internal 759 reverse_proxy unix//run/taler-auditor/httpd/auditor-http.sock 760 } 761 762 https://$CHALLENGER_DOMAIN { 763 tls internal 764 reverse_proxy unix//run/challenger/httpd/challenger.http 765 } 766 767 https://$PAIVANA_DOMAIN { 768 tls internal 769 reverse_proxy unix//run/paivana/httpd/paivana-http.sock 770 } 771 772 EOF 773 774 else 775 # Config for HTTP without TLS. 776 777 cat <<EOF >>/etc/caddy/Caddyfile 778 779 http://$BANK_DOMAIN$PORT_SUFFIX { 780 reverse_proxy :8080 { 781 # libeufin-bank should eventually not require this anymore, 782 # but currently doesn't work without this header. 783 header_up X-Forwarded-Prefix "" 784 } 785 } 786 787 http://$EXCHANGE_DOMAIN$PORT_SUFFIX { 788 reverse_proxy unix//run/taler-exchange/httpd/exchange-http.sock 789 } 790 791 http://$MERCHANT_DOMAIN$PORT_SUFFIX { 792 reverse_proxy unix//run/taler-merchant/httpd/merchant-http.sock 793 } 794 795 http://$DONAU_DOMAIN$PORT_SUFFIX { 796 reverse_proxy unix//run/donau/httpd/http.sock 797 } 798 799 http://$AUDITOR_DOMAIN$PORT_SUFFIX { 800 reverse_proxy unix//run/taler-auditor/httpd/auditor-http.sock 801 } 802 803 http://$CHALLENGER_DOMAIN$PORT_SUFFIX { 804 reverse_proxy unix//run/challenger/httpd/challenger.http 805 } 806 807 http://$LANDING_DOMAIN$PORT_SUFFIX { 808 reverse_proxy :$PORT_INTERNAL_LANDING 809 } 810 811 http://$BLOG_DOMAIN$PORT_SUFFIX { 812 reverse_proxy :$PORT_INTERNAL_BLOG 813 } 814 815 http://$DONATIONS_DOMAIN$PORT_SUFFIX { 816 reverse_proxy :$PORT_INTERNAL_DONATIONS 817 } 818 819 http://$DRUPAL_DOMAIN$PORT_SUFFIX { 820 reverse_proxy :$PORT_INTERNAL_DRUPAL 821 } 822 823 http://$PAIVANA_DOMAIN$PORT_SUFFIX { 824 reverse_proxy unix//run/paivana/httpd/paivana-http.sock 825 } 826 827 EOF 828 829 fi 830 831 cat <<EOF >>/etc/hosts 832 # Start of Taler Sandcastle Domains 833 127.0.0.1 $LANDING_DOMAIN 834 127.0.0.1 $BANK_DOMAIN 835 127.0.0.1 $EXCHANGE_DOMAIN 836 127.0.0.1 $MERCHANT_DOMAIN 837 127.0.0.1 $BLOG_DOMAIN 838 127.0.0.1 $DONATIONS_DOMAIN 839 127.0.0.1 $DONAU_DOMAIN 840 127.0.0.1 $CHALLENGER_DOMAIN 841 127.0.0.1 $DRUPAL_DOMAIN 842 127.0.0.1 $PAIVANA_DOMAIN 843 # End of Taler Sandcastle Domains 844 EOF 845 846 systemctl start caddy.service 847 848 # Install local, internal CA certs for caddy 849 caddy trust 850 851 # Set up challenger 852 853 CHALLENGER_CLIENT_SECRET=secret-token:sandbox 854 CHALLENGER_CLIENT_ID=$(sudo -u challenger-httpd challenger-admin -q --add="$CHALLENGER_CLIENT_SECRET" https://$EXCHANGE_DOMAIN/kyc-proof/mychallenger) 855 echo Challenger client ID: $CHALLENGER_CLIENT_ID 856 857 systemctl enable --now challenger-httpd.service 858 859 # Set up bank 860 861 sudo -u libeufin-bank libeufin-bank edit-account admin --debit_threshold=$CURRENCY:10000000 862 sudo -u libeufin-bank libeufin-bank passwd admin $(get_credential_pw bank/admin) 863 864 systemctl enable --now libeufin-bank.service 865 866 BANK_BASEURL=$PROTO://$BANK_DOMAIN$PORT_SUFFIX/ 867 868 taler-harness deployment wait-taler-service taler-corebank ${BANK_BASEURL}config 869 870 sudo -u libeufin-bank libeufin-bank passwd exchange $(get_credential_pw bank/exchange) || true 871 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 872 --login exchange --exchange --public \ 873 --payto $EXCHANGE_PAYTO \ 874 --name Exchange \ 875 --password $(get_credential_pw bank/exchange) 876 877 sudo -u libeufin-bank libeufin-bank passwd merchant-admin $(get_credential_pw bank/merchant-admin) || true 878 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 879 --login merchant-admin --public \ 880 --payto $MERCHANT_PAYTO_ADMIN \ 881 --name "Default Demo Merchant" \ 882 --password $(get_credential_pw bank/merchant-admin) 883 884 sudo -u libeufin-bank libeufin-bank passwd merchant-testing $(get_credential_pw bank/merchant-testing) || true 885 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 886 --login merchant-testing --public \ 887 --payto $MERCHANT_PAYTO_TESTING \ 888 --name "Testing Merchant" \ 889 --password $(get_credential_pw bank/merchant-testing) 890 891 sudo -u libeufin-bank libeufin-bank passwd merchant-pos $(get_credential_pw bank/merchant-pos) || true 892 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 893 --login merchant-pos --public \ 894 --payto $MERCHANT_PAYTO_POS \ 895 --name "PoS Merchant" \ 896 --password $(get_credential_pw bank/merchant-pos) 897 898 sudo -u libeufin-bank libeufin-bank passwd merchant-blog $(get_credential_pw bank/merchant-blog) || true 899 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 900 --login merchant-blog --public \ 901 --payto $MERCHANT_PAYTO_BLOG \ 902 --name "Blog Merchant" \ 903 --password $(get_credential_pw bank/merchant-blog) 904 905 sudo -u libeufin-bank libeufin-bank passwd merchant-gnunet $(get_credential_pw bank/merchant-gnunet) || true 906 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 907 --login merchant-gnunet --public \ 908 --payto "$MERCHANT_PAYTO_GNUNET" \ 909 --name "GNUnet Donations Merchant" \ 910 --password $(get_credential_pw bank/merchant-gnunet) 911 912 sudo -u libeufin-bank libeufin-bank passwd merchant-taler $(get_credential_pw bank/merchant-taler) || true 913 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 914 --login merchant-taler --public \ 915 --payto "$MERCHANT_PAYTO_TALER" \ 916 --name "Taler Donations Merchant" \ 917 --password $(get_credential_pw bank/merchant-taler) 918 919 sudo -u libeufin-bank libeufin-bank passwd merchant-tor $(get_credential_pw bank/merchant-tor) || true 920 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 921 --login merchant-tor --public \ 922 --payto "$MERCHANT_PAYTO_TOR" \ 923 --name "Tor Donations Merchant" \ 924 --password $(get_credential_pw bank/merchant-tor) 925 926 sudo -u libeufin-bank libeufin-bank passwd merchant-umami $(get_credential_pw bank/merchant-umami) || true 927 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 928 --login merchant-umami --public \ 929 --payto "$MERCHANT_PAYTO_UMAMI" \ 930 --name "Umami Merchant" \ 931 --password $(get_credential_pw bank/merchant-umami) 932 933 sudo -u libeufin-bank libeufin-bank passwd merchant-paivana $(get_credential_pw bank/merchant-paivana) || true 934 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 935 --login merchant-paivana --public \ 936 --payto "$MERCHANT_PAYTO_PAIVANA" \ 937 --name "Paivana Merchant" \ 938 --password $(get_credential_pw bank/merchant-paivana) 939 940 # Special bank account without a secure password 941 sudo -u libeufin-bank libeufin-bank passwd merchant-sandbox sandbox || true 942 taler-harness deployment provision-bank-account "${BANK_BASEURL}" \ 943 --login merchant-sandbox --public \ 944 --payto "$MERCHANT_PAYTO_SANDBOX" \ 945 --name "Sandbox Merchant" \ 946 --password sandbox 947 948 # Set up exchange 949 950 ## 951 ## Configure KYC if enabled 952 ## 953 954 if [[ ${ENABLE_KYC:-0} = 1 ]]; then 955 # KYC config 956 if [[ ${KYC_DIALECT:-simple} = simple ]]; then 957 source /data/setup-kyc-simple.sh 958 elif [[ ${KYC_DIALECT:-simple} = tops ]]; then 959 source /data/setup-kyc-tops.sh 960 fi 961 else 962 rm -f /etc/taler-exchange/conf.d/sandcastle-kyc.conf 963 fi 964 965 966 if [[ ! -e /etc/taler-exchange/conf.d/sandcastle-$CURRENCY-coins.conf ]]; then 967 # Only create if necessary, as each [COIN-...] section 968 # has a unique name with a timestamp. 969 taler-harness deployment gen-coin-config \ 970 --min-amount "${CURRENCY}:0.01" \ 971 --max-amount "${CURRENCY}:100" \ 972 --no-fees \ 973 >"/etc/taler-exchange/conf.d/sandcastle-$CURRENCY-coins.conf" 974 else 975 # Exchange broke backwards compatibility, fix up existing config file. 976 sed -i 's/COIN-/COIN_/gI' "/etc/taler-exchange/conf.d/sandcastle-$CURRENCY-coins.conf" 977 fi 978 979 taler-terms-generator -i /usr/share/taler-exchange/terms/exchange-tos-v0 980 taler-terms-generator -i /usr/share/taler-exchange/terms/exchange-pp-v0 981 982 systemctl enable --now taler-exchange.target 983 984 taler-harness deployment wait-taler-service taler-exchange $PROTO://$EXCHANGE_DOMAIN$PORT_SUFFIX/config 985 taler-harness deployment wait-endpoint $PROTO://$EXCHANGE_DOMAIN$PORT_SUFFIX/management/keys 986 987 sudo -u taler-exchange-offline \ 988 taler-exchange-offline \ 989 -c /etc/taler-exchange/taler-exchange.conf \ 990 download \ 991 sign \ 992 upload 993 994 sudo -u taler-exchange-offline \ 995 taler-exchange-offline \ 996 enable-account "${EXCHANGE_PAYTO}" \ 997 wire-fee now "$WIRE_METHOD" "${CURRENCY}":0 "${CURRENCY}":0 \ 998 global-fee now "${CURRENCY}":0 "${CURRENCY}":0 "${CURRENCY}":0 1h 6a 0 \ 999 upload 1000 1001 systemctl enable --now taler-exchange-offline.timer 1002 1003 function dup_exchange_opt() { 1004 echo "$2 = $(taler-exchange-config -c /etc/taler-exchange/taler-exchange.conf -s $1 -o $2)" 1005 } 1006 1007 # 1008 # Set up exchange auditor 1009 # 1010 1011 if [[ $ENABLE_AUDITOR = 1 ]]; then 1012 systemctl enable --now taler-auditor.target 1013 fi 1014 1015 # Set up merchant backend 1016 1017 MERCHANT_BASEURL=$PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/ 1018 1019 cat <<EOF >/etc/taler-merchant/conf.d/sandcastle-merchant-terms.conf 1020 [merchant] 1021 TERMS_ETAG = merchant-tos-demo-v0 1022 TERMS_DIR = \${TALER_DATA_HOME}terms/ 1023 EOF 1024 1025 taler-terms-generator -i /usr/share/taler-merchant/terms/merchant-tos-demo-v0.en.rst -o "$(taler-merchant-config -f -s merchant -o terms_dir)" 1026 1027 systemctl enable --now taler-merchant.target 1028 taler-harness deployment wait-taler-service taler-merchant ${MERCHANT_BASEURL}config 1029 1030 function reset_merchant_pw() { 1031 pw=$(get_credential_pw merchant/$1) 1032 sudo -u taler-merchant-httpd taler-merchant-passwd --instance "$1" "$pw" 1033 if [[ $? -eq 2 ]]; then 1034 echo "Instance $1 does not exist" >&2 1035 return 2 1036 fi 1037 if [[ $? -ne 0 ]]; then 1038 echo "Failed to reset password for merchant instance $1" >&2 1039 exit 1 1040 fi 1041 } 1042 1043 # FIXME: Move this into a harness tool (that just reads a config file)? 1044 1045 instance_missing=no 1046 reset_merchant_pw admin || instance_missing=yes 1047 if [[ $instance_missing = yes ]]; then 1048 taler-harness deployment provision-merchant-instance \ 1049 ${MERCHANT_BASEURL} \ 1050 --management-token "secret-token:none" \ 1051 --instance-password $(get_credential_pw merchant/admin) \ 1052 --name Merchant \ 1053 --id admin \ 1054 --payto "$MERCHANT_PAYTO_ADMIN" 1055 fi 1056 1057 ADMIN_TOK=$(taler-harness merchant token ${MERCHANT_BASEURL} admin --password $(get_credential_pw merchant/admin)) 1058 1059 instance_missing=no 1060 reset_merchant_pw pos || instance_missing=yes 1061 if [[ $instance_missing = yes ]]; then 1062 taler-harness deployment provision-merchant-instance \ 1063 ${MERCHANT_BASEURL} \ 1064 --management-token $ADMIN_TOK \ 1065 --instance-password $(get_credential_pw merchant/pos) \ 1066 --name "POS Merchant" \ 1067 --id pos \ 1068 --payto "$MERCHANT_PAYTO_POS" 1069 fi 1070 1071 instance_missing=no 1072 reset_merchant_pw testing || instance_missing=yes 1073 if [[ $instance_missing = yes ]]; then 1074 taler-harness deployment provision-merchant-instance \ 1075 ${MERCHANT_BASEURL} \ 1076 --management-token $ADMIN_TOK \ 1077 --instance-password $(get_credential_pw merchant/testing) \ 1078 --name "Testing Merchant" \ 1079 --id testing \ 1080 --payto "$MERCHANT_PAYTO_TESTING" 1081 fi 1082 1083 instance_missing=no 1084 reset_merchant_pw blog || instance_missing=yes 1085 if [[ $instance_missing = yes ]]; then 1086 taler-harness deployment provision-merchant-instance \ 1087 ${MERCHANT_BASEURL} \ 1088 --management-token $ADMIN_TOK \ 1089 --instance-password $(get_credential_pw merchant/blog) \ 1090 --name "Blog Merchant" \ 1091 --id blog \ 1092 --payto "$MERCHANT_PAYTO_BLOG" 1093 fi 1094 1095 instance_missing=no 1096 reset_merchant_pw gnunet || instance_missing=yes 1097 if [[ $instance_missing = yes ]]; then 1098 taler-harness deployment provision-merchant-instance \ 1099 ${MERCHANT_BASEURL} \ 1100 --management-token $ADMIN_TOK \ 1101 --instance-password $(get_credential_pw merchant/gnunet) \ 1102 --name "GNUnet Merchant" \ 1103 --id gnunet \ 1104 --payto "$MERCHANT_PAYTO_GNUNET" 1105 fi 1106 1107 instance_missing=no 1108 reset_merchant_pw taler || instance_missing=yes 1109 if [[ $instance_missing = yes ]]; then 1110 taler-harness deployment provision-merchant-instance \ 1111 ${MERCHANT_BASEURL} \ 1112 --management-token $ADMIN_TOK \ 1113 --instance-password $(get_credential_pw merchant/taler) \ 1114 --name "Taler Merchant" \ 1115 --id taler \ 1116 --payto "$MERCHANT_PAYTO_TALER" 1117 fi 1118 1119 instance_missing=no 1120 reset_merchant_pw tor || instance_missing=yes 1121 if [[ $instance_missing = yes ]]; then 1122 taler-harness deployment provision-merchant-instance \ 1123 ${MERCHANT_BASEURL} \ 1124 --management-token $ADMIN_TOK \ 1125 --instance-password $(get_credential_pw merchant/tor) \ 1126 --name "Tor Merchant" \ 1127 --id tor \ 1128 --payto "$MERCHANT_PAYTO_TOR" 1129 fi 1130 1131 instance_missing=no 1132 reset_merchant_pw umami || instance_missing=yes 1133 if [[ $instance_missing = yes ]]; then 1134 taler-harness deployment provision-merchant-instance \ 1135 ${MERCHANT_BASEURL} \ 1136 --management-token $ADMIN_TOK \ 1137 --instance-password $(get_credential_pw merchant/umami) \ 1138 --name "Umami Merchant" \ 1139 --id umami \ 1140 --payto "$MERCHANT_PAYTO_UMAMI" 1141 fi 1142 1143 instance_missing=no 1144 reset_merchant_pw paivana || instance_missing=yes 1145 if [[ $instance_missing = yes ]]; then 1146 taler-harness deployment provision-merchant-instance \ 1147 ${MERCHANT_BASEURL} \ 1148 --management-token $ADMIN_TOK \ 1149 --instance-password $(get_credential_pw merchant/paivana) \ 1150 --name "Paivana Merchant" \ 1151 --id paivana \ 1152 --payto "$MERCHANT_PAYTO_PAIVANA" 1153 fi 1154 1155 # Special instance with fixed "sandbox" password 1156 sudo -u taler-merchant-httpd taler-merchant-passwd --instance sandbox sandbox || true 1157 taler-harness deployment provision-merchant-instance \ 1158 ${MERCHANT_BASEURL} \ 1159 --management-token $ADMIN_TOK \ 1160 --instance-password sandbox \ 1161 --name "sandbox merchant" \ 1162 --id sandbox \ 1163 --payto "$MERCHANT_PAYTO_SANDBOX" 1164 1165 # token families needed by demo blog 1166 1167 langs=(de en ar zh fr hi it ja ko pt pt_BR ru es sv tr uk) 1168 valid_before_ts=$(date -u +%s -d '+1 year') # one year later 1169 duration_us=$((30 * 24 * 60 * 60 * 1000000)) # 30 days 1170 validity_granularity_us=$((24 * 60 * 60 * 1000000)) # 1 day 1171 1172 # FIXME: Move this into a harness tool? 1173 for lang in "${langs[@]}"; do 1174 curl -X POST "${MERCHANT_BASEURL}instances/blog/private/tokenfamilies" \ 1175 -H "Authorization: Bearer secret-token:$(get_credential_pw merchant/blog)" \ 1176 -H "Content-Type: application/json" \ 1177 --data-raw "{ 1178 \"kind\": \"subscription\", 1179 \"slug\": \"blog_abo_${lang}\", 1180 \"name\": \"One month of access (${lang})\", 1181 \"description\": \"One month of access (${lang})\", 1182 \"description_i18n\": { 1183 \"de\": \"Ein monat lang Zugang zu den Artikeln\", 1184 \"en\": \"One month of access to articles\", 1185 \"fr\": \"Un mois d'accès aux articles\", 1186 \"es\": \"Un mes de acceso a los artículos\" 1187 }, 1188 \"valid_before\": { \"t_s\": ${valid_before_ts} }, 1189 \"duration\": { \"d_us\": ${duration_us} }, 1190 \"validity_granularity\": { \"d_us\": ${validity_granularity_us} } 1191 }" 1192 done 1193 1194 1195 # Set up the Paivana paywall. 1196 # The paywall itself is configured entirely via merchant templates, 1197 # see /etc/paivana/paivana.conf for the daemon configuration. 1198 1199 PAIVANA_INSTANCE_URL=${MERCHANT_BASEURL}instances/paivana/ 1200 PAIVANA_TOKEN=secret-token:$(get_credential_pw merchant/paivana) 1201 1202 # Subscription offered as an alternative to paying per visit. 1203 # Reuses the validity settings of the blog subscriptions above. 1204 curl -X POST "${PAIVANA_INSTANCE_URL}private/tokenfamilies" \ 1205 -H "Authorization: Bearer $PAIVANA_TOKEN" \ 1206 -H "Content-Type: application/json" \ 1207 --data-raw "{ 1208 \"kind\": \"subscription\", 1209 \"slug\": \"paivana_abo\", 1210 \"name\": \"One month of access\", 1211 \"description\": \"One month of access to $PAIVANA_DESTINATION\", 1212 \"valid_before\": { \"t_s\": ${valid_before_ts} }, 1213 \"duration\": { \"d_us\": ${duration_us} }, 1214 \"validity_granularity\": { \"d_us\": ${validity_granularity_us} } 1215 }" 1216 1217 # paivana-httpd learns which URLs cost how much from the templates 1218 # of its merchant instance. A single template covering the whole 1219 # site is enough here, as paivana-httpd runs with '-g'. 1220 paivana_template=$(cat <<EOF 1221 { 1222 "template_id": "paivana", 1223 "template_description": "Paywall for $PAIVANA_DESTINATION", 1224 "template_contract": { 1225 "template_type": "paivana", 1226 "summary": "Access to $PAIVANA_DESTINATION", 1227 "website_regex": ".*", 1228 "max_pickup_duration": { "d_us": $((24 * 60 * 60 * 1000000)) }, 1229 "choices": [ 1230 { 1231 "amount": "$CURRENCY:1", 1232 "description": "Pay for one day of access" 1233 }, 1234 { 1235 "amount": "$CURRENCY:10", 1236 "description": "Buy a one month subscription", 1237 "outputs": [ { "type": "token", "token_family_slug": "paivana_abo" } ] 1238 }, 1239 { 1240 "amount": "$CURRENCY:0", 1241 "description": "Use my subscription", 1242 "inputs": [ { "type": "token", "token_family_slug": "paivana_abo" } ], 1243 "outputs": [ { "type": "token", "token_family_slug": "paivana_abo" } ] 1244 } 1245 ] 1246 } 1247 } 1248 EOF 1249 ) 1250 1251 paivana_response=$(mktemp) 1252 paivana_status=$(curl -X POST "${PAIVANA_INSTANCE_URL}private/templates" \ 1253 -H "Authorization: Bearer $PAIVANA_TOKEN" \ 1254 -H "Content-Type: application/json" \ 1255 --data-raw "$paivana_template" \ 1256 -s -o "$paivana_response" -w '%{http_code}') 1257 1258 case "$paivana_status" in 1259 204) 1260 ;; 1261 409) 1262 # Template exists already, update it so that changes take effect. 1263 paivana_status=$(curl -X PATCH "${PAIVANA_INSTANCE_URL}private/templates/paivana" \ 1264 -H "Authorization: Bearer $PAIVANA_TOKEN" \ 1265 -H "Content-Type: application/json" \ 1266 --data-raw "$(jq 'del(.template_id)' <<<"$paivana_template")" \ 1267 -s -o "$paivana_response" -w '%{http_code}') 1268 if [[ $paivana_status != 204 ]]; then 1269 echo "Failed to update Paivana template (HTTP $paivana_status)" >&2 1270 cat "$paivana_response" >&2 1271 exit 1 1272 fi 1273 ;; 1274 *) 1275 echo "Failed to create Paivana template (HTTP $paivana_status)" >&2 1276 cat "$paivana_response" >&2 1277 exit 1 1278 ;; 1279 esac 1280 rm -f "$paivana_response" 1281 1282 systemctl enable --now paivana-httpd.socket 1283 systemctl enable --now paivana-httpd.service 1284 1285 1286 # Set up Donau 1287 1288 cat <<EOF >/etc/donau/conf.d/sandcastle.conf 1289 [donau] 1290 CURRENCY = $CURRENCY 1291 LEGAL_DOMAIN = Gnuland 1292 EXPIRE_LEGAL_YEARS = 3 1293 # We don't do the token yet, as the merchant doesn't support 1294 # authenticating with donau. 1295 # ADMIN_BEARER_TOKEN = secret-token:secret 1296 EOF 1297 1298 donau-dbconfig 1299 1300 if [[ ! -e /etc/donau/conf.d/sandcastle-$CURRENCY-units.conf ]]; then 1301 # Only create if necessary 1302 taler-harness deployment gen-doco-config \ 1303 --min-amount "${CURRENCY}:0.01" \ 1304 --max-amount "${CURRENCY}:100" \ 1305 >"/etc/donau/conf.d/sandcastle-$CURRENCY-units.conf" 1306 fi 1307 1308 systemctl enable --now donau.target 1309 1310 DONAU_BASE_URL=$PROTO://$DONAU_DOMAIN$PORT_SUFFIX/ 1311 1312 taler-harness deployment wait-taler-service donau ${DONAU_BASE_URL}config 1313 1314 if [[ ${ENABLE_TALDIR:-0} == 1 ]]; then 1315 # Mailbox and Directory 1316 mkdir -p /etc/taler-directory 1317 cp /usr/share/taler-directory/taldir.conf.example /etc/taler-directory/taler-directory.conf 1318 taler-directory-dbconfig 1319 systemctl enable --now taler-directory.service 1320 fi 1321 1322 if [[ ${ENABLE_MAILBOX:-0} == 1 ]]; then 1323 mkdir -p /etc/taler-mailbox 1324 cp /usr/share/taler-mailbox/mailbox.conf.example /etc/taler-mailbox/taler-mailbox.conf 1325 sed -i 's/localhost:11000/localhost:12000/' /etc/taler-mailbox/taler-mailbox.conf 1326 taler-mailbox-dbconfig 1327 systemctl enable --now taler-mailbox.service 1328 fi 1329 1330 GNUNET_TOK=$(taler-harness merchant token ${MERCHANT_BASEURL}instances/gnunet/ gnunet --password $(get_credential_pw merchant/gnunet)) 1331 taler-harness deployment provision-merchant-donau \ 1332 --merchant-auth-token $GNUNET_TOK \ 1333 --merchant-base-url $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/gnunet/ \ 1334 --donau-base-url $DONAU_BASE_URL \ 1335 --donau-auth-token secret-token:secret \ 1336 --currency $CURRENCY 1337 1338 TALER_TOK=$(taler-harness merchant token ${MERCHANT_BASEURL}instances/taler/ taler --password $(get_credential_pw merchant/taler)) 1339 taler-harness deployment provision-merchant-donau \ 1340 --merchant-auth-token $TALER_TOK \ 1341 --merchant-base-url $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/taler/ \ 1342 --donau-base-url $DONAU_BASE_URL \ 1343 --donau-auth-token secret-token:secret \ 1344 --currency $CURRENCY 1345 1346 TOR_TOK=$(taler-harness merchant token ${MERCHANT_BASEURL}instances/tor/ tor --password $(get_credential_pw merchant/tor)) 1347 taler-harness deployment provision-merchant-donau \ 1348 --merchant-auth-token $TOR_TOK \ 1349 --merchant-base-url $PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/tor/ \ 1350 --donau-base-url $DONAU_BASE_URL \ 1351 --donau-auth-token secret-token:secret \ 1352 --currency $CURRENCY 1353 1354 UMAMI_TOK=$(taler-harness merchant token ${MERCHANT_BASEURL}instances/umami/ umami --password $(get_credential_pw merchant/umami)) 1355 1356 # Now we set up the taler-merchant-demos 1357 1358 systemctl enable --now taler-demo-landing 1359 systemctl enable --now taler-demo-blog 1360 systemctl enable --now taler-demo-donations 1361 1362 # Turnstile (drupal/php) 1363 if [[ ${ENABLE_TURNSTILE:-1} = 1 ]]; then 1364 1365 systemctl enable --now php8.4-fpm 1366 1367 DRUPAL_DB_PW=$(get_credential_pw db/drupal) 1368 DRUPAL_ADMIN_PW=$(get_credential_pw drupal/admin) 1369 1370 sudo -i -u postgres psql postgres -c "CREATE ROLE drupal WITH login;" || true 1371 sudo -i -u postgres psql postgres -c "ALTER ROLE drupal password '$DRUPAL_DB_PW';" 1372 sudo -u postgres createdb drupal --owner=drupal || true 1373 1374 # Needed by PHP's composer 1375 export HOME=/root 1376 1377 # FIXME: Would probably be better to checkout output of 1378 # drush status --fields=bootstrap --format=string 1379 1380 cd /talerdata/ 1381 if [[ ! -e /talerdata/sandcastle-drupal ]]; then 1382 composer create-project drupal/recommended-project:^10 sandcastle-drupal 1383 cd /talerdata/sandcastle-drupal 1384 composer require drush/drush 1385 # This can take a ridiculous amount of time! 1386 COMPOSER_PROCESS_TIMEOUT=0 composer exec -- drush site-install demo_umami --account-name=admin --account-pass=$DRUPAL_ADMIN_PW --account-mail=admin@localhost --db-url=pgsql://drupal:$DRUPAL_DB_PW@localhost/drupal --site-name=SandcastleUmami --yes 1387 fi 1388 1389 chown -R www-data:www-data /talerdata/sandcastle-drupal/ 1390 1391 ln -sf /opt/turnstile /talerdata/sandcastle-drupal/web/modules/taler_turnstile 1392 1393 snip=$(cat <<'EOF' 1394 $settings['reverse_proxy'] = TRUE; 1395 $settings['reverse_proxy_addresses'] = ['127.0.0.1', '10.0.0.0/8']; 1396 $settings['trusted_host_patterns'] = ['.*']; 1397 EOF 1398 ) 1399 1400 update_config_block /talerdata/sandcastle-drupal/web/sites/default/settings.php SANDCASTLE "$snip" 1401 1402 cd /talerdata/sandcastle-drupal 1403 composer exec -- drush upwd admin $DRUPAL_ADMIN_PW 1404 composer exec -- drush en taler_turnstile 1405 composer exec -- drush config:set taler_turnstile.settings access_token "$UMAMI_TOK" --yes 1406 composer exec -- drush config:set taler_turnstile.settings payment_backend_url "$PROTO://$MERCHANT_DOMAIN$PORT_SUFFIX/instances/umami/" --yes 1407 composer exec -- drush config:set --input-format=yaml taler_turnstile.settings enabled_content_types '["article", "recipe"]' --yes 1408 1409 snip=$(cat <<'EOF' | sed "s/@CURRENCY@/$CURRENCY/" 1410 $storage = \Drupal::entityTypeManager()->getStorage('taler_turnstile_price_category'); 1411 $e = $storage->create(['id'=>"normal", 'label'=>'Normal', 'description' => "Normal Article Price", 'prices' => ['%none%' => ['@CURRENCY@' => '0.3']]]); 1412 try { 1413 $e->save(); 1414 } catch (Exception $ex) { 1415 echo $ex->getMessage(); 1416 echo "\n"; 1417 } 1418 EOF 1419 ) 1420 composer exec -- drush php:eval "$snip" 1421 1422 snip=$(cat <<'EOF' 1423 $prcat_storage = \Drupal::entityTypeManager()->getStorage('taler_turnstile_price_category'); 1424 $node_storage = \Drupal::entityTypeManager()->getStorage('node'); 1425 $prcat = $prcat_storage->load('normal'); 1426 $nodes = $node_storage->loadByProperties(['type'=> ['article', 'recipe']]); 1427 foreach ($nodes as $k => $node) { 1428 echo 'updating node ' . $k . "\n"; 1429 if (!$node->hasField('field_taler_turnstile_prcat')) { 1430 echo 'prcat missing' . "\n"; 1431 continue; 1432 } 1433 $node->set('field_taler_turnstile_prcat', $prcat); 1434 $node->save(); 1435 } 1436 EOF 1437 ) 1438 composer exec -- drush php:eval "$snip" 1439 1440 composer exec -- drush cr 1441 1442 fi 1443 1444 cd / 1445 1446 # FIXME: Maybe do some taler-wallet-cli test? 1447 # FIXME: How do we report errors occurring during the setup script?