Add register-by-signature, web fixes, bin scripts, docs
CI / test (push) Successful in 5s

- Register by signing service key: GET /v1/service-key, POST /v1/auth/register-by-signature
- Login auto-attempts register first for new users
- Web: default API URL momswap.produktor.duckdns.org, /libs/ static handler
- Docker: webbuild stage for geo-api-client, copy web+libs to runtime
- Bin scripts: test.sh, run.sh, up.sh, down.sh
- docs/ed25519-security-use-cases.md: use cases, message formats, examples
- SERVICE_PUBLIC_KEY env (defaults to ADMIN_PUBLIC_KEY)

Made-with: Cursor
This commit is contained in:
2026-03-01 12:58:44 +00:00
parent 978e0403eb
commit a5a97a0ad9
19 changed files with 405 additions and 41 deletions
+11
View File
@@ -546,9 +546,20 @@ class GeoApiClient {
}
return await res.json();
}
async getServicePublicKey() {
return this.request("/v1/service-key", { method: "GET" });
}
async createChallenge(publicKey) {
return this.request("/v1/auth/challenge", { method: "POST", body: { publicKey } });
}
async registerBySigningServiceKey(publicKey, privateKey) {
const { publicKey: servicePublicKey } = await this.getServicePublicKey();
const signature = await signMessage(privateKey, servicePublicKey);
await this.request("/v1/auth/register-by-signature", {
method: "POST",
body: { publicKey, signature }
});
}
async loginWithSignature(publicKey, privateKey) {
const challenge = await this.createChallenge(publicKey);
const signature = await signMessage(privateKey, challenge.messageToSign);
+13
View File
@@ -62,10 +62,23 @@ export class GeoApiClient {
return (await res.json()) as T;
}
async getServicePublicKey(): Promise<{ publicKey: string }> {
return this.request("/v1/service-key", { method: "GET" });
}
async createChallenge(publicKey: string): Promise<{ nonce: string; messageToSign: string }> {
return this.request("/v1/auth/challenge", { method: "POST", body: { publicKey } });
}
async registerBySigningServiceKey(publicKey: string, privateKey: string): Promise<void> {
const { publicKey: servicePublicKey } = await this.getServicePublicKey();
const signature = await signMessage(privateKey, servicePublicKey);
await this.request("/v1/auth/register-by-signature", {
method: "POST",
body: { publicKey, signature },
});
}
async loginWithSignature(publicKey: string, privateKey: string): Promise<string> {
const challenge = await this.createChallenge(publicKey);
const signature = await signMessage(privateKey, challenge.messageToSign);