From d0b0722a7b725a034656aeecb0f21c30dbe3ffbe Mon Sep 17 00:00:00 2001 From: nocci Date: Thu, 11 Dec 2025 12:22:48 +0000 Subject: [PATCH] Initial Taler stack with templated configs, db init script, caddy proxy --- .env.example | 59 ++++++++++ .gitignore | 1 + Dockerfile | 33 ++++++ bank/conf/bank.conf.tmpl | 48 +++++++++ caddy/Caddyfile | 15 +++ compose.yml | 115 ++++++++++++++++++++ entrypoints/with-dbinit.sh | 119 +++++++++++++++++++++ exchange/conf/conf.d/99-exchange.conf.tmpl | 59 ++++++++++ exchange/conf/overrides.conf | 1 + exchange/conf/taler-exchange.conf.tmpl | 8 ++ exchange/privacy/privacy.txt | 55 ++++++++++ exchange/terms/terms.txt | 44 ++++++++ merchant/conf/merchant.conf.tmpl | 12 +++ postgres/init/01-init-taler.sh | 16 +++ scripts/enable-exchange-account.sh | 61 +++++++++++ scripts/provision-bank-user.sh | 77 +++++++++++++ 16 files changed, 723 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 bank/conf/bank.conf.tmpl create mode 100644 caddy/Caddyfile create mode 100644 compose.yml create mode 100644 entrypoints/with-dbinit.sh create mode 100644 exchange/conf/conf.d/99-exchange.conf.tmpl create mode 100644 exchange/conf/overrides.conf create mode 100644 exchange/conf/taler-exchange.conf.tmpl create mode 100644 exchange/privacy/privacy.txt create mode 100644 exchange/terms/terms.txt create mode 100644 merchant/conf/merchant.conf.tmpl create mode 100644 postgres/init/01-init-taler.sh create mode 100644 scripts/enable-exchange-account.sh create mode 100644 scripts/provision-bank-user.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..722da3a --- /dev/null +++ b/.env.example @@ -0,0 +1,59 @@ +POSTGRES_HOST=postgres +POSTGRES_PORT=5432 +POSTGRES_PASSWORD=taler +POSTGRES_ADMIN_USER=postgres + +TALER_EXCHANGE_DB=talerexchange +TALER_EXCHANGE_DB_USER=talerexchange +TALER_EXCHANGE_DB_PASSWORD=taler + +TALER_MERCHANT_DB=talermerchant +TALER_MERCHANT_DB_USER=talermerchant +TALER_MERCHANT_DB_PASSWORD=taler + +LIBEUFIN_DB_NAME=libeufinbank +LIBEUFIN_DB_USER=libeufinbank +LIBEUFIN_DB_PASSWORD=taler +LIBEUFIN_ADMIN_USER=admin +LIBEUFIN_ADMIN_PASSWORD= +LIBEUFIN_MERCHANT_USER=demogeldbank +LIBEUFIN_MERCHANT_PASSWORD= +LIBEUFIN_MERCHANT_TOKEN= +LIBEUFIN_USER=demogeld +LIBEUFIN_USER_PASSWORD= +LIBEUFIN_DEBIT_THRESHOLD=DEMOGELD:1000000 + +# Exchange offline account enablement +ENABLE_EXCHANGE_ACCOUNT=0 +PAYTO_URI=payto://x-taler-bank/yourbank.domain.tld/demogeld?receiver-name=demogeld +EXCHANGE_KEYS_URL=http://exchange.internal:8081/keys +EXCHANGE_WAIT_RETRIES=60 +EXCHANGE_WAIT_INTERVAL=2 +# Optional curl flags for HTTPS with custom certs, etc. Example: "-k" +EXCHANGE_CURL_OPTS= + +# Caddy reverse proxy +CADDY_ACME_EMAIL=ops@example.com +BANK_HOST=bank.domain.tld +EXCHANGE_HOST=exchange.domain.tld +MERCHANT_HOST=merchant.domain.tld + +# Secrets path (host path mounted into /etc/taler/secrets) +EXCHANGE_SECRETS_PATH=./exchange/secrets + +# Master key (public) for exchange/merchant configs +MASTER_PUBLIC_KEY= + +# Optional token provisioning output path +TOKEN_OUTPUT=bank/token-info.txt + +TALER_DOMAIN=localhost +TALER_EXCHANGE_PORT=8081 +TALER_MERCHANT_PORT=9966 +LIBEUFIN_BANK_PORT=8080 +EXCHANGE_BASE_URL=https://exchange.domain.tld/ +EXCHANGE_SHOPPING_URL=https://exchange.domain.tld/ +OPEN_BANKING_GATEWAY_URL=https://bank.domain.tld +BANK_BASE_URL=https://bank.domain.tld/ + +TALER_CURRENCY=DEMOGELD diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0a550b7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM debian:sid + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + build-essential git automake libtool pkg-config \ + libgnutls28-dev libjansson-dev libsqlite3-dev \ + postgresql-client curl gnupg gettext-base \ + openjdk-17-jdk maven \ + && rm -rf /var/lib/apt/lists/* + +# GNUnet (falls nicht schon systemweit neu genug) +RUN git clone https://git.taler.net/gnunet.git /src/gnunet && \ + cd /src/gnunet && ./bootstrap && \ + ./configure --prefix=/usr && make -j$(nproc) && make install + +# Taler Exchange + Merchant +RUN git clone https://git.taler.net/exchange.git /src/exchange && \ + cd /src/exchange && ./bootstrap && \ + ./configure --prefix=/usr && make -j$(nproc) && make install && \ + git clone https://git.taler.net/merchant.git /src/merchant && \ + cd /src/merchant && ./bootstrap && \ + ./configure --prefix=/usr && make -j$(nproc) && make install + +# LibEuFin (Bank) +RUN git clone https://git.taler.net/libeufin.git /src/libeufin && \ + cd /src/libeufin && ./bootstrap && \ + ./configure --prefix=/usr && make -j$(nproc) && make install + +# Shared entrypoint for dbinit + service start +COPY entrypoints/with-dbinit.sh /usr/local/bin/with-dbinit.sh +COPY scripts/enable-exchange-account.sh /usr/local/bin/enable-exchange-account.sh +RUN chmod +x /usr/local/bin/with-dbinit.sh /usr/local/bin/enable-exchange-account.sh diff --git a/bank/conf/bank.conf.tmpl b/bank/conf/bank.conf.tmpl new file mode 100644 index 0000000..39d2c4b --- /dev/null +++ b/bank/conf/bank.conf.tmpl @@ -0,0 +1,48 @@ +[libeufin-bank] +# Internal currency of the libeufin-bank +CURRENCY = DEMOGELD + +# Supported payment target type, choose x-taler-bank for this stack +WIRE_TYPE = x-taler-bank + +# Base URL as seen by clients; adjust via BANK_BASE_URL +BASE_URL = ${BANK_BASE_URL:-https://${BANK_HOST:-ob.antifa.ltd}/} + +# Display name +NAME = "Demogeld Taler Bank" + +# Fees and limits for demo operation +WIRE_TRANSFER_FEES = DEMOGELD:0 +MIN_WIRE_TRANSFER_AMOUNT = DEMOGELD:0 +MAX_WIRE_TRANSFER_AMOUNT = DEMOGELD:200 +DEFAULT_DEBT_LIMIT = DEMOGELD:200 +REGISTRATION_BONUS = DEMOGELD:50 + +# Self-service options +ALLOW_REGISTRATION = yes +ALLOW_ACCOUNT_DELETION = no +ALLOW_EDIT_NAME = yes + +# Serving parameters +SERVE = tcp +PORT = 8080 +BIND_TO = 0.0.0.0 + +# Suggested exchange for withdrawals +SUGGESTED_WITHDRAWAL_EXCHANGE = ${EXCHANGE_BASE_URL:-https://${EXCHANGE_HOST:-exchange.antifa.ltd}/} + +# Password hashing +PWD_HASH_ALGORITHM = bcrypt +PWD_HASH_CONFIG = { "cost": 8 } +PWD_CHECK = yes +PWD_AUTH_COMPAT = no + +# GC settings +GC_ABORT_AFTER = 15m +GC_CLEAN_AFTER = 14d +GC_DELETE_AFTER = 10year + +[libeufin-bankdb-postgres] +# JDBC URL to the Postgres instance from compose. Keep in sync with postgres/init SQL and compose env. +CONFIG = jdbc:postgresql://postgres:5432/libeufinbank?user=libeufinbank&password=taler&ssl=false&connectTimeout=5 +sql_dir = /usr/share/libeufin diff --git a/caddy/Caddyfile b/caddy/Caddyfile new file mode 100644 index 0000000..8ae3657 --- /dev/null +++ b/caddy/Caddyfile @@ -0,0 +1,15 @@ +{ + email {$CADDY_ACME_EMAIL} +} + +{$BANK_HOST} { + reverse_proxy bank:8080 +} + +{$EXCHANGE_HOST} { + reverse_proxy exchange:8081 +} + +{$MERCHANT_HOST} { + reverse_proxy merchant:9966 +} diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..00a8c78 --- /dev/null +++ b/compose.yml @@ -0,0 +1,115 @@ +services: + postgres: + image: postgres:16 + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-taler} + volumes: + - pgdata:/var/lib/postgresql/data + - ./postgres/init:/docker-entrypoint-initdb.d:ro + + exchange: + image: taler-stack:build + entrypoint: ["/usr/local/bin/with-dbinit.sh"] + command: ["taler-exchange-httpd", "-c", "/etc/taler/taler-exchange.conf"] + environment: + DB_NAME: ${TALER_EXCHANGE_DB:-talerexchange} + INIT_CMD: taler-exchange-dbinit -c /etc/taler/taler-exchange.conf + PGHOST: ${POSTGRES_HOST:-postgres} + PGUSER: ${POSTGRES_ADMIN_USER:-postgres} + PGPASSWORD: ${POSTGRES_PASSWORD:-taler} + EXCHANGE_BASE_URL: ${EXCHANGE_BASE_URL:-https://exchange.antifa.ltd/} + EXCHANGE_SHOPPING_URL: ${EXCHANGE_SHOPPING_URL:-https://exchange.antifa.ltd/} + OPEN_BANKING_GATEWAY_URL: ${OPEN_BANKING_GATEWAY_URL:-https://ob.antifa.ltd} + PAYTO_URI: ${PAYTO_URI:-payto://x-taler-bank/ob.antifa.ltd/demogeld?receiver-name=demogeld} + EXCHANGE_HOST: ${EXCHANGE_HOST:-exchange.antifa.ltd} + BANK_HOST: ${BANK_HOST:-ob.antifa.ltd} + depends_on: [postgres] + volumes: + - ./exchange/conf:/etc/taler + - ${EXCHANGE_SECRETS_PATH:-./exchange/secrets}:/etc/taler/secrets + - ./exchange/terms:/etc/taler-exchange/terms + - ./exchange/privacy:/etc/taler-exchange/privacy + ports: + - "8081:8081" # intern, später via Reverse Proxy auf 443 + + exchange-account-init: + image: taler-stack:build + depends_on: [exchange] + environment: + ENABLE_EXCHANGE_ACCOUNT: ${ENABLE_EXCHANGE_ACCOUNT:-0} + PAYTO_URI: ${PAYTO_URI:-payto://x-taler-bank/ob.antifa.ltd/demogeld?receiver-name=demogeld} + EXCHANGE_CONFIG: /etc/taler/taler-exchange.conf + EXCHANGE_KEYS_URL: ${EXCHANGE_KEYS_URL:-http://exchange:8081/keys} + EXCHANGE_WAIT_RETRIES: ${EXCHANGE_WAIT_RETRIES:-60} + EXCHANGE_WAIT_INTERVAL: ${EXCHANGE_WAIT_INTERVAL:-2} + EXCHANGE_CURL_OPTS: ${EXCHANGE_CURL_OPTS:-} + volumes: + - ./exchange/conf:/etc/taler + - ${EXCHANGE_SECRETS_PATH:-./exchange/secrets}:/etc/taler/secrets + - ./exchange/terms:/etc/taler-exchange/terms + - ./exchange/privacy:/etc/taler-exchange/privacy + command: ["/usr/local/bin/enable-exchange-account.sh"] + restart: "no" + + merchant: + image: taler-stack:build + entrypoint: ["/usr/local/bin/with-dbinit.sh"] + command: ["taler-merchant-httpd", "-c", "/etc/taler-merchant/merchant.conf"] + environment: + DB_NAME: ${TALER_MERCHANT_DB:-talermerchant} + INIT_CMD: taler-merchant-dbinit -c /etc/taler-merchant/merchant.conf + PGHOST: ${POSTGRES_HOST:-postgres} + PGUSER: ${POSTGRES_ADMIN_USER:-postgres} + PGPASSWORD: ${POSTGRES_PASSWORD:-taler} + EXCHANGE_BASE_URL: ${EXCHANGE_BASE_URL:-https://exchange.antifa.ltd/} + EXCHANGE_HOST: ${EXCHANGE_HOST:-exchange.antifa.ltd} + depends_on: [postgres, exchange] + volumes: + - ./merchant/conf:/etc/taler-merchant + ports: + - "9966:9966" + + bank: + image: taler-stack:build + entrypoint: ["/usr/local/bin/with-dbinit.sh"] + command: ["libeufin-bank", "serve", "-c", "/etc/libeufin/bank.conf"] + environment: + DB_NAME: ${LIBEUFIN_DB_NAME:-libeufinbank} + INIT_CMD: libeufin-bank dbinit -c /etc/libeufin/bank.conf + PGHOST: ${POSTGRES_HOST:-postgres} + PGUSER: ${POSTGRES_ADMIN_USER:-postgres} + PGPASSWORD: ${POSTGRES_PASSWORD:-taler} + BANK_BASE_URL: ${BANK_BASE_URL:-https://ob.antifa.ltd/} + BANK_HOST: ${BANK_HOST:-ob.antifa.ltd} + EXCHANGE_BASE_URL: ${EXCHANGE_BASE_URL:-https://exchange.antifa.ltd/} + EXCHANGE_HOST: ${EXCHANGE_HOST:-exchange.antifa.ltd} + LIBEUFIN_ADMIN_USER: ${LIBEUFIN_ADMIN_USER:-admin} + LIBEUFIN_ADMIN_PASSWORD: ${LIBEUFIN_ADMIN_PASSWORD:-} + LIBEUFIN_USER: ${LIBEUFIN_USER:-demogeld} + LIBEUFIN_USER_PASSWORD: ${LIBEUFIN_USER_PASSWORD:-} + depends_on: [postgres] + volumes: + - ./bank/conf:/etc/libeufin + ports: + - "8080:8080" + + caddy: + image: caddy:2 + depends_on: [exchange, merchant, bank] + ports: + - "80:80" + - "443:443" + volumes: + - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro + - caddy_data:/data + - caddy_config:/config + environment: + CADDY_ACME_EMAIL: ${CADDY_ACME_EMAIL:-ops@example.com} + BANK_HOST: ${BANK_HOST:-ob.antifa.ltd} + EXCHANGE_HOST: ${EXCHANGE_HOST:-exchange.antifa.ltd} + MERCHANT_HOST: ${MERCHANT_HOST:-merchant.antifa.ltd} + +volumes: + pgdata: {} + caddy_data: {} + caddy_config: {} diff --git a/entrypoints/with-dbinit.sh b/entrypoints/with-dbinit.sh new file mode 100644 index 0000000..625190d --- /dev/null +++ b/entrypoints/with-dbinit.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${PGHOST:=postgres}" +: "${PGPORT:=5432}" +: "${PGUSER:=postgres}" +: "${PGPASSWORD:=taler}" + +if [[ -z "${DB_NAME:-}" ]]; then + echo "DB_NAME not set; cannot run dbinit" >&2 + exit 1 +fi + +if [[ -z "${INIT_CMD:-}" ]]; then + echo "INIT_CMD not set; cannot run dbinit" >&2 + exit 1 +fi + +SERVICE_CMD=("$@") + +render_template() { + local src="$1" + local dst="$2" + if [[ -f "${src}" ]]; then + echo "Rendering template ${src} -> ${dst}" + envsubst < "${src}" > "${dst}" + fi +} + +render_templates() { + case "${SERVICE_CMD[0]:-}" in + taler-exchange-httpd|taler-exchange-*) + render_template /etc/taler/taler-exchange.conf.tmpl /etc/taler/taler-exchange.conf + render_template /etc/taler/conf.d/99-exchange.conf.tmpl /etc/taler/conf.d/99-exchange.conf + ;; + taler-merchant-httpd|taler-merchant-*) + render_template /etc/taler-merchant/merchant.conf.tmpl /etc/taler-merchant/merchant.conf + ;; + libeufin-bank) + render_template /etc/libeufin/bank.conf.tmpl /etc/libeufin/bank.conf + ;; + esac +} + +render_templates + +wait_for_db() { + echo "Waiting for Postgres at ${PGHOST}:${PGPORT}..." + until pg_isready -h "${PGHOST}" -p "${PGPORT}" -U "${PGUSER}" >/dev/null 2>&1; do + sleep 1 + done +} + +db_has_tables() { + local count + count="$(psql -h "${PGHOST}" -p "${PGPORT}" -U "${PGUSER}" -d "${DB_NAME}" -Atc \ + "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public';")" + [[ "${count}" != "0" ]] +} + +run_init() { + if [[ "${SKIP_DBINIT:-}" == "1" ]]; then + echo "SKIP_DBINIT=1 set; skipping dbinit for ${DB_NAME}" + return + fi + + echo "Running dbinit for ${DB_NAME}: ${INIT_CMD}" + # shellcheck disable=SC2206 + init_arr=(${INIT_CMD}) + "${init_arr[@]}" +} + +set_libeufin_admin_password() { + # Only relevant for libeufin-bank service and if credentials are provided. + if [[ "${SERVICE_CMD[0]:-}" != "libeufin-bank" ]]; then + return + fi + if [[ -z "${LIBEUFIN_ADMIN_USER:-}" || -z "${LIBEUFIN_ADMIN_PASSWORD:-}" ]]; then + return + fi + echo "Setting LibEuFin admin password for user ${LIBEUFIN_ADMIN_USER}" + if ! printf "%s\n%s\n" "${LIBEUFIN_ADMIN_PASSWORD}" "${LIBEUFIN_ADMIN_PASSWORD}" | \ + libeufin-bank passwd "${LIBEUFIN_ADMIN_USER}" -c /etc/libeufin/bank.conf; then + echo "Warning: failed to set LibEuFin admin password" >&2 + fi +} + +ensure_libeufin_user() { + # Create/update a non-admin bank user if configured. + if [[ "${SERVICE_CMD[0]:-}" != "libeufin-bank" ]]; then + return + fi + if [[ -z "${LIBEUFIN_USER:-}" || -z "${LIBEUFIN_USER_PASSWORD:-}" ]]; then + return + fi + echo "Ensuring LibEuFin user ${LIBEUFIN_USER}" + if ! libeufin-bank users add "${LIBEUFIN_USER}" --password "${LIBEUFIN_USER_PASSWORD}" \ + -c /etc/libeufin/bank.conf 2>/tmp/libeufin-add-user.log; then + if grep -qi "already exists" /tmp/libeufin-add-user.log; then + echo "LibEuFin user ${LIBEUFIN_USER} already exists; skipping creation." + else + echo "Warning: failed to ensure LibEuFin user ${LIBEUFIN_USER}" >&2 + cat /tmp/libeufin-add-user.log >&2 + fi + fi +} + +wait_for_db +if db_has_tables; then + echo "Database ${DB_NAME} already initialized; skipping dbinit." +else + run_init +fi +render_templates +set_libeufin_admin_password +ensure_libeufin_user + +echo "Starting service command: ${SERVICE_CMD[*]}" +exec "${SERVICE_CMD[@]}" diff --git a/exchange/conf/conf.d/99-exchange.conf.tmpl b/exchange/conf/conf.d/99-exchange.conf.tmpl new file mode 100644 index 0000000..5397dc9 --- /dev/null +++ b/exchange/conf/conf.d/99-exchange.conf.tmpl @@ -0,0 +1,59 @@ +[exchange] +BASE_URL = ${EXCHANGE_BASE_URL:-https://${EXCHANGE_HOST:-exchange.antifa.ltd}/} +DB = postgres +MASTER_PUBLIC_KEY = ${MASTER_PUBLIC_KEY:-QZEPPYMSPF9RKNDCJ1SYMYY5RCV0Y0827SP2FZ9Z1J8C7PEW6CDG} +SERVE = tcp +PORT = 8081 +BIND_TO = 0.0.0.0 +IDLE_RESERVE_EXPIRATION_TIME = 4 weeks +RESHARE_RESERVE_EXPIRATION_TIME = 8 weeks +TERMS_DIR = /etc/taler-exchange/terms +PRIVACY_DIR = /etc/taler-exchange/privacy +TINY_AMOUNT = DEMOGELD:0.01 +SHOPPING_URL = ${EXCHANGE_SHOPPING_URL:-${EXCHANGE_BASE_URL:-https://${EXCHANGE_HOST:-exchange.antifa.ltd}/}} +OPEN_BANKING_GATEWAY_URL = ${OPEN_BANKING_GATEWAY_URL:-https://${BANK_HOST:-ob.antifa.ltd}} + +[exchangedb-postgres] +CONFIG = postgres://talerexchange:taler@postgres:5432/talerexchange + +[coin_demogeld_1] +VALUE = DEMOGELD:0.50 +CIPHER = RSA +RSA_KEYSIZE = 2048 +DURATION_WITHDRAW = 12 weeks +DURATION_SPEND = 52 weeks +DURATION_DEPOSIT = 104 weeks +DURATION_LEGAL = 208 weeks +FEE_WITHDRAW = 0.00 DEMOGELD +FEE_DEPOSIT = 0.00 DEMOGELD +FEE_REFRESH = 0.00 DEMOGELD +FEE_REFUND = 0.00 DEMOGELD + +[coin_demogeld_2] +VALUE = DEMOGELD:1.00 +CIPHER = RSA +RSA_KEYSIZE = 2048 +DURATION_WITHDRAW = 12 weeks +DURATION_SPEND = 52 weeks +DURATION_DEPOSIT = 104 weeks +DURATION_LEGAL = 208 weeks +FEE_WITHDRAW = 0.00 DEMOGELD +FEE_DEPOSIT = 0.00 DEMOGELD +FEE_REFRESH = 0.00 DEMOGELD +FEE_REFUND = 0.00 DEMOGELD + +[coin_demogeld_3] +VALUE = DEMOGELD:5.00 +CIPHER = RSA +RSA_KEYSIZE = 2048 +DURATION_WITHDRAW = 12 weeks +DURATION_SPEND = 52 weeks +DURATION_DEPOSIT = 104 weeks +DURATION_LEGAL = 208 weeks +FEE_WITHDRAW = 0.00 DEMOGELD +FEE_DEPOSIT = 0.00 DEMOGELD +FEE_REFRESH = 0.00 DEMOGELD +FEE_REFUND = 0.00 DEMOGELD + +[wire-demogeld] +PAYTO_URI = ${PAYTO_URI:-payto://x-taler-bank/${BANK_HOST:-ob.antifa.ltd}/demogeld?receiver-name=demogeld} diff --git a/exchange/conf/overrides.conf b/exchange/conf/overrides.conf new file mode 100644 index 0000000..4290fa6 --- /dev/null +++ b/exchange/conf/overrides.conf @@ -0,0 +1 @@ +# Intentionally empty; can be used by tooling to override settings. diff --git a/exchange/conf/taler-exchange.conf.tmpl b/exchange/conf/taler-exchange.conf.tmpl new file mode 100644 index 0000000..6a522a4 --- /dev/null +++ b/exchange/conf/taler-exchange.conf.tmpl @@ -0,0 +1,8 @@ +[exchange] +currency = DEMOGELD + +@inline-matching@ conf.d/*.conf +@inline@ overrides.conf + +[wire-exchange-demogeld] +PAYTO_URI = ${PAYTO_URI:-payto://x-taler-bank/${BANK_HOST:-ob.antifa.ltd}/demogeld?receiver-name=demogeld} diff --git a/exchange/privacy/privacy.txt b/exchange/privacy/privacy.txt new file mode 100644 index 0000000..d8e5cec --- /dev/null +++ b/exchange/privacy/privacy.txt @@ -0,0 +1,55 @@ +Datenschutzerklaerung (Demo) +Stand: 2025-12-10 + +1. Verantwortlicher + Georg Elser Institut fuer Angewandten Antifaschismus und Antiautoritarismusforschung + Koenig-Lothar-Platz 1, DE-01161 Dresden + Vertreten durch: Mirco da Silva, Amalie-Dietrich-Platz 9, DE-01169 Dresden + E-Mail: gamemaster@antifa.ltd + +2. Zweck der Verarbeitung + Bereitstellung und Betrieb von Demogeld-Konten zu Demonstrations- und Spielzwecken (fiktive + Waehrung ohne realen Gegenwert). + +3. Kategorien von Daten + - Kontodaten: Benutzername, E-Mail (optional), fiktive oder reale Personenangaben. + - Protokolle: technische Logfiles fuer Betrieb/Sicherheit (z.B. Zeitstempel, IP, Fehlerlogs). + +4. Rechtsgrundlage (DSGVO) + - Art. 6 Abs. 1 lit. b DSGVO (vertragliche Anbahnung/Nutzung des Demo-Dienstes) + - Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse am sicheren Betrieb) + - Bei rein fiktiven Angaben sind keine personenbezogenen Daten betroffen. + +5. Speicherdauer + - Kontodaten: bis zur Loeschung des Kontos oder Einstellung des Dienstes. + - Logdaten: in der Regel wenige Wochen/Monate, sofern keine laengere Aufbewahrung wegen + Fehlersuche/Sicherheit erforderlich ist. + +6. Empfaenger + Keine Weitergabe an Dritte, ausser technische Dienstleister (Hosting/Administration) mit + entsprechender Vereinbarung. + +7. Uebermittlungen in Drittlaender + Nicht vorgesehen. + +8. Rechte der Betroffenen (DSGVO) + - Auskunft (Art. 15) + - Berichtigung (Art. 16) + - Loeschung (Art. 17) + - Einschraenkung (Art. 18) + - Datenuebertragbarkeit (Art. 20) + - Widerspruch (Art. 21) + - Beschwerde bei einer Aufsichtsbehoerde (Art. 77) + + Kontakt fuer Betroffenenrechte: gamemaster@antifa.ltd + +9. Erforderlichkeit/Freiwilligkeit + Die Nutzung ist freiwillig; erforderliche Angaben sind auf das Minimum fuer den Betrieb des + Demo-Kontos beschraenkt und duerfen fiktiv sein. + +10. Sicherheit + Uebliche technische und organisatorische Massnahmen; keine Garantie fuer Verfuegbarkeit oder + Unversehrtheit der Daten (Demo-Betrieb, Haftungsausschluss siehe Nutzungsbedingungen). + +11. Aenderungen + Diese Erklaerung kann angepasst werden. Bitte beachten Sie die jeweils aktuelle Fassung. diff --git a/exchange/terms/terms.txt b/exchange/terms/terms.txt new file mode 100644 index 0000000..7f10e4d --- /dev/null +++ b/exchange/terms/terms.txt @@ -0,0 +1,44 @@ +Demogeld Nutzungsbedingungen (Demo) +Stand: 2025-12-10 + +1. Anbieter und Kontakt + Georg Elser Institut fuer Angewandten Antifaschismus und Antiautoritarismusforschung + Koenig-Lothar-Platz 1, DE-01161 Dresden + Vertreten durch: Mirco da Silva, Amalie-Dietrich-Platz 9, DE-01169 Dresden + E-Mail: gamemaster@antifa.ltd + +2. Zweck + Demogeld ist eine rein fiktive Waehrung ohne realen Gegenwert. Sie dient ausschliesslich zu + Demonstrations- und Spielzwecken (u.a. LLARP). Es besteht kein Anspruch auf Einloesung oder + Umtausch in gesetzliche Zahlungsmittel. + +3. Registrierung und Nutzung + - Konten koennen mit realen oder fiktiven Daten angelegt werden. + - Die Nutzung erfolgt auf eigenes Risiko. Der Anbieter kann Konten jederzeit sperren oder loeschen. + - Technische Verfuegbarkeiten sind nicht garantiert; Wartungen und Ausfaelle sind jederzeit moeglich. + +4. Haftungsausschluss + - Der Anbieter uebernimmt keine Haftung fuer Schaeden oder Verluste, die aus der Nutzung oder + Nichtnutzung von Demogeld entstehen. + - Keine Gewaehr fuer Verfuegbarkeit, Integritaet von Daten oder Funktionsfaehigkeit des Systems. + - Kein Finanzdienstleistungsangebot; keine Aufsicht durch Finanzbehoerden. + +5. Datenschutz + Siehe separate Datenschutzerklaerung. Es werden nur Daten erhoben, die fuer den Betrieb des Demo- + Kontos erforderlich sind; diese duerfen fiktiv sein. Es erfolgt keine Weitergabe an Dritte ausser + zur technischen Bereitstellung. + +6. Missbrauch und Inhalte + - Keine rechtswidrigen, volksverhetzenden oder diskriminierenden Inhalte. + - Kein Versuch, technische Sicherheitsmechanismen zu umgehen. + +7. Aenderungen + Der Anbieter kann diese Bedingungen jederzeit aendern. Fortgesetzte Nutzung nach Aenderungen gilt + als Zustimmung. + +8. Gerichtsstand/Recht + Es gilt deutsches Recht. Gerichtsstand (soweit vereinbar) ist Dresden. + +9. Salvatorische Klausel + Sollten einzelne Bestimmungen unwirksam sein, bleibt der Rest wirksam; an ihre Stelle tritt die + gesetzliche Regelung. diff --git a/merchant/conf/merchant.conf.tmpl b/merchant/conf/merchant.conf.tmpl new file mode 100644 index 0000000..593aa5e --- /dev/null +++ b/merchant/conf/merchant.conf.tmpl @@ -0,0 +1,12 @@ +[merchant] +CURRENCY = DEMOGELD +SERVE = tcp +PORT = 9966 +BIND_TO = 0.0.0.0 + +[merchantdb-postgres] +CONFIG = postgres://talermerchant:taler@postgres:5432/talermerchant + +[merchant-exchange-demogeld] +MASTER_KEY = ${MASTER_PUBLIC_KEY:-QZEPPYMSPF9RKNDCJ1SYMYY5RCV0Y0827SP2FZ9Z1J8C7PEW6CDG} +EXCHANGE_BASE_URLS = ${EXCHANGE_BASE_URL:-https://${EXCHANGE_HOST:-exchange.antifa.ltd}/} diff --git a/postgres/init/01-init-taler.sh b/postgres/init/01-init-taler.sh new file mode 100644 index 0000000..64eb04c --- /dev/null +++ b/postgres/init/01-init-taler.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +exchange_pw="${TALER_EXCHANGE_DB_PASSWORD:-taler}" +merchant_pw="${TALER_MERCHANT_DB_PASSWORD:-taler}" +bank_pw="${LIBEUFIN_DB_PASSWORD:-taler}" + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL + CREATE USER talerexchange PASSWORD '${exchange_pw}'; + CREATE USER talermerchant PASSWORD '${merchant_pw}'; + CREATE USER libeufinbank PASSWORD '${bank_pw}'; + + CREATE DATABASE talerexchange OWNER talerexchange; + CREATE DATABASE talermerchant OWNER talermerchant; + CREATE DATABASE libeufinbank OWNER libeufinbank; +EOSQL diff --git a/scripts/enable-exchange-account.sh b/scripts/enable-exchange-account.sh new file mode 100644 index 0000000..8ea120e --- /dev/null +++ b/scripts/enable-exchange-account.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# Helper to enable a bank account for the exchange via taler-exchange-offline. +# Run this inside the exchange container (where the master private key lives). +# Requires taler-exchange-offline and a valid master key in the secrets path. + +set -euo pipefail + +EXCHANGE_CONFIG="${EXCHANGE_CONFIG:-/etc/taler/taler-exchange.conf}" +PAYTO_URI="${PAYTO_URI:-payto://x-taler-bank/ob.antifa.ltd/demogeld?receiver-name=demogeld}" +OUT="${ENABLE_ACCOUNT_JSON:-/tmp/enable-account.json}" +EXCHANGE_KEYS_URL="${EXCHANGE_KEYS_URL:-http://exchange:8081/keys}" +EXCHANGE_WAIT_RETRIES="${EXCHANGE_WAIT_RETRIES:-60}" +EXCHANGE_WAIT_INTERVAL="${EXCHANGE_WAIT_INTERVAL:-2}" +EXCHANGE_CURL_OPTS="${EXCHANGE_CURL_OPTS:-}" + +render_template() { + local src="$1" + local dst="$2" + if [[ -f "${src}" ]]; then + echo "Rendering template ${src} -> ${dst}" + envsubst < "${src}" > "${dst}" + fi +} + +render_template /etc/taler/taler-exchange.conf.tmpl /etc/taler/taler-exchange.conf +render_template /etc/taler/conf.d/99-exchange.conf.tmpl /etc/taler/conf.d/99-exchange.conf + +enabled_flag="${ENABLE_EXCHANGE_ACCOUNT:-0}" +case "${enabled_flag,,}" in + 1|true|yes|on) ;; + *) + echo "ENABLE_EXCHANGE_ACCOUNT not set to true; skipping enable-account." + exit 0 + ;; +esac + +echo "Using config: ${EXCHANGE_CONFIG}" +echo "Payto URI: ${PAYTO_URI}" +echo "Output JSON: ${OUT}" +echo "Waiting for exchange at: ${EXCHANGE_KEYS_URL}" + +wait_for_exchange() { + local i + for ((i=1; i<=EXCHANGE_WAIT_RETRIES; i++)); do + if curl -fsS ${EXCHANGE_CURL_OPTS} "${EXCHANGE_KEYS_URL}" >/dev/null 2>&1; then + echo "Exchange reachable (attempt ${i})." + return 0 + fi + sleep "${EXCHANGE_WAIT_INTERVAL}" + done + echo "Exchange not reachable after ${EXCHANGE_WAIT_RETRIES} attempts." >&2 + return 1 +} + +wait_for_exchange + +taler-exchange-offline -c "${EXCHANGE_CONFIG}" enable-account "${PAYTO_URI}" > "${OUT}" +echo "enable-account JSON written to ${OUT}" + +taler-exchange-offline -c "${EXCHANGE_CONFIG}" upload < "${OUT}" +echo "Upload complete." diff --git a/scripts/provision-bank-user.sh b/scripts/provision-bank-user.sh new file mode 100644 index 0000000..f360a11 --- /dev/null +++ b/scripts/provision-bank-user.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Provision LibEuFin bank users, debit limits and tokens via docker compose. +# Reads .env if present, then uses docker compose exec inside the bank container. + +set -euo pipefail + +if [[ -f ".env" ]]; then + set -a + # shellcheck disable=SC1091 + source ".env" + set +a +fi + +COMPOSE_CMD="${COMPOSE_CMD:-docker compose}" +BANK_SERVICE="${BANK_SERVICE:-bank}" +BANK_CONFIG="${BANK_CONFIG:-/etc/libeufin/bank.conf}" + +USER="${LIBEUFIN_USER:-demogeld}" +USER_PASSWORD="${LIBEUFIN_USER_PASSWORD:-}" +DEBIT_THRESHOLD="${LIBEUFIN_DEBIT_THRESHOLD:-DEMOGELD:1000000}" + +TOKEN_USER="${LIBEUFIN_MERCHANT_USER:-demogeldbank}" +TOKEN_PASSWORD="${LIBEUFIN_MERCHANT_PASSWORD:-}" +TOKEN_SCOPE="${LIBEUFIN_MERCHANT_SCOPE:-readwrite}" +TOKEN_DURATION="${LIBEUFIN_MERCHANT_TOKEN_DURATION:-forever}" +TOKEN_OUTPUT="${TOKEN_OUTPUT:-bank/token-info.txt}" + +ensure_user() { + echo "Ensuring bank user '${USER}' exists (password will be set if provided)..." + if ! ${COMPOSE_CMD} exec -T "${BANK_SERVICE}" libeufin-bank users add "${USER}" --password "${USER_PASSWORD}" -c "${BANK_CONFIG}" >/tmp/libeufin-users-add.log 2>&1; then + if grep -qi "already exists" /tmp/libeufin-users-add.log; then + echo "User ${USER} already exists; proceeding." + else + echo "Failed to add user ${USER}:" + cat /tmp/libeufin-users-add.log + exit 1 + fi + fi + + echo "Setting debit threshold ${DEBIT_THRESHOLD} for ${USER}..." + ${COMPOSE_CMD} exec -T "${BANK_SERVICE}" libeufin-bank edit-account "${USER}" \ + --debit_threshold "${DEBIT_THRESHOLD}" -c "${BANK_CONFIG}" +} + +provision_token() { + echo "Creating token for user '${TOKEN_USER}' (scope=${TOKEN_SCOPE}, duration=${TOKEN_DURATION})..." + local token_output + token_output="$(${COMPOSE_CMD} exec -T "${BANK_SERVICE}" libeufin-bank create-token \ + -c "${BANK_CONFIG}" \ + --user="${TOKEN_USER}" \ + --scope="${TOKEN_SCOPE}" \ + --duration="${TOKEN_DURATION}")" + + echo "Token response:" + echo "${token_output}" + + mkdir -p "$(dirname "${TOKEN_OUTPUT}")" + { + echo "# Generated $(date -Is)" + echo "USER=${TOKEN_USER}" + echo "SCOPE=${TOKEN_SCOPE}" + echo "DURATION=${TOKEN_DURATION}" + echo "${token_output}" + } > "${TOKEN_OUTPUT}" + echo "Token saved to ${TOKEN_OUTPUT}" +} + +main() { + if [[ -z "${USER_PASSWORD}" || -z "${TOKEN_PASSWORD}" ]]; then + echo "Warning: LIBEUFIN_USER_PASSWORD or LIBEUFIN_MERCHANT_PASSWORD not set; user/token may be created without password enforcement." >&2 + fi + ensure_user + provision_token + echo "Done." +} + +main "$@"