bank: API for auto-created personal accounts (balance zero)

Add GET /intro/auto-account.json on the bank helper (demo-withdraw-api):
public registration with generated username/password, balance starts GOA:0,
credentials returned once for the client to display.

Nginx proxies the new path; install-demo-withdraw-api.sh installs the
location. This is separate from the shared explorer demo withdraw.
This commit is contained in:
Hernâni Marques 2026-07-10 20:42:20 +02:00
parent 65629ea57c
commit f341116371
No known key found for this signature in database
4 changed files with 267 additions and 14 deletions

View file

@ -448,6 +448,67 @@
transform: scale(0.92);
transform-origin: center top;
}
.own-acct-lead {
margin: 0 0 0.85rem;
color: var(--muted);
font-size: 0.95rem;
line-height: 1.45;
}
.own-acct-lead strong { color: #e8c878; }
.own-acct-creds {
margin: 0 0 0.85rem;
padding: 0.75rem 0.85rem;
border-radius: 12px;
background: rgba(94, 234, 212, 0.08);
border: 1px solid rgba(94, 234, 212, 0.35);
text-align: left;
}
.own-acct-warn {
margin: 0 0 0.65rem;
font-size: 0.86rem;
color: #ccfbf1;
line-height: 1.4;
}
.own-acct-warn strong { color: #5eead4; }
.own-acct-dl {
margin: 0;
display: grid;
gap: 0.45rem;
}
.own-acct-dl div {
display: grid;
grid-template-columns: 5.5rem 1fr;
gap: 0.35rem;
align-items: baseline;
}
.own-acct-dl dt {
margin: 0;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--muted);
}
.own-acct-dl dd {
margin: 0;
}
.own-acct-dl code {
font-size: 0.95rem;
font-weight: 700;
color: #f0d090;
word-break: break-all;
user-select: all;
}
#auto-account-btn {
border: 0;
cursor: pointer;
width: 100%;
max-width: 22rem;
}
#auto-account-btn:disabled {
opacity: 0.55;
cursor: wait;
}
.stats {
background: rgba(18, 28, 28, 0.55);
border: 1px solid rgba(62, 207, 191, 0.28);
@ -763,18 +824,43 @@
<div class="more-fold-body" id="more-fold-body" hidden>
<div class="more-card">
<h2>Own bank account?</h2>
<p>Register in the bank UI for your own balance (separate from the shared pool).</p>
<p class="own-acct-lead">
We can <strong>create a personal bank account for you</strong> automatically
(you do not pick a username or password). Balance starts at
<strong>GOA:0</strong> — separate from the shared pool.
</p>
<div class="more-actions" style="margin-bottom:0.75rem">
<button type="button" class="cta teal" id="auto-account-btn">
Create my bank account →
</button>
</div>
<div class="own-acct-creds" id="auto-account-box" hidden>
<p class="own-acct-warn" role="status">
<strong>Created for you.</strong>
Copy these credentials now — they are not stored for recovery.
Login at the bank UI; balance is <strong>GOA:0</strong>.
</p>
<dl class="own-acct-dl">
<div><dt>Username</dt><dd><code id="auto-account-user"></code></dd></div>
<div><dt>Password</dt><dd><code id="auto-account-pass"></code></dd></div>
<div><dt>Balance</dt><dd><code id="auto-account-bal">GOA:0</code></dd></div>
</dl>
<p class="meta" id="auto-account-status" style="margin:0.5rem 0 0"></p>
</div>
<div class="more-qr">
<div class="qr-taler-wrap">
<div class="goa-pay-taler-qr" id="qr-webui-wrap">
<div class="goa-pay-taler-qr__inner" id="qr-webui"></div>
<img class="goa-pay-taler-qr__logo" id="qr-webui-logo" alt="" />
</div>
<div class="qr-label">Bank UI · register / login</div>
<div class="qr-label">Bank UI · login with your credentials</div>
</div>
</div>
<div class="more-actions">
<a class="cta-sec" href="/webui/">Open bank UI →</a>
<a class="cta-sec" href="/webui/" id="auto-account-webui">Open bank UI →</a>
<button type="button" class="cta-sec" id="auto-account-again" hidden style="margin-top:0.45rem">
Generate another account
</button>
</div>
</div>
@ -1095,6 +1181,71 @@
);
webuiPainted = true;
});
function createAutoAccount() {
var btn = document.getElementById("auto-account-btn");
var box = document.getElementById("auto-account-box");
var st = document.getElementById("auto-account-status");
var again = document.getElementById("auto-account-again");
if (btn) {
btn.disabled = true;
btn.textContent = "Creating account…";
}
if (st) st.textContent = "";
fetch("/intro/auto-account.json", { cache: "no-store" })
.then(function (r) {
if (!r.ok) throw new Error("HTTP " + r.status);
return r.json();
})
.then(function (d) {
if (!d || !d.ok) throw new Error((d && d.error) || "create failed");
if (box) box.hidden = false;
var u = document.getElementById("auto-account-user");
var p = document.getElementById("auto-account-pass");
var b = document.getElementById("auto-account-bal");
if (u) u.textContent = d.username || "—";
if (p) p.textContent = d.password || "—";
if (b) b.textContent = d.balance || "GOA:0";
if (st) {
st.textContent =
"Account created for you · save username & password · balance " +
(d.balance || "GOA:0");
}
if (btn) {
btn.hidden = true;
btn.disabled = false;
btn.textContent = "Create my bank account →";
}
if (again) again.hidden = false;
})
.catch(function (err) {
if (box) box.hidden = false;
if (st) {
st.textContent =
"Could not create account — try again. " +
(err && err.message ? err.message : "");
}
if (btn) {
btn.disabled = false;
btn.hidden = false;
btn.textContent = "Create my bank account →";
}
});
}
var btn = document.getElementById("auto-account-btn");
var again = document.getElementById("auto-account-again");
if (btn) btn.addEventListener("click", createAutoAccount);
if (again) {
again.addEventListener("click", function () {
var b = document.getElementById("auto-account-btn");
if (b) {
b.hidden = false;
b.disabled = false;
}
again.hidden = true;
createAutoAccount();
});
}
})();
function fmtCest(unix, fallback) {

View file

@ -41,6 +41,14 @@ server {
add_header Cache-Control "no-store" always;
add_header Access-Control-Allow-Origin * always;
}
# Auto-create personal bank account (credentials returned once; balance GOA:0)
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;
}
location /intro/ {
alias /var/www/bank-landing/;
}