ops: GOA vanilla landings stats wdGet + collect greening
This commit is contained in:
parent
0d881cd726
commit
337d253691
24 changed files with 1074 additions and 107 deletions
|
|
@ -1118,12 +1118,18 @@
|
|||
<script src="/intro/qrcode.min.js"></script>
|
||||
</head>
|
||||
<body data-shop-theme="bank">
|
||||
<p class="stack-bar" role="note" title="Taler software on this bank service (links → git.taler.net tags)">
|
||||
<!-- stack-bar -->
|
||||
<p class="stack-bar" role="note" title="Taler software on this bank service (goa-regio-ng vanilla)">
|
||||
<strong>stack</strong><span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/libeufin/commit/ab00480dd9b3be50704fb449b750c764fd4c1de0.html" target="_blank" rel="noopener noreferrer" title="libeufin tag v1.6.6">libeufin-bank 1.6.6</a>
|
||||
<a href="https://git.taler.net/taler-deployment.git/tree/?h=dev/hernani/goa-regio-ng-vanilla" target="_blank" rel="noopener noreferrer" title="taler-deployment branch dev/hernani/goa-regio-ng-vanilla">vanilla</a>
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/libeufin/commit/ab00480dd9b3be50704fb449b750c764fd4c1de0.html" target="_blank" rel="noopener noreferrer" title="libeufin tag v1.6.6">libeufin-common 1.6.6</a>
|
||||
libeufin-bank 1.6.10
|
||||
<span class="sep">·</span>
|
||||
libeufin-common 1.6.10
|
||||
<span class="sep">·</span>
|
||||
libeufin-bank-webui 1.6.38
|
||||
</p>
|
||||
<!-- /stack-bar -->
|
||||
<main>
|
||||
<header class="hero">
|
||||
<span class="badge">Intergalactic · GOA · no IBAN</span>
|
||||
|
|
@ -1558,10 +1564,10 @@ tw run-until-done && tw balance</pre>
|
|||
<a href="https://bank.hacktivism.ch/privacy" style="color:#5eead4">/privacy</a>.
|
||||
</p>
|
||||
<!-- landing-rev -->
|
||||
<p class="landing-rev" data-landing-site="bank" data-landing-version="44" data-landing-commit="689ee59">
|
||||
Bank landing <strong>v44</strong>
|
||||
· content <time datetime="2026-07-17T18:31:49+02:00">2026-07-17 18:31 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/689ee595e08f3880c1e4068aac8e972574e20d21" title="koopa-admin-log 689ee595e08f3880c1e4068aac8e972574e20d21">689ee59</a>
|
||||
<p class="landing-rev" data-landing-site="bank" data-landing-version="45" data-landing-commit="0d881cd">
|
||||
Bank landing <strong>v45</strong>
|
||||
· content <time datetime="2026-09-16T23:19:33+02:00">2026-09-16 23:19 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6" title="koopa-admin-log 0d881cd726da8d298c98114678253e3cbb7aa5e6">0d881cd</a>
|
||||
</p>
|
||||
<!-- /landing-rev -->
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@ server {
|
|||
add_header Cache-Control "no-store" always;
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
}
|
||||
# FP pattern: GET Integration via demo-api (inject suggested/required_exchange)
|
||||
# Caddy @wdGet → :9013 → here → :19096; POST/other Integration stays on :9012
|
||||
location /taler-integration/withdrawal-operation/ {
|
||||
proxy_pass http://127.0.0.1:19096;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 70s;
|
||||
add_header Cache-Control "no-store" always;
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
}
|
||||
location /intro/ {
|
||||
alias /var/www/bank-landing/;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,19 @@ bank.hacktivism.ch {
|
|||
}
|
||||
}
|
||||
|
||||
# FP pattern (francpaysan-admin-log files/caddy/Caddyfile @wdGet):
|
||||
# GET withdrawal-operation → landing :9013 → demo-api :19096
|
||||
# (injects suggested_exchange / required_exchange for Android/iOS)
|
||||
@wdGet {
|
||||
method GET
|
||||
path /taler-integration/withdrawal-operation/*
|
||||
}
|
||||
handle @wdGet {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
reverse_proxy 127.0.0.1:9012 {
|
||||
import proxy_public
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,18 +289,22 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="stack-bar" role="note" title="Taler software on this exchange service (links → git.taler.net tags)">
|
||||
<!-- stack-bar -->
|
||||
<p class="stack-bar" role="note" title="Taler software on this exchange service (goa-regio-ng vanilla)">
|
||||
<strong>stack</strong><span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/6dbfa41e3fc6657eff28d11166d24301cdfa93ff.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.6">taler-exchange 1.6.6</a>
|
||||
<a href="https://git.taler.net/taler-deployment.git/tree/?h=dev/hernani/goa-regio-ng-vanilla" target="_blank" rel="noopener noreferrer" title="taler-deployment branch dev/hernani/goa-regio-ng-vanilla">vanilla</a>
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/6dbfa41e3fc6657eff28d11166d24301cdfa93ff.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.6">libtalerexchange 1.6.6</a>
|
||||
taler-exchange 1.6.15
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/6dbfa41e3fc6657eff28d11166d24301cdfa93ff.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.6">taler-exchange-database 1.6.6</a>
|
||||
libtalerexchange 1.6.15
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/6dbfa41e3fc6657eff28d11166d24301cdfa93ff.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.6">taler-exchange-offline 1.6.6</a>
|
||||
taler-exchange-database 1.6.15
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/6dbfa41e3fc6657eff28d11166d24301cdfa93ff.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.6">taler-terms-generator 1.6.6</a>
|
||||
taler-exchange-offline 1.6.15
|
||||
<span class="sep">·</span>
|
||||
taler-terms-generator 1.6.15
|
||||
</p>
|
||||
<!-- /stack-bar -->
|
||||
<main>
|
||||
<header class="hero">
|
||||
<span class="badge">GOA · Exchange</span>
|
||||
|
|
@ -500,10 +504,10 @@ sudo apt-get install -y taler-wallet-cli</pre>
|
|||
<a href="https://exchange.hacktivism.ch/privacy" style="color:#5eead4">/privacy</a>.
|
||||
</p>
|
||||
<!-- landing-rev -->
|
||||
<p class="landing-rev" data-landing-site="exchange" data-landing-version="43" data-landing-commit="d0594cb">
|
||||
Exchange landing <strong>v43</strong>
|
||||
· content <time datetime="2026-07-17T18:33:13+02:00">2026-07-17 18:33 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/d0594cb44ffb1bec2e009f6812167cbbf216eda9" title="koopa-admin-log d0594cb44ffb1bec2e009f6812167cbbf216eda9">d0594cb</a>
|
||||
<p class="landing-rev" data-landing-site="exchange" data-landing-version="44" data-landing-commit="0d881cd">
|
||||
Exchange landing <strong>v44</strong>
|
||||
· content <time datetime="2026-09-16T23:19:33+02:00">2026-09-16 23:19 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6" title="koopa-admin-log 0d881cd726da8d298c98114678253e3cbb7aa5e6">0d881cd</a>
|
||||
</p>
|
||||
<!-- /landing-rev -->
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -530,18 +530,22 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="stack-bar" role="note" title="Taler software on this merchant service (links → git.taler.net tags)">
|
||||
<!-- stack-bar -->
|
||||
<p class="stack-bar" role="note" title="Taler software on this merchant service (goa-regio-ng vanilla)">
|
||||
<strong>stack</strong><span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/merchant/commit/b5af1c99052f4c5053070cd5c6cc39b68eca2a20.html" target="_blank" rel="noopener noreferrer" title="merchant tag v1.6.9">taler-merchant 1.6.9</a>
|
||||
<a href="https://git.taler.net/taler-deployment.git/tree/?h=dev/hernani/goa-regio-ng-vanilla" target="_blank" rel="noopener noreferrer" title="taler-deployment branch dev/hernani/goa-regio-ng-vanilla">vanilla</a>
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/taler-typescript-core/commit/d7ab425239226b798a95dbf6742fe4b4a2e30e47.html" target="_blank" rel="noopener noreferrer" title="taler-typescript-core tag v1.6.8-dev.6">taler-merchant-webui 1.6.8~dev6</a>
|
||||
taler-merchant 1.6.23
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/merchant/commit/b5af1c99052f4c5053070cd5c6cc39b68eca2a20.html" target="_blank" rel="noopener noreferrer" title="merchant tag v1.6.9">libtalermerchant 1.6.9</a>
|
||||
taler-merchant-webui 1.6.38
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/fed7d0e782ea4d36b2d2e337d93bfd2723c6ed64.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.7-dev.2">libtalerexchange 1.6.7~dev2</a>
|
||||
libtalermerchant 1.6.23
|
||||
<span class="sep">·</span>
|
||||
<a href="https://git.taler.net/taler/exchange/commit/fed7d0e782ea4d36b2d2e337d93bfd2723c6ed64.html" target="_blank" rel="noopener noreferrer" title="exchange tag v1.6.7-dev.2">taler-terms-generator 1.6.7~dev2</a>
|
||||
libtalerexchange 1.6.15
|
||||
<span class="sep">·</span>
|
||||
taler-terms-generator 1.6.15
|
||||
</p>
|
||||
<!-- /stack-bar -->
|
||||
<main>
|
||||
<header class="hero">
|
||||
<span class="badge">Merchant · dual currency</span>
|
||||
|
|
@ -833,10 +837,10 @@ sudo apt-get install -y taler-wallet-cli</pre>
|
|||
<a href="https://taler.hacktivism.ch/privacy" style="color:#5eead4">/privacy</a>.
|
||||
</p>
|
||||
<!-- landing-rev -->
|
||||
<p class="landing-rev" data-landing-site="merchant" data-landing-version="42" data-landing-commit="37ea4bb">
|
||||
Merchant landing <strong>v42</strong>
|
||||
· content <time datetime="2026-07-17T18:27:48+02:00">2026-07-17 18:27 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/37ea4bb8396691e3ea69ae61374e6623bf6c5ea7" title="koopa-admin-log 37ea4bb8396691e3ea69ae61374e6623bf6c5ea7">37ea4bb</a>
|
||||
<p class="landing-rev" data-landing-site="merchant" data-landing-version="43" data-landing-commit="0d881cd">
|
||||
Merchant landing <strong>v43</strong>
|
||||
· content <time datetime="2026-09-16T23:19:33+02:00">2026-09-16 23:19 CEST</time>
|
||||
· <a href="https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6" title="koopa-admin-log 0d881cd726da8d298c98114678253e3cbb7aa5e6">0d881cd</a>
|
||||
</p>
|
||||
<!-- /landing-rev -->
|
||||
</footer>
|
||||
|
|
|
|||
79
configs/shared/landing-stack-versions.json
Normal file
79
configs/shared/landing-stack-versions.json
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"updated_iso": "2026-09-16T23:19:33+02:00",
|
||||
"updated_human": "2026-09-16 23:19 CEST",
|
||||
"ctr": "goa-regio-ng",
|
||||
"ssh": "hernani@192.168.100.95",
|
||||
"packages": {
|
||||
"libeufin-bank": {
|
||||
"dpkg": "1.6.10-0+trixie",
|
||||
"display": "1.6.10"
|
||||
},
|
||||
"libeufin-bank-webui": {
|
||||
"dpkg": "1.6.38-0+trixie",
|
||||
"display": "1.6.38"
|
||||
},
|
||||
"libeufin-common": {
|
||||
"dpkg": "1.6.10-0+trixie",
|
||||
"display": "1.6.10"
|
||||
},
|
||||
"libtalerexchange": {
|
||||
"dpkg": "1.6.15-0+trixie",
|
||||
"display": "1.6.15"
|
||||
},
|
||||
"libtalermerchant": {
|
||||
"dpkg": "1.6.23-0+trixie",
|
||||
"display": "1.6.23"
|
||||
},
|
||||
"taler-exchange": {
|
||||
"dpkg": "1.6.15-0+trixie",
|
||||
"display": "1.6.15"
|
||||
},
|
||||
"taler-exchange-database": {
|
||||
"dpkg": "1.6.15-0+trixie",
|
||||
"display": "1.6.15"
|
||||
},
|
||||
"taler-exchange-offline": {
|
||||
"dpkg": "1.6.15-0+trixie",
|
||||
"display": "1.6.15"
|
||||
},
|
||||
"taler-merchant": {
|
||||
"dpkg": "1.6.23-0+trixie",
|
||||
"display": "1.6.23"
|
||||
},
|
||||
"taler-merchant-webui": {
|
||||
"dpkg": "1.6.38-0+trixie",
|
||||
"display": "1.6.38"
|
||||
},
|
||||
"taler-terms-generator": {
|
||||
"dpkg": "1.6.15-0+trixie",
|
||||
"display": "1.6.15"
|
||||
}
|
||||
},
|
||||
"sites": {
|
||||
"bank": {
|
||||
"packages": {
|
||||
"libeufin-bank": "1.6.10",
|
||||
"libeufin-common": "1.6.10",
|
||||
"libeufin-bank-webui": "1.6.38"
|
||||
}
|
||||
},
|
||||
"exchange": {
|
||||
"packages": {
|
||||
"taler-exchange": "1.6.15",
|
||||
"libtalerexchange": "1.6.15",
|
||||
"taler-exchange-database": "1.6.15",
|
||||
"taler-exchange-offline": "1.6.15",
|
||||
"taler-terms-generator": "1.6.15"
|
||||
}
|
||||
},
|
||||
"merchant": {
|
||||
"packages": {
|
||||
"taler-merchant": "1.6.23",
|
||||
"taler-merchant-webui": "1.6.38",
|
||||
"libtalermerchant": "1.6.23",
|
||||
"libtalerexchange": "1.6.15",
|
||||
"taler-terms-generator": "1.6.15"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
configs/shared/landing-stack.json
Normal file
35
configs/shared/landing-stack.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"note": "Stack-bar package lists per landing. Versions filled by scripts/taler-landing/stamp-landing-stack.sh from live CTR dpkg. Only hard link = vanilla branch.",
|
||||
"vanilla_href": "https://git.taler.net/taler-deployment.git/tree/?h=dev/hernani/goa-regio-ng-vanilla",
|
||||
"vanilla_title": "taler-deployment branch dev/hernani/goa-regio-ng-vanilla",
|
||||
"sites": {
|
||||
"bank": {
|
||||
"title": "Taler software on this bank service (goa-regio-ng vanilla)",
|
||||
"packages": [
|
||||
"libeufin-bank",
|
||||
"libeufin-common",
|
||||
"libeufin-bank-webui"
|
||||
]
|
||||
},
|
||||
"exchange": {
|
||||
"title": "Taler software on this exchange service (goa-regio-ng vanilla)",
|
||||
"packages": [
|
||||
"taler-exchange",
|
||||
"libtalerexchange",
|
||||
"taler-exchange-database",
|
||||
"taler-exchange-offline",
|
||||
"taler-terms-generator"
|
||||
]
|
||||
},
|
||||
"merchant": {
|
||||
"title": "Taler software on this merchant service (goa-regio-ng vanilla)",
|
||||
"packages": [
|
||||
"taler-merchant",
|
||||
"taler-merchant-webui",
|
||||
"libtalermerchant",
|
||||
"libtalerexchange",
|
||||
"taler-terms-generator"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,34 +2,34 @@
|
|||
"note": "Per-site landing content versions (start 42). Bump: scripts/taler-landing/stamp-landing-version.sh --bump bank|exchange|merchant",
|
||||
"sites": {
|
||||
"bank": {
|
||||
"version": 44,
|
||||
"version": 45,
|
||||
"label": "Bank landing",
|
||||
"path": "configs/bank-landing",
|
||||
"updated_iso": "2026-07-17T18:31:49+02:00",
|
||||
"updated_human": "2026-07-17 18:31 CEST",
|
||||
"commit": "689ee595e08f3880c1e4068aac8e972574e20d21",
|
||||
"commit_short": "689ee59",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/689ee595e08f3880c1e4068aac8e972574e20d21"
|
||||
"updated_iso": "2026-09-16T23:19:33+02:00",
|
||||
"updated_human": "2026-09-16 23:19 CEST",
|
||||
"commit": "0d881cd726da8d298c98114678253e3cbb7aa5e6",
|
||||
"commit_short": "0d881cd",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6"
|
||||
},
|
||||
"exchange": {
|
||||
"version": 43,
|
||||
"version": 44,
|
||||
"label": "Exchange landing",
|
||||
"path": "configs/exchange-landing",
|
||||
"updated_iso": "2026-07-17T18:33:13+02:00",
|
||||
"updated_human": "2026-07-17 18:33 CEST",
|
||||
"commit": "d0594cb44ffb1bec2e009f6812167cbbf216eda9",
|
||||
"commit_short": "d0594cb",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/d0594cb44ffb1bec2e009f6812167cbbf216eda9"
|
||||
"updated_iso": "2026-09-16T23:19:33+02:00",
|
||||
"updated_human": "2026-09-16 23:19 CEST",
|
||||
"commit": "0d881cd726da8d298c98114678253e3cbb7aa5e6",
|
||||
"commit_short": "0d881cd",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6"
|
||||
},
|
||||
"merchant": {
|
||||
"version": 42,
|
||||
"version": 43,
|
||||
"label": "Merchant landing",
|
||||
"path": "configs/merchant-landing",
|
||||
"updated_iso": "2026-07-17T18:27:48+02:00",
|
||||
"updated_human": "2026-07-17 18:27 CEST",
|
||||
"commit": "37ea4bb8396691e3ea69ae61374e6623bf6c5ea7",
|
||||
"commit_short": "37ea4bb",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/37ea4bb8396691e3ea69ae61374e6623bf6c5ea7"
|
||||
"updated_iso": "2026-09-16T23:19:33+02:00",
|
||||
"updated_human": "2026-09-16 23:19 CEST",
|
||||
"commit": "0d881cd726da8d298c98114678253e3cbb7aa5e6",
|
||||
"commit_short": "0d881cd",
|
||||
"repo_commit_url": "https://git.hacktivism.ch/hernani/koopa-admin-log/commit/0d881cd726da8d298c98114678253e3cbb7aa5e6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,19 @@ bank.hacktivism.ch {
|
|||
}
|
||||
}
|
||||
|
||||
# FP pattern (francpaysan-admin-log files/caddy/Caddyfile @wdGet):
|
||||
# GET withdrawal-operation → landing :9013 → demo-api :19096
|
||||
# (injects suggested_exchange / required_exchange for Android/iOS)
|
||||
@wdGet {
|
||||
method GET
|
||||
path /taler-integration/withdrawal-operation/*
|
||||
}
|
||||
handle @wdGet {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
reverse_proxy 127.0.0.1:9012 {
|
||||
import proxy_public
|
||||
}
|
||||
|
|
|
|||
354
scripts/caddy/Caddyfile.koopa-live-wdGet
Normal file
354
scripts/caddy/Caddyfile.koopa-live-wdGet
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
# Internal only (not in the browser URL):
|
||||
# 9010 merchant API | 9011 exchange API | 9012 bank API
|
||||
# 9013 bank landing | 9014 exchange landing | 9015 merchant landing
|
||||
# 9020 castopod | 9021 bonfire | 9022 prime | 9023 bt | 9024 forgejo | 9025 paivana | 9026 lemmy | 9027 decidim | 9200 forgejo-ssh
|
||||
# 9090 tops ng1 | 9091 tops ng2 | 9092 tops ng3
|
||||
{
|
||||
email info+koopa@hacktivism.ch
|
||||
http_port 9000
|
||||
https_port 9001
|
||||
auto_https disable_redirects
|
||||
# Caddy listens on 9001 behind VeciGate/https-proxy :443.
|
||||
# Default HTTP/3 would send Alt-Svc: h3=":9001" — break public HTTPS on :443.
|
||||
servers {
|
||||
protocols h1 h2
|
||||
}
|
||||
}
|
||||
|
||||
(proxy_public) {
|
||||
header_up Host {host}
|
||||
header_up X-Forwarded-Port 443
|
||||
header_down Location "^https?://[^/]+:90[0-9]{2}(.*)$" "https://{host}$1"
|
||||
}
|
||||
|
||||
taler.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
|
||||
# Public landing first
|
||||
redir / /intro/ 302
|
||||
|
||||
handle /intro* {
|
||||
reverse_proxy 127.0.0.1:9015 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
# surface + aptdeploy HTML (taler.hacktivism.ch only)
|
||||
handle /taler-monitoring-surface_err {
|
||||
redir /taler-monitoring-surface_err/ 302
|
||||
}
|
||||
handle /taler-monitoring-surface_err* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /taler-monitoring-surface {
|
||||
redir /taler-monitoring-surface/ 302
|
||||
}
|
||||
handle /taler-monitoring-surface* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /taler-monitoring-aptdeploy_err {
|
||||
redir /taler-monitoring-aptdeploy_err/ 302
|
||||
}
|
||||
handle /taler-monitoring-aptdeploy_err* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /taler-monitoring-aptdeploy {
|
||||
redir /taler-monitoring-aptdeploy/ 302
|
||||
}
|
||||
handle /taler-monitoring-aptdeploy* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
handle /taler-monitoring-mattermost_err {
|
||||
redir /taler-monitoring-mattermost_err/ 302
|
||||
}
|
||||
handle /taler-monitoring-mattermost_err* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /taler-monitoring-mattermost {
|
||||
redir /taler-monitoring-mattermost/ 302
|
||||
}
|
||||
handle /taler-monitoring-mattermost* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
handle /taler-monitoring-mail_err {
|
||||
redir /taler-monitoring-mail_err/ 302
|
||||
}
|
||||
handle /taler-monitoring-mail_err* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /taler-monitoring-mail {
|
||||
redir /taler-monitoring-mail/ 302
|
||||
}
|
||||
handle /taler-monitoring-mail* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
# taler-monitoring console HTML (host static — not in app containers)
|
||||
handle /monitoring_err {
|
||||
redir /monitoring_err/ 302
|
||||
}
|
||||
handle /monitoring_err* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /monitoring {
|
||||
redir /monitoring/ 302
|
||||
}
|
||||
handle /monitoring* {
|
||||
root * /var/www/monitoring-sites/taler.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
# SPA: /webui → /webui/
|
||||
redir /webui /webui/ 302
|
||||
|
||||
# Merchant API + WebUI (nginx :9010 → unix socket)
|
||||
reverse_proxy https://127.0.0.1:9010 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
exchange.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
|
||||
# Public landing first
|
||||
redir / /intro/ 302
|
||||
|
||||
handle /intro* {
|
||||
reverse_proxy 127.0.0.1:9014 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
# taler-monitoring console HTML (host static — not in app containers)
|
||||
handle /monitoring_err {
|
||||
redir /monitoring_err/ 302
|
||||
}
|
||||
handle /monitoring_err* {
|
||||
root * /var/www/monitoring-sites/exchange.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /monitoring {
|
||||
redir /monitoring/ 302
|
||||
}
|
||||
handle /monitoring* {
|
||||
root * /var/www/monitoring-sites/exchange.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
reverse_proxy 127.0.0.1:9011 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
bank.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
|
||||
# Public landing first
|
||||
redir / /intro/ 302
|
||||
|
||||
handle /intro* {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
# taler-monitoring console HTML (host static — not in app containers)
|
||||
handle /monitoring_err {
|
||||
redir /monitoring_err/ 302
|
||||
}
|
||||
handle /monitoring_err* {
|
||||
root * /var/www/monitoring-sites/bank.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
handle /monitoring {
|
||||
redir /monitoring/ 302
|
||||
}
|
||||
handle /monitoring* {
|
||||
root * /var/www/monitoring-sites/bank.hacktivism.ch
|
||||
file_server
|
||||
}
|
||||
|
||||
# Static terms/privacy on landing nginx :9013
|
||||
handle /terms* {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
handle /privacy* {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
# FP pattern (francpaysan-admin-log files/caddy/Caddyfile @wdGet):
|
||||
# GET withdrawal-operation → landing :9013 → demo-api :19096
|
||||
# (injects suggested_exchange / required_exchange for Android/iOS)
|
||||
@wdGet {
|
||||
method GET
|
||||
path /taler-integration/withdrawal-operation/*
|
||||
}
|
||||
handle @wdGet {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
reverse_proxy 127.0.0.1:9012 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
||||
castopod.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9020 {
|
||||
header_up Host {host}
|
||||
}
|
||||
}
|
||||
|
||||
bonfire.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9021 {
|
||||
header_up Host {host}
|
||||
flush_interval -1
|
||||
}
|
||||
}
|
||||
|
||||
prime.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9022 {
|
||||
header_up Host {host}
|
||||
flush_interval -1
|
||||
}
|
||||
}
|
||||
|
||||
bt.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9023 {
|
||||
header_up Host {host}
|
||||
}
|
||||
}
|
||||
|
||||
# 9024 forgejo HTTP (SSH :9200 host-direct, not via Caddy)
|
||||
git.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9024 {
|
||||
header_up Host {host}
|
||||
flush_interval -1
|
||||
transport http {
|
||||
read_timeout 3600s
|
||||
write_timeout 3600s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Taler Operations design previews (static nginx)
|
||||
tops.ng1.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9090 {
|
||||
header_up Host {host}
|
||||
}
|
||||
}
|
||||
|
||||
tops.ng2.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9091 {
|
||||
header_up Host {host}
|
||||
}
|
||||
}
|
||||
|
||||
tops.ng3.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9092 {
|
||||
header_up Host {host}
|
||||
}
|
||||
}
|
||||
|
||||
# 9025 paivana-httpd (GOA paywall)
|
||||
paivana.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9025 {
|
||||
header_up Host {host}
|
||||
header_up X-Forwarded-Port 443
|
||||
}
|
||||
}
|
||||
|
||||
# 9026 lemmy (+ ui/pictrs via internal nginx)
|
||||
lemmy.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9026 {
|
||||
header_up Host {host}
|
||||
flush_interval -1
|
||||
transport http {
|
||||
read_timeout 3600s
|
||||
write_timeout 3600s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 9027 decidim (rails)
|
||||
decidim.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
reverse_proxy 127.0.0.1:9027 {
|
||||
header_up Host {host}
|
||||
header_up X-Forwarded-Port 443
|
||||
flush_interval -1
|
||||
transport http {
|
||||
read_timeout 3600s
|
||||
write_timeout 3600s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http://taler.hacktivism.ch, http://exchange.hacktivism.ch, http://bank.hacktivism.ch, http://castopod.hacktivism.ch, http://bonfire.hacktivism.ch, http://prime.hacktivism.ch, http://bt.hacktivism.ch, http://git.hacktivism.ch, http://paivana.hacktivism.ch, http://tops.ng1.hacktivism.ch, http://tops.ng2.hacktivism.ch, http://tops.ng3.hacktivism.ch, http://lemmy.hacktivism.ch, http://decidim.hacktivism.ch {
|
||||
handle /.well-known/acme-challenge/* {
|
||||
root * /var/www/acme
|
||||
file_server
|
||||
}
|
||||
handle {
|
||||
redir https://{host}{uri} permanent
|
||||
}
|
||||
}
|
||||
|
||||
# --- LLM Lightweight Monitoring (applied 2026-09-05T10:08:03+02:00) ---
|
||||
monitoring.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
root * /var/www/monitoring-sites/monitoring.hacktivism.ch
|
||||
file_server
|
||||
try_files {path} /index.html
|
||||
}
|
||||
|
||||
# ngi0-landing dossiers test sites (static) — numbering like tops.ng*
|
||||
dossiers.ngi.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
root * /var/www/monitoring-sites/dossiers.ngi.hacktivism.ch
|
||||
file_server
|
||||
try_files {path} /index.html
|
||||
}
|
||||
|
||||
dossiers.2.ngi.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
root * /var/www/monitoring-sites/dossiers.2.ngi.hacktivism.ch
|
||||
file_server
|
||||
try_files {path} /index.html
|
||||
}
|
||||
|
||||
dossiers.3.ngi.hacktivism.ch {
|
||||
header Alt-Svc "clear"
|
||||
root * /var/www/monitoring-sites/dossiers.3.ngi.hacktivism.ch
|
||||
file_server
|
||||
try_files {path} /index.html
|
||||
}
|
||||
|
|
@ -10,6 +10,24 @@ sudo caddy validate --config /etc/caddy/Caddyfile
|
|||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
Preferred live path: edit `~/koopa-caddy/Caddyfile`, then `sudo ~/bin/caddy-apply`
|
||||
(copies → `/etc/caddy/Caddyfile`, validate, `systemctl reload caddy`).
|
||||
|
||||
## GOA bank @wdGet (FP Android withdraw) — full replace
|
||||
|
||||
Live snapshot + `@wdGet` (GET Integration → `:9013` → demo-api):
|
||||
|
||||
- `Caddyfile.koopa-live-wdGet` — whole-file replacement (based on live koopa, not admin-log mirror)
|
||||
- `apply-goa-wdGet-full-replace.sh` — replaces `~/koopa-caddy/Caddyfile` **and** `/etc/caddy/Caddyfile`, reload, smoke
|
||||
|
||||
```bash
|
||||
# on koopa (root) — scp both files first if no admin-log checkout:
|
||||
sudo bash /tmp/goa-fp-port/caddy/apply-goa-wdGet-full-replace.sh \
|
||||
/tmp/goa-fp-port/caddy/Caddyfile.koopa-live-wdGet
|
||||
```
|
||||
|
||||
FP SoT: `$HOME/git/admin-logs/taler/francpaysan-admin-log` `files/caddy/Caddyfile` `@wdGet`.
|
||||
|
||||
## dossiers.ngi* — basic_auth (htaccess-in-front)
|
||||
|
||||
Caddy **ignores** Apache `.htaccess`. Use:
|
||||
|
|
|
|||
80
scripts/caddy/apply-goa-wdGet-full-replace.sh
Executable file
80
scripts/caddy/apply-goa-wdGet-full-replace.sh
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env bash
|
||||
# Full-replace koopa Caddyfile with live snapshot + FP @wdGet (GOA Android withdraw).
|
||||
#
|
||||
# Replaces BOTH:
|
||||
# /home/hernani/koopa-caddy/Caddyfile (runtime SoT for ~/bin/caddy-apply)
|
||||
# /etc/caddy/Caddyfile (active config)
|
||||
# then validates + systemctl reload caddy.
|
||||
#
|
||||
# On koopa (root):
|
||||
# sudo bash /path/to/apply-goa-wdGet-full-replace.sh
|
||||
# # or with explicit file:
|
||||
# sudo bash …/apply-goa-wdGet-full-replace.sh /path/to/Caddyfile.koopa-live-wdGet
|
||||
#
|
||||
# FP pattern: francpaysan-admin-log files/caddy/Caddyfile @wdGet
|
||||
# Ship file: scripts/caddy/Caddyfile.koopa-live-wdGet (live koopa + @wdGet only)
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SRC="${1:-$HERE/Caddyfile.koopa-live-wdGet}"
|
||||
USER_CADDY="/home/hernani/koopa-caddy/Caddyfile"
|
||||
ETC_CADDY="/etc/caddy/Caddyfile"
|
||||
BACKUP_DIR="/etc/caddy"
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "ERROR: run as root: sudo bash $0${1:+ $1}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[[ -f "$SRC" ]] || { echo "ERROR: missing source: $SRC" >&2; exit 1; }
|
||||
[[ -d "$(dirname "$USER_CADDY")" ]] || { echo "ERROR: missing dir: $(dirname "$USER_CADDY")" >&2; exit 1; }
|
||||
[[ -f "$ETC_CADDY" ]] || { echo "ERROR: missing $ETC_CADDY" >&2; exit 1; }
|
||||
command -v caddy >/dev/null || { echo "ERROR: caddy not in PATH" >&2; exit 1; }
|
||||
|
||||
if ! grep -q '@wdGet' "$SRC"; then
|
||||
echo "ERROR: source lacks @wdGet — refusing replace: $SRC" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -q 'path /taler-integration/withdrawal-operation/\*' "$SRC"; then
|
||||
echo "ERROR: source lacks Integration @wdGet path — refusing: $SRC" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
bak_etc="${BACKUP_DIR}/Caddyfile.bak-goa-wdGet-${ts}"
|
||||
bak_user="${USER_CADDY}.bak-goa-wdGet-${ts}"
|
||||
|
||||
cp -a "$ETC_CADDY" "$bak_etc"
|
||||
echo "backup etc: $bak_etc"
|
||||
if [[ -f "$USER_CADDY" ]]; then
|
||||
cp -a "$USER_CADDY" "$bak_user"
|
||||
echo "backup user: $bak_user"
|
||||
fi
|
||||
|
||||
install -o hernani -g hernani -m 644 "$SRC" "$USER_CADDY"
|
||||
echo "wrote: $USER_CADDY"
|
||||
|
||||
install -o root -g caddy -m 644 "$SRC" "$ETC_CADDY" 2>/dev/null \
|
||||
|| install -o root -g root -m 644 "$SRC" "$ETC_CADDY"
|
||||
echo "wrote: $ETC_CADDY"
|
||||
|
||||
echo "validate..."
|
||||
caddy validate --config "$ETC_CADDY"
|
||||
|
||||
echo "reload..."
|
||||
systemctl reload caddy
|
||||
systemctl is-active caddy
|
||||
|
||||
echo "spot-check @wdGet:"
|
||||
grep -n '@wdGet\|withdrawal-operation\|reverse_proxy 127.0.0.1:9013\|reverse_proxy 127.0.0.1:9012' "$ETC_CADDY" | head -20
|
||||
|
||||
echo "smoke public Integration (expect suggested_exchange + required_exchange):"
|
||||
smoke="$(curl -sS --max-time 10 \
|
||||
'https://bank.hacktivism.ch/taler-integration/withdrawal-operation/00000000-0000-0000-0000-000000000001' || true)"
|
||||
echo "$smoke"
|
||||
if echo "$smoke" | grep -q 'suggested_exchange' && echo "$smoke" | grep -q 'required_exchange'; then
|
||||
echo "OK: public Integration injects exchange fields"
|
||||
else
|
||||
echo "WARN: public smoke missing exchange fields — check nginx Integration + demo-api :19096" >&2
|
||||
exit 1
|
||||
fi
|
||||
18
scripts/caddy/wdGet-bank-snippet.caddy
Normal file
18
scripts/caddy/wdGet-bank-snippet.caddy
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Paste into live ~/koopa-caddy/Caddyfile inside bank.hacktivism.ch { ... }
|
||||
# BEFORE the catch-all: reverse_proxy 127.0.0.1:9012
|
||||
# Then on koopa: sudo ~/bin/caddy-apply
|
||||
#
|
||||
# FP pattern: francpaysan-admin-log files/caddy/Caddyfile @wdGet
|
||||
# GET Integration → landing :9013 → demo-api :19096
|
||||
# (injects suggested_exchange / required_exchange for Android/iOS)
|
||||
# SoT mirrors: configs/caddy/Caddyfile + host/caddy/Caddyfile
|
||||
|
||||
@wdGet {
|
||||
method GET
|
||||
path /taler-integration/withdrawal-operation/*
|
||||
}
|
||||
handle @wdGet {
|
||||
reverse_proxy 127.0.0.1:9013 {
|
||||
import proxy_public
|
||||
}
|
||||
}
|
||||
|
|
@ -38,24 +38,48 @@ Details + JSON schema: `configs/bank-landing/README.md`.
|
|||
|
||||
## Demo withdraw + auto-account API
|
||||
|
||||
`demo-withdraw-api.py` listens on **127.0.0.1:19096** (proxied by nginx on the landing):
|
||||
**FP reference SoT:** `$HOME/git/admin-logs/taler/francpaysan-admin-log`
|
||||
(`files/testpaysan/demo-withdraw-api.py`, `files/caddy/Caddyfile` `@wdGet`).
|
||||
GOA ports that pattern: mint `amount`+`exchange_url`, and GET Integration
|
||||
injects `suggested_exchange` / `required_exchange` (Android/iOS).
|
||||
|
||||
`demo-withdraw-api.py` listens on **127.0.0.1:19096** (in bank CTR; nginx on :9013):
|
||||
|
||||
| Path | Behaviour |
|
||||
|------|-----------|
|
||||
| `GET /demo-withdraw.json` | Mint one-shot withdraw from shared **`explorer`** pool; write `withdraw.uri` + watch ids |
|
||||
| `GET /auto-account.json` | Public `POST /accounts` with generated **`goa-account-<random>`** user + password containing **pleasechangeme**; **balance GOA:0**; return credentials once |
|
||||
| `GET /taler-integration/withdrawal-operation/*` | Proxy libeufin + inject `suggested_exchange`/`required_exchange` |
|
||||
|
||||
Install / restart:
|
||||
**Public path (Android):** Caddy `@wdGet` (GET only) → landing **:9013** → nginx → **:19096**.
|
||||
POST / other Integration stays Caddy → **:9012** (raw libeufin).
|
||||
FP stage proxies `@wdGet` straight to host `:19096`; GOA keeps 19096 CTR-only
|
||||
and routes via published 9013 instead.
|
||||
|
||||
Install / restart (host, podman → `taler-hacktivism-bank`):
|
||||
|
||||
```bash
|
||||
./install-demo-withdraw-api.sh
|
||||
# Public checks:
|
||||
curl -sS https://bank.hacktivism.ch/intro/demo-withdraw.json | head
|
||||
curl -sS https://bank.hacktivism.ch/intro/auto-account.json | head # creates a real account
|
||||
# After Caddy @wdGet + nginx Integration are live:
|
||||
WID=… # from demo-withdraw.json
|
||||
curl -sS "https://bank.hacktivism.ch/taler-integration/withdrawal-operation/$WID" \
|
||||
| python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("suggested_exchange"), d.get("required_exchange"))'
|
||||
```
|
||||
|
||||
Requires **python3** in the bank container. Env: `BANK_URL`, `BANK_USER`/`BANK_PASS`
|
||||
(or `/root/bank-explorer-password.txt`), `AMOUNT` (default `GOA:10` for shared withdraws).
|
||||
(or `/root/bank-explorer-password.txt`), `AMOUNT` (default `GOA:10`),
|
||||
`EXCHANGE_URL` (default `https://exchange.hacktivism.ch/`).
|
||||
|
||||
**Caddy (root on koopa — you apply):** insert `@wdGet` before the bank catch-all
|
||||
`reverse_proxy 127.0.0.1:9012` in `~/koopa-caddy/Caddyfile` (SoT:
|
||||
`configs/caddy/Caddyfile` / `host/caddy/Caddyfile`; paste-ready snippet:
|
||||
`scripts/caddy/wdGet-bank-snippet.caddy`, also copied live as
|
||||
`~/koopa-caddy/wdGet-bank-snippet.caddy`), then `sudo ~/bin/caddy-apply`.
|
||||
Caddy alone is not enough — demo-api + nginx Integration must be installed
|
||||
via `./install-demo-withdraw-api.sh` first.
|
||||
|
||||
### Auto-confirm (explorer only)
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ BANK = os.environ.get("BANK_URL", "http://127.0.0.1:9012").rstrip("/")
|
|||
BANK_PUBLIC = os.environ.get("BANK_PUBLIC", "https://bank.hacktivism.ch").rstrip("/")
|
||||
USER = os.environ.get("BANK_USER", "explorer")
|
||||
AMOUNT = os.environ.get("AMOUNT", "GOA:10")
|
||||
EXCHANGE = (
|
||||
os.environ.get("EXCHANGE_URL", "https://exchange.hacktivism.ch/").rstrip("/")
|
||||
+ "/"
|
||||
)
|
||||
LANDING = Path(os.environ.get("LANDING_DIR", "/var/www/bank-landing"))
|
||||
LISTEN = ("127.0.0.1", int(os.environ.get("DEMO_WITHDRAW_PORT", "19096")))
|
||||
|
||||
|
|
@ -112,7 +116,7 @@ def http_json(method: str, url: str, body=None, headers=None, auth=None):
|
|||
return e.code, {"raw": raw[:500]}
|
||||
|
||||
|
||||
def mint_withdraw() -> dict:
|
||||
def mint_withdraw(amount: str | None = None) -> dict:
|
||||
pw = load_pass()
|
||||
code, tok = http_json(
|
||||
"POST",
|
||||
|
|
@ -123,10 +127,14 @@ def mint_withdraw() -> dict:
|
|||
if code != 200 or not tok.get("access_token"):
|
||||
raise RuntimeError(f"token failed HTTP {code}: {tok}")
|
||||
access = tok["access_token"]
|
||||
amt = amount or AMOUNT
|
||||
if ":" not in str(amt):
|
||||
amt = f"GOA:{amt}"
|
||||
# FP pattern: amount + exchange_url (not suggested_amount alone)
|
||||
code, wd = http_json(
|
||||
"POST",
|
||||
f"{BANK}/accounts/{USER}/withdrawals",
|
||||
{"suggested_amount": AMOUNT},
|
||||
{"amount": amt, "exchange_url": EXCHANGE},
|
||||
headers={"Authorization": f"Bearer {access}"},
|
||||
)
|
||||
if code not in (200, 201):
|
||||
|
|
@ -142,7 +150,7 @@ def mint_withdraw() -> dict:
|
|||
uri = normalize_taler_withdraw_uri(str(uri).strip())
|
||||
LANDING.mkdir(parents=True, exist_ok=True)
|
||||
(LANDING / "withdraw.uri").write_text(uri + "\n")
|
||||
(LANDING / "withdraw.amount").write_text(AMOUNT + "\n")
|
||||
(LANDING / "withdraw.amount").write_text(amt + "\n")
|
||||
(LANDING / "withdraw.created").write_text(
|
||||
time.strftime("%Y-%m-%dT%H:%MZ", time.gmtime()) + "\n"
|
||||
)
|
||||
|
|
@ -151,7 +159,8 @@ def mint_withdraw() -> dict:
|
|||
"ok": True,
|
||||
"taler_withdraw_uri": uri,
|
||||
"withdrawal_id": wid,
|
||||
"amount": AMOUNT,
|
||||
"amount": amt,
|
||||
"exchange_url": EXCHANGE,
|
||||
"pool_account": USER,
|
||||
"taler_integration_base": f"{BANK_PUBLIC}/taler-integration/",
|
||||
"hint": "Open in GNU Taler Wallet (iOS/Android/desktop). No bank registration.",
|
||||
|
|
@ -301,15 +310,54 @@ class Handler(BaseHTTPRequestHandler):
|
|||
self._cors()
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
path = self.path.split("?", 1)[0]
|
||||
def _proxy_wd(self, parsed):
|
||||
"""GET withdrawal-operation: inject suggested/required exchange (Android/iOS)."""
|
||||
q = ("?" + parsed.query) if parsed.query else ""
|
||||
url = f"{BANK}{parsed.path}{q}"
|
||||
ctx = ssl.create_default_context()
|
||||
req = urllib.request.Request(url, method="GET")
|
||||
try:
|
||||
with urllib.request.urlopen(req, context=ctx, timeout=70) as r:
|
||||
raw = r.read()
|
||||
status = r.status
|
||||
except urllib.error.HTTPError as e:
|
||||
raw = e.read()
|
||||
status = e.code
|
||||
except Exception as e:
|
||||
raw = json.dumps({"ok": False, "error": str(e)}).encode()
|
||||
status = 502
|
||||
try:
|
||||
body = json.loads(raw.decode() or "{}")
|
||||
if isinstance(body, dict):
|
||||
body.setdefault("suggested_exchange", EXCHANGE)
|
||||
body.setdefault("required_exchange", EXCHANGE)
|
||||
raw = json.dumps(body).encode()
|
||||
except Exception:
|
||||
pass
|
||||
self.send_response(status)
|
||||
self._cors()
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Content-Length", str(len(raw)))
|
||||
self.end_headers()
|
||||
self.wfile.write(raw)
|
||||
|
||||
def do_GET(self):
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
parsed = urlparse(self.path)
|
||||
path = parsed.path
|
||||
qs = parse_qs(parsed.query)
|
||||
try:
|
||||
if path.startswith("/taler-integration/withdrawal-operation/"):
|
||||
self._proxy_wd(parsed)
|
||||
return
|
||||
if path in (
|
||||
"/",
|
||||
"/demo-withdraw.json",
|
||||
"/intro/demo-withdraw.json",
|
||||
):
|
||||
body = mint_withdraw()
|
||||
amt = (qs.get("amount") or qs.get("n") or [None])[0]
|
||||
body = mint_withdraw(amt)
|
||||
elif path in (
|
||||
"/auto-account.json",
|
||||
"/intro/auto-account.json",
|
||||
|
|
|
|||
|
|
@ -14,61 +14,86 @@ podman exec -u root "$CTR" chmod 755 \
|
|||
/usr/local/bin/auto-confirm-withdrawals.sh \
|
||||
/usr/local/bin/refresh-demo-withdraw.sh
|
||||
|
||||
# nginx: proxy demo-withdraw.json
|
||||
NGX=/etc/nginx/sites-available/bank-landing
|
||||
# nginx: ensure demo-withdraw / auto-account / Integration → :19096
|
||||
# FP pattern: Caddy @wdGet GET → :9013 → this location → demo-api
|
||||
# (single in-CTR python; no nested podman)
|
||||
podman exec -u root "$CTR" bash -lc '
|
||||
set -e
|
||||
f=/etc/nginx/sites-available/bank-landing
|
||||
if ! grep -q demo-withdraw.json "$f"; then
|
||||
# insert before location /intro/
|
||||
python3 - <<PY
|
||||
from pathlib import Path
|
||||
p = Path("/etc/nginx/sites-available/bank-landing")
|
||||
t = p.read_text()
|
||||
block=""" location = /intro/demo-withdraw.json {
|
||||
changed = False
|
||||
anchor = " location /intro/ {"
|
||||
blocks = []
|
||||
if "demo-withdraw.json" not in t:
|
||||
blocks.append(""" location = /intro/demo-withdraw.json {
|
||||
proxy_pass http://127.0.0.1:19096/demo-withdraw.json;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
add_header Cache-Control "no-store" always;
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
}
|
||||
"""
|
||||
if "demo-withdraw.json" not in t:
|
||||
t=t.replace(" location /intro/ {", block+" location /intro/ {", 1)
|
||||
p.write_text(t)
|
||||
print("nginx location added")
|
||||
""")
|
||||
print("nginx demo-withdraw location added")
|
||||
else:
|
||||
print("nginx already has demo-withdraw")
|
||||
if "auto-account.json" not in t:
|
||||
t=p.read_text()
|
||||
block2=""" location = /intro/auto-account.json {
|
||||
blocks.append(""" location = /intro/auto-account.json {
|
||||
proxy_pass http://127.0.0.1:19096/auto-account.json;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
add_header Cache-Control "no-store" always;
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
}
|
||||
"""
|
||||
t=t.replace(" location /intro/ {", block2+" location /intro/ {", 1)
|
||||
p.write_text(t)
|
||||
""")
|
||||
print("nginx auto-account location added")
|
||||
else:
|
||||
print("nginx already has auto-account")
|
||||
if "taler-integration/withdrawal-operation" not in t:
|
||||
blocks.append(""" # FP pattern: GET Integration via demo-api (suggested/required_exchange)
|
||||
# Caddy @wdGet → :9013 → here → :19096; POST/other stays on :9012
|
||||
location /taler-integration/withdrawal-operation/ {
|
||||
proxy_pass http://127.0.0.1:19096;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_read_timeout 70s;
|
||||
add_header Cache-Control "no-store" always;
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
}
|
||||
""")
|
||||
print("nginx Integration withdrawal-operation location added")
|
||||
else:
|
||||
print("nginx already has Integration withdrawal-operation")
|
||||
if blocks:
|
||||
if anchor not in t:
|
||||
raise SystemExit("nginx anchor location /intro/ not found")
|
||||
t = t.replace(anchor, "".join(blocks) + anchor, 1)
|
||||
p.write_text(t)
|
||||
changed = True
|
||||
if not changed:
|
||||
print("nginx locations already complete")
|
||||
PY
|
||||
nginx -t && nginx -s reload || true
|
||||
else
|
||||
echo "nginx already configured"
|
||||
fi
|
||||
'
|
||||
|
||||
# start/restart API + single auto-confirm loop (flock inside script)
|
||||
podman exec -u root "$CTR" bash -lc '
|
||||
# stop demo-withdraw by pid (avoid pkill -f self-match)
|
||||
# stop demo-withdraw by pid (avoid pkill -f self-match); wait for :19096
|
||||
ps -eo pid=,args= | awk "/demo-withdraw-api\\.py/ && !/awk/ {print \$1}" | while read p; do kill \$p 2>/dev/null || true; done
|
||||
sleep 0.3
|
||||
sleep 1
|
||||
ps -eo pid=,args= | awk "/demo-withdraw-api\\.py/ && !/awk/ {print \$1}" | while read p; do kill -9 \$p 2>/dev/null || true; done
|
||||
sleep 0.5
|
||||
nohup python3 /usr/local/bin/demo-withdraw-api.py \
|
||||
>>/var/log/demo-withdraw-api.log 2>&1 </dev/null &
|
||||
echo "api pid $!"
|
||||
# fail loud if bind lost to a leftover listener
|
||||
sleep 0.5
|
||||
ps -eo pid=,args= | awk "/demo-withdraw-api\\.py/ && !/awk/" || {
|
||||
echo "ERROR: demo-withdraw-api failed to stay up (port busy?)" >&2
|
||||
tail -20 /var/log/demo-withdraw-api.log >&2 || true
|
||||
exit 1
|
||||
}
|
||||
# stop auto-confirm by pid
|
||||
ps -eo pid=,args= | awk "/auto-confirm-withdrawals\\.sh --loop/ && !/awk/ {print \$1}" | while read p; do kill \$p 2>/dev/null || true; done
|
||||
sleep 0.5
|
||||
|
|
|
|||
|
|
@ -203,8 +203,11 @@ if [ -n "$ADMIN_TOKEN" ]; then
|
|||
u=$(printf '%s' "$line" | sed -n 's/.*"username"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
[ -n "$u" ] && echo "$u"
|
||||
done >"$WORKDIR/usernames.txt" || true
|
||||
ACCOUNTS_N=$(grep -cve '^\s*$' "$WORKDIR/usernames.txt" 2>/dev/null || echo 0)
|
||||
ACCOUNTS_USERS=$(grep -Eve '^(admin|exchange)$' "$WORKDIR/usernames.txt" 2>/dev/null | grep -cve '^\s*$' || echo 0)
|
||||
# grep -c exits 1 on zero matches; do not `|| echo 0` (would print 0\n0 and break JSON)
|
||||
ACCOUNTS_N=$(grep -cve '^\s*$' "$WORKDIR/usernames.txt" 2>/dev/null || true)
|
||||
ACCOUNTS_N=${ACCOUNTS_N:-0}
|
||||
ACCOUNTS_USERS=$(grep -Eve '^(admin|exchange)$' "$WORKDIR/usernames.txt" 2>/dev/null | grep -cve '^\s*$' || true)
|
||||
ACCOUNTS_USERS=${ACCOUNTS_USERS:-0}
|
||||
else
|
||||
echo "$BANK_USER" >"$WORKDIR/usernames.txt"
|
||||
ACCOUNTS_N=1
|
||||
|
|
@ -323,9 +326,11 @@ sort -t$'\t' -k2,2nr "$WORKDIR/all-in.tsv" -o "$WORKDIR/all-in-sorted.tsv" 2>/de
|
|||
|| cp "$WORKDIR/all-in.tsv" "$WORKDIR/all-in-sorted.tsv"
|
||||
|
||||
# Unique reserves = individual wallet withdraws (each wallet reserve_pub)
|
||||
WALLETS_N=$(awk -F'\t' '$5!=""{print $5}' "$WORKDIR/all-wd-sorted.tsv" | sort -u | grep -cve '^\s*$' || echo 0)
|
||||
WALLETS_N=$(awk -F'\t' '$5!=""{print $5}' "$WORKDIR/all-wd-sorted.tsv" | sort -u | grep -cve '^\s*$' || true)
|
||||
WALLETS_N=${WALLETS_N:-0}
|
||||
# Accounts that funded at least one withdraw
|
||||
ACCOUNTS_WITH_WD=$(awk -F'\t' '$4!=""{print $4}' "$WORKDIR/all-wd-sorted.tsv" | sort -u | grep -cve '^\s*$' || echo 0)
|
||||
ACCOUNTS_WITH_WD=$(awk -F'\t' '$4!=""{print $4}' "$WORKDIR/all-wd-sorted.tsv" | sort -u | grep -cve '^\s*$' || true)
|
||||
ACCOUNTS_WITH_WD=${ACCOUNTS_WITH_WD:-0}
|
||||
|
||||
# Aggregates
|
||||
NOW=$(now_unix)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
# Run INSIDE taler-hacktivism-exchange-ansible.
|
||||
# Writes /var/www/exchange-landing/stats.json
|
||||
#
|
||||
# Data lives in Postgres DB taler-exchange, schema exchange.*
|
||||
# Data lives in Postgres (DB name varies: vanilla regio-ng uses "exchange";
|
||||
# older hacktivism images use "taler-exchange"). Schema is exchange.*.
|
||||
# (reserves, reserves_in, known_coins, withdraw, denominations, …)
|
||||
#
|
||||
# IMPORTANT: never use psql -F$'\t' -v ON_ERROR_STOP=1
|
||||
|
|
@ -16,7 +17,38 @@ LANDING_DIR="${LANDING_DIR:-/var/www/exchange-landing}"
|
|||
OUT="$LANDING_DIR/stats.json"
|
||||
RUN="$LANDING_DIR/stats-run.json"
|
||||
TMP="${OUT}.tmp.$$"
|
||||
DB="${EXCHANGE_DB:-taler-exchange}"
|
||||
# Resolve DB: EXCHANGE_DB env → CONFIG=postgres:///NAME in secret conf → fallbacks
|
||||
_resolve_exchange_db() {
|
||||
if [ -n "${EXCHANGE_DB:-}" ]; then
|
||||
printf '%s' "$EXCHANGE_DB"
|
||||
return
|
||||
fi
|
||||
local conf c name
|
||||
for conf in \
|
||||
/etc/taler-exchange/secrets/exchange-db.secret.conf \
|
||||
/etc/taler/secrets/exchange-db.secret.conf; do
|
||||
if [ -r "$conf" ]; then
|
||||
c=$(grep -E '^[[:space:]]*CONFIG[[:space:]]*=' "$conf" | head -1 | sed 's/^[^=]*=[[:space:]]*//')
|
||||
# postgres:///dbname or postgres://user@/dbname
|
||||
name=$(printf '%s' "$c" | sed -n 's#.*postgres://[^/]*/\([^?]*\).*#\1#p')
|
||||
if [ -n "$name" ]; then
|
||||
printf '%s' "$name"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
for name in exchange taler-exchange; do
|
||||
if [ -d "/var/lib/postgresql" ] || command -v psql >/dev/null 2>&1; then
|
||||
if runuser -u postgres -- psql -d "$name" -At -c 'SELECT 1' >/dev/null 2>&1 \
|
||||
|| su -s /bin/bash postgres -c "psql -d $name -At -c 'SELECT 1'" >/dev/null 2>&1; then
|
||||
printf '%s' "$name"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
printf '%s' "taler-exchange"
|
||||
}
|
||||
DB="$(_resolve_exchange_db)"
|
||||
BASE_URL="${EXCHANGE_BASE_URL:-https://exchange.hacktivism.ch}"
|
||||
ERRLOG="${LANDING_STATS_ERRLOG:-/var/log/landing-stats-exchange.err}"
|
||||
mkdir -p "$LANDING_DIR"
|
||||
|
|
@ -253,7 +285,7 @@ cat >"$TMP" <<EOF
|
|||
{
|
||||
"ok": true,
|
||||
"source": "exchange-db",
|
||||
"schema": "exchange.* @ taler-exchange",
|
||||
"schema": "exchange.* @ ${DB}",
|
||||
"focus": "coins",
|
||||
"timezone": $(json_str "$TZ"),
|
||||
"generated_at": $(json_str "$GEN"),
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ COLLECT_MERCHANT="${COLLECT_MERCHANT:-1}"
|
|||
COLLECT_RESOURCES="${COLLECT_RESOURCES:-1}"
|
||||
|
||||
# Containers (empty = skip podman publish for that role)
|
||||
BANK_CTR="${BANK_CTR:-taler-hacktivism-bank}"
|
||||
EX_CTR="${EX_CTR:-taler-hacktivism-exchange-ansible}"
|
||||
MER_CTR="${MER_CTR:-taler-hacktivism}"
|
||||
BANK_CTR="${BANK_CTR:-goa-regio-ng}"
|
||||
EX_CTR="${EX_CTR:-goa-regio-ng}"
|
||||
MER_CTR="${MER_CTR:-goa-regio-ng}"
|
||||
|
||||
BANK_URL="${BANK_URL:-http://127.0.0.1:9012}"
|
||||
BANK_PUBLIC_URL="${BANK_PUBLIC_URL:-https://bank.hacktivism.ch}"
|
||||
|
|
@ -322,10 +322,14 @@ run_incontainer_stats() {
|
|||
fi
|
||||
log "$label: run $script inside $ctr"
|
||||
set +e
|
||||
# Pass optional DB overrides (vanilla regio-ng: EXCHANGE_DB=exchange)
|
||||
podman exec \
|
||||
-e LANDING_DIR="$landing" \
|
||||
-e TZ=Europe/Zurich \
|
||||
-e PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
|
||||
${EXCHANGE_DB:+-e EXCHANGE_DB="$EXCHANGE_DB"} \
|
||||
${MERCHANT_DB:+-e MERCHANT_DB="$MERCHANT_DB"} \
|
||||
${EXCHANGE_BASE_URL:+-e EXCHANGE_BASE_URL="$EXCHANGE_BASE_URL"} \
|
||||
"$ctr" bash "$script" >>"$LOG_DIR/${label}.log" 2>&1
|
||||
local ec=$?
|
||||
set -e
|
||||
|
|
|
|||
|
|
@ -130,6 +130,11 @@ def get_token(bank: str, user: str, password: str) -> str:
|
|||
|
||||
def list_all_accounts(bank: str, token: str, delta: int) -> List[str]:
|
||||
"""List accounts; page with start if needed."""
|
||||
# libeufin-bank: |delta| must be in 1..1024 (same floor as Param 'limit')
|
||||
if delta == 0:
|
||||
delta = -1024
|
||||
elif abs(delta) > 1024:
|
||||
delta = -1024 if delta < 0 else 1024
|
||||
names: List[str] = []
|
||||
seen: Set[str] = set()
|
||||
start: Optional[int] = None
|
||||
|
|
@ -213,9 +218,10 @@ def iter_transactions(
|
|||
pages = 0
|
||||
safety = max_pages if max_pages > 0 else 10_000
|
||||
|
||||
page = min(abs(page), 1024) or 1024
|
||||
while pages < safety:
|
||||
pages += 1
|
||||
q = f"delta=-{abs(page)}"
|
||||
q = f"delta=-{page}"
|
||||
if start is not None:
|
||||
q += f"&start={start}"
|
||||
code, data, raw = http_json(
|
||||
|
|
@ -364,7 +370,7 @@ def main() -> int:
|
|||
ap.add_argument(
|
||||
"--accounts-delta",
|
||||
type=int,
|
||||
default=int(env("ACCOUNTS_DELTA", "-10000") or "-10000"),
|
||||
default=int(env("ACCOUNTS_DELTA", "-1024") or "-1024"),
|
||||
)
|
||||
ap.add_argument("--recent", type=int, default=int(env("RECENT_WD_N", "10") or "10"))
|
||||
ap.add_argument("--public-base", default=env("BANK_PUBLIC_URL", "https://bank.hacktivism.ch"))
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
# listens on 9014 (exchange) / 9015 (merchant).
|
||||
#
|
||||
# Port map (wire these in Caddy / podman -p):
|
||||
# 9013 bank landing (already on taler-hacktivism-bank)
|
||||
# 9014 exchange landing (taler-hacktivism-exchange-ansible)
|
||||
# 9015 merchant landing (taler-hacktivism)
|
||||
# 9013 bank landing
|
||||
# 9014 exchange landing
|
||||
# 9015 merchant landing
|
||||
# Unified vanilla CTR: set LANDING_CTR=goa-regio-ng (default) so all three
|
||||
# landings land in the same container publishing 9010-9015.
|
||||
#
|
||||
# Run on koopa (host) with podman access.
|
||||
set -euo pipefail
|
||||
|
|
@ -18,9 +20,10 @@ SRC_BANK="${SRC_BANK:-$ROOT/configs/bank-landing}"
|
|||
SRC_QR="${SRC_QR:-$ROOT/configs/bank-landing/qrcode.min.js}"
|
||||
SRC_GOA_AMT="${SRC_GOA_AMT:-$ROOT/configs/shared/goa-amount.js}"
|
||||
|
||||
C_EX=taler-hacktivism-exchange-ansible
|
||||
C_MER=taler-hacktivism
|
||||
C_BANK="${C_BANK:-taler-hacktivism-bank}"
|
||||
LANDING_CTR="${LANDING_CTR:-goa-regio-ng}"
|
||||
C_EX="${C_EX:-$LANDING_CTR}"
|
||||
C_MER="${C_MER:-$LANDING_CTR}"
|
||||
C_BANK="${C_BANK:-$LANDING_CTR}"
|
||||
|
||||
# Prefer per-landing copy, then shared (keeps bank/exchange/merchant in sync)
|
||||
resolve_goa_amount() {
|
||||
|
|
@ -104,8 +107,8 @@ podman exec "$C_MER" curl -sS -m 3 -o /dev/null -w "merchant_landing=%{http_code
|
|||
|
||||
echo
|
||||
echo "PORTS TO WIRE (host → Caddy / firewall / podman -p):"
|
||||
echo " 9013 bank landing (taler-hacktivism-bank) already published"
|
||||
echo " 9014 exchange landing (taler-hacktivism-exchange-ansible) NEEDS -p 9014:9014"
|
||||
echo " 9015 merchant landing (taler-hacktivism) NEEDS -p 9015:9015"
|
||||
echo " 9013 bank landing ($C_BANK)"
|
||||
echo " 9014 exchange landing ($C_EX)"
|
||||
echo " 9015 merchant landing ($C_MER)"
|
||||
echo
|
||||
echo "If host curl to :9014/:9015 fails, republish pasta ports (commit+replace) — see README."
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Stack profile: GOA / hacktivism
|
||||
# Stack profile: GOA / goa-regio-ng vanilla (9010-9015)
|
||||
# systemd EnvironmentFile: KEY=value only (no export)
|
||||
BANK_CTR=taler-hacktivism-bank
|
||||
EX_CTR=taler-hacktivism-exchange-ansible
|
||||
MER_CTR=taler-hacktivism
|
||||
BANK_CTR=goa-regio-ng
|
||||
EX_CTR=goa-regio-ng
|
||||
MER_CTR=goa-regio-ng
|
||||
BANK_URL=http://127.0.0.1:9012
|
||||
BANK_PUBLIC_URL=https://bank.hacktivism.ch
|
||||
EXCHANGE_CONFIG_URL=https://exchange.hacktivism.ch/config
|
||||
|
|
@ -15,4 +15,4 @@ COLLECT_EXCHANGE=1
|
|||
COLLECT_MERCHANT=1
|
||||
COLLECT_RESOURCES=1
|
||||
PUBLISH_PODMAN=1
|
||||
STATS_SOURCE_LABEL="host collect_bank_stats.py goa hacktivism"
|
||||
STATS_SOURCE_LABEL="host collect_bank_stats.py goa regio-ng vanilla"
|
||||
|
|
|
|||
179
scripts/taler-landing/stamp-landing-stack.sh
Normal file
179
scripts/taler-landing/stamp-landing-stack.sh
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#!/usr/bin/env bash
|
||||
# Fill landing stack-bar package versions from live CTR dpkg (not hand-edited HTML).
|
||||
#
|
||||
# Reads: configs/shared/landing-stack.json (package lists + vanilla href)
|
||||
# Writes: configs/{bank,exchange,merchant}-landing/index.html (<!-- stack-bar --> block)
|
||||
# configs/shared/landing-stack-versions.json (last dpkg snapshot)
|
||||
#
|
||||
# Usage (from koopa-admin-log root, laptop or koopa):
|
||||
# ./scripts/taler-landing/stamp-landing-stack.sh
|
||||
# ./scripts/taler-landing/stamp-landing-stack.sh --ctr goa-regio-ng --ssh hernani@192.168.100.95
|
||||
# ./scripts/taler-landing/stamp-landing-stack.sh bank exchange
|
||||
#
|
||||
# After this, bump footer dates with:
|
||||
# ./scripts/taler-landing/stamp-landing-version.sh --bump --all
|
||||
# Then deploy (unified vanilla CTR):
|
||||
# LANDING_CTR=goa-regio-ng ./scripts/taler-landing/deploy-landings.sh
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
STACK_FILE="$ROOT/configs/shared/landing-stack.json"
|
||||
VERS_OUT="$ROOT/configs/shared/landing-stack-versions.json"
|
||||
|
||||
CTR="${LANDING_CTR:-goa-regio-ng}"
|
||||
SSH_HOST="${LANDING_SSH:-hernani@192.168.100.95}"
|
||||
USE_SSH=1
|
||||
sites=()
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--ctr) CTR="${2:-}"; shift 2 ;;
|
||||
--ssh) SSH_HOST="${2:-}"; USE_SSH=1; shift 2 ;;
|
||||
--local) USE_SSH=0; shift ;;
|
||||
bank|exchange|merchant) sites+=("$1"); shift ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "unknown arg: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "${#sites[@]}" -eq 0 ]; then
|
||||
sites=(bank exchange merchant)
|
||||
fi
|
||||
|
||||
[ -f "$STACK_FILE" ] || { echo "missing $STACK_FILE" >&2; exit 1; }
|
||||
|
||||
# Collect unique package names from JSON for the selected sites
|
||||
mapfile -t PKGS < <(python3 - "$STACK_FILE" "${sites[@]}" <<'PY'
|
||||
import json, sys
|
||||
data = json.load(open(sys.argv[1], encoding="utf-8"))
|
||||
sites = sys.argv[2:]
|
||||
seen = []
|
||||
for s in sites:
|
||||
for p in data["sites"][s]["packages"]:
|
||||
if p not in seen:
|
||||
seen.append(p)
|
||||
print("\n".join(seen))
|
||||
PY
|
||||
)
|
||||
|
||||
if [ "${#PKGS[@]}" -eq 0 ]; then
|
||||
echo "no packages configured" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkg_args=$(printf '%q ' "${PKGS[@]}")
|
||||
query_cmd="podman exec $(printf '%q' "$CTR") dpkg-query -W -f='\${Package}=\${Version}\n' ${pkg_args}"
|
||||
|
||||
if [ "$USE_SSH" = 1 ]; then
|
||||
echo "dpkg ← ${SSH_HOST} ctr=${CTR}"
|
||||
# shellcheck disable=SC2086
|
||||
raw=$(ssh -o BatchMode=yes -o ConnectTimeout=12 "$SSH_HOST" "podman exec $(printf '%q' "$CTR") dpkg-query -W -f='\${Package}=\${Version}\n' ${pkg_args}")
|
||||
else
|
||||
echo "dpkg ← local ctr=${CTR}"
|
||||
# shellcheck disable=SC2086
|
||||
raw=$(podman exec "$CTR" dpkg-query -W -f='${Package}=${Version}\n' "${PKGS[@]}")
|
||||
fi
|
||||
|
||||
python3 - "$STACK_FILE" "$VERS_OUT" "$ROOT" "$CTR" "$SSH_HOST" "$raw" "${sites[@]}" <<'PY'
|
||||
import json, re, sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
stack_path, vers_out, root, ctr, ssh_host, raw = sys.argv[1:7]
|
||||
sites = sys.argv[7:]
|
||||
stack = json.load(open(stack_path, encoding="utf-8"))
|
||||
tz = ZoneInfo("Europe/Zurich")
|
||||
now = datetime.now(tz)
|
||||
iso = now.isoformat(timespec="seconds")
|
||||
human = now.strftime("%Y-%m-%d %H:%M %Z")
|
||||
|
||||
versions = {}
|
||||
for line in raw.splitlines():
|
||||
line = line.strip()
|
||||
if not line or "=" not in line:
|
||||
continue
|
||||
pkg, ver = line.split("=", 1)
|
||||
# display upstream-ish: drop Debian revision (1.6.10-0+trixie → 1.6.10)
|
||||
short = re.sub(r"-[0-9].*$", "", ver)
|
||||
versions[pkg] = {"dpkg": ver, "display": short}
|
||||
|
||||
missing = []
|
||||
for site in sites:
|
||||
for pkg in stack["sites"][site]["packages"]:
|
||||
if pkg not in versions:
|
||||
missing.append(pkg)
|
||||
if missing:
|
||||
raise SystemExit(f"dpkg missing packages: {', '.join(sorted(set(missing)))}")
|
||||
|
||||
vanilla_href = stack["vanilla_href"]
|
||||
vanilla_title = stack.get("vanilla_title", "vanilla")
|
||||
sep = '<span class="sep">·</span>'
|
||||
|
||||
def render_block(site: str) -> str:
|
||||
meta = stack["sites"][site]
|
||||
parts = [
|
||||
f' <!-- stack-bar -->',
|
||||
f' <p class="stack-bar" role="note" title="{meta["title"]}">',
|
||||
f' <strong>stack</strong>{sep}',
|
||||
f' <a href="{vanilla_href}" target="_blank" rel="noopener noreferrer" title="{vanilla_title}">vanilla</a>',
|
||||
]
|
||||
for pkg in meta["packages"]:
|
||||
disp = versions[pkg]["display"]
|
||||
parts.append(f" {sep}")
|
||||
parts.append(f" {pkg} {disp}")
|
||||
parts.append(" </p>")
|
||||
parts.append(" <!-- /stack-bar -->")
|
||||
return "\n".join(parts) + "\n"
|
||||
|
||||
site_html = {
|
||||
"bank": Path(root) / "configs/bank-landing/index.html",
|
||||
"exchange": Path(root) / "configs/exchange-landing/index.html",
|
||||
"merchant": Path(root) / "configs/merchant-landing/index.html",
|
||||
}
|
||||
|
||||
marker_re = re.compile(r"[ \t]*<!-- stack-bar -->.*?<!-- /stack-bar -->\n?", re.S)
|
||||
bare_re = re.compile(
|
||||
r"[ \t]*<p class=\"stack-bar\"[^>]*>.*?</p>\n?",
|
||||
re.S,
|
||||
)
|
||||
|
||||
for site in sites:
|
||||
path = site_html[site]
|
||||
text = path.read_text(encoding="utf-8")
|
||||
block = render_block(site)
|
||||
if marker_re.search(text):
|
||||
text = marker_re.sub(block, text, count=1)
|
||||
elif bare_re.search(text):
|
||||
text = bare_re.sub(block, text, count=1)
|
||||
else:
|
||||
raise SystemExit(f"no stack-bar in {path}")
|
||||
path.write_text(text, encoding="utf-8")
|
||||
print(f"stack → {path.relative_to(root)} ({site})")
|
||||
|
||||
out = {
|
||||
"updated_iso": iso,
|
||||
"updated_human": human,
|
||||
"ctr": ctr,
|
||||
"ssh": ssh_host if ssh_host else None,
|
||||
"packages": versions,
|
||||
"sites": {
|
||||
site: {
|
||||
"packages": {
|
||||
pkg: versions[pkg]["display"]
|
||||
for pkg in stack["sites"][site]["packages"]
|
||||
}
|
||||
}
|
||||
for site in ("bank", "exchange", "merchant")
|
||||
if site in stack["sites"]
|
||||
},
|
||||
}
|
||||
Path(vers_out).write_text(json.dumps(out, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
print(f"versions → {Path(vers_out).relative_to(root)}")
|
||||
print(f"OK stack stamped: {' '.join(sites)} @ {human}")
|
||||
PY
|
||||
|
||||
echo "OK stamp-landing-stack: ${sites[*]} ← ${CTR}"
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
# Host: koopa (hernani, podman). No Freigabe-bypass — caller must have Freigabe.
|
||||
#
|
||||
# ./goa-live-backup-upgrade.sh dry-run
|
||||
# ./goa-live-backup-upgrade.sh backup # stamp only (no apt / no commit)
|
||||
# ./goa-live-backup-upgrade.sh apply # backup + apt + commit + smoke
|
||||
# ./goa-live-backup-upgrade.sh status
|
||||
#
|
||||
|
|
@ -312,6 +313,12 @@ cmd_status() {
|
|||
|
||||
case "$MODE" in
|
||||
dry-run|dry) cmd_dry_run ;;
|
||||
backup)
|
||||
set_status BACKUP_RUNNING
|
||||
cmd_backup
|
||||
set_status BACKUP_OK "STAMP=$STAMP" "CURRENT=$ROOT/current"
|
||||
log "BACKUP_OK"
|
||||
;;
|
||||
apply) cmd_apply ;;
|
||||
status) cmd_status ;;
|
||||
-h|--help|help)
|
||||
|
|
@ -319,7 +326,7 @@ case "$MODE" in
|
|||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 dry-run|apply|status" >&2
|
||||
echo "usage: $0 dry-run|backup|apply|status" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue