sandcastle-ng

Scripts for the deployment of Sandcastle (GNU Taler)
Log | Files | Refs | README

commit 91f792719cf1d0b6e9f31d197596112e9df0adf6
parent 7f743fddc8e1a8f67aabaa99e55380f9c90aba06
Author: Florian Dold <dold@taler.net>
Date:   Sat, 22 Aug 2026 20:21:57 +0200

sandcastle: keep subscription token families valid forever

Diffstat:
Mscripts/demo/setup-sandcastle.sh | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 77 insertions(+), 11 deletions(-)

diff --git a/scripts/demo/setup-sandcastle.sh b/scripts/demo/setup-sandcastle.sh @@ -1236,16 +1236,77 @@ taler-harness deployment provision-merchant-instance \ # token families needed by demo blog langs=(de en ar zh fr hi it ja ko pt pt_BR ru es sv tr uk) -valid_before_ts=$(date -u +%s -d '+1 year') # one year later duration_us=$((30 * 24 * 60 * 60 * 1000000)) # 30 days validity_granularity_us=$((24 * 60 * 60 * 1000000)) # 1 day +# valid_before is intentionally omitted so token families remain valid forever. + +provision_token_family() { + local instance_url=$1 + local access_token=$2 + local slug=$3 + local request_body=$4 + local response_file + local response_status + local update_body + + response_file=$(mktemp) + response_status=$(curl -X POST "${instance_url}private/tokenfamilies" \ + -H "Authorization: Bearer $access_token" \ + -H "Content-Type: application/json" \ + --data-raw "$request_body" \ + --silent --show-error \ + --output "$response_file" \ + --write-out '%{http_code}') + + case "$response_status" in + 204) + ;; + 409) + response_status=$(curl "${instance_url}private/tokenfamilies/${slug}" \ + -H "Authorization: Bearer $access_token" \ + --silent --show-error \ + --output "$response_file" \ + --write-out '%{http_code}') + if [[ $response_status != 200 ]]; then + echo "Failed to retrieve existing token family ${slug} (HTTP $response_status)" >&2 + cat "$response_file" >&2 + rm -f "$response_file" + return 1 + fi + + # PATCH only the mutable fields, preserving the original validity start. + # Omitting valid_before changes the validity end to "forever". + update_body=$(jq ' + {name, description, description_i18n, valid_after} + + (if .extra_data == null then {} else {extra_data} end) + ' "$response_file") + response_status=$(curl -X PATCH "${instance_url}private/tokenfamilies/${slug}" \ + -H "Authorization: Bearer $access_token" \ + -H "Content-Type: application/json" \ + --data-raw "$update_body" \ + --silent --show-error \ + --output "$response_file" \ + --write-out '%{http_code}') + if [[ $response_status != 204 ]]; then + echo "Failed to update token family ${slug} (HTTP $response_status)" >&2 + cat "$response_file" >&2 + rm -f "$response_file" + return 1 + fi + ;; + *) + echo "Failed to create token family ${slug} (HTTP $response_status)" >&2 + cat "$response_file" >&2 + rm -f "$response_file" + return 1 + ;; + esac + rm -f "$response_file" +} # FIXME: Move this into a harness tool? for lang in "${langs[@]}"; do - curl -X POST "${MERCHANT_BASEURL}instances/blog/private/tokenfamilies" \ - -H "Authorization: Bearer secret-token:$(get_credential_pw merchant/blog)" \ - -H "Content-Type: application/json" \ - --data-raw "{ + blog_token_family="{ \"kind\": \"subscription\", \"slug\": \"blog_abo_${lang}\", \"name\": \"One month of access (${lang})\", @@ -1256,10 +1317,14 @@ for lang in "${langs[@]}"; do \"fr\": \"Un mois d'accès aux articles\", \"es\": \"Un mes de acceso a los artículos\" }, - \"valid_before\": { \"t_s\": ${valid_before_ts} }, \"duration\": { \"d_us\": ${duration_us} }, \"validity_granularity\": { \"d_us\": ${validity_granularity_us} } }" + provision_token_family \ + "${MERCHANT_BASEURL}instances/blog/" \ + "secret-token:$(get_credential_pw merchant/blog)" \ + "blog_abo_${lang}" \ + "$blog_token_family" done @@ -1272,18 +1337,19 @@ PAIVANA_TOKEN=secret-token:$(get_credential_pw merchant/paivana) # Subscription offered as an alternative to paying per visit. # Reuses the validity settings of the blog subscriptions above. -curl -X POST "${PAIVANA_INSTANCE_URL}private/tokenfamilies" \ - -H "Authorization: Bearer $PAIVANA_TOKEN" \ - -H "Content-Type: application/json" \ - --data-raw "{ +paivana_token_family="{ \"kind\": \"subscription\", \"slug\": \"paivana_abo\", \"name\": \"One month of access\", \"description\": \"One month of access to $PAIVANA_DESTINATION\", - \"valid_before\": { \"t_s\": ${valid_before_ts} }, \"duration\": { \"d_us\": ${duration_us} }, \"validity_granularity\": { \"d_us\": ${validity_granularity_us} } }" +provision_token_family \ + "$PAIVANA_INSTANCE_URL" \ + "$PAIVANA_TOKEN" \ + paivana_abo \ + "$paivana_token_family" # paivana-httpd learns which URLs cost how much from the templates # of its merchant instance. A single template covering the whole