@umbra-privacy/ceremony 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +36 -5
  2. package/package.json +6 -1
package/dist/index.js CHANGED
@@ -111,13 +111,44 @@ var api = {
111
111
  `/api/ceremonies/${ceremonyId2}/contributions/${contributionId}/receipt`
112
112
  );
113
113
  },
114
- // Admin
115
- adminDashboard(ceremonyId2, adminKey) {
116
- return request(`/api/admin/ceremonies/${ceremonyId2}/dashboard`, {
117
- headers: { "X-Admin-Key": adminKey }
118
- });
114
+ // Admin — signed-request flow. Caller supplies the 64-byte Solana keypair
115
+ // bytes (32 secret + 32 public). The helper fetches a one-time challenge,
116
+ // builds the canonical message, hashes it with Keccak256, signs with
117
+ // Ed25519, and posts the actual GET with the three X-Admin-* headers.
118
+ async adminDashboard(ceremonyId2, keypair) {
119
+ const path = `/api/admin/ceremonies/${ceremonyId2}/dashboard`;
120
+ const headers = await signAdminRequest(keypair, "GET", path, new Uint8Array());
121
+ return request(path, { headers });
119
122
  }
120
123
  };
124
+ async function signAdminRequest(keypair, method, path, body) {
125
+ const { default: bs58 } = await import("bs58");
126
+ const ed = await import("@noble/ed25519");
127
+ const { keccak_256 } = await import("@noble/hashes/sha3");
128
+ const pubkeyB58 = bs58.encode(keypair.publicKey);
129
+ const chRes = await fetch(`${BASE}/api/admin/challenge`, {
130
+ method: "POST",
131
+ headers: { "Content-Type": "application/json" },
132
+ body: JSON.stringify({ pubkey: pubkeyB58 })
133
+ });
134
+ if (!chRes.ok) {
135
+ const text = await chRes.text();
136
+ throw new Error(`admin challenge failed: HTTP ${chRes.status}: ${text}`);
137
+ }
138
+ const { challenge } = await chRes.json();
139
+ const bodyHashHex = createHash("sha256").update(Buffer.from(body)).digest("hex");
140
+ const canonical = `${challenge}
141
+ ${method}
142
+ ${path}
143
+ ${bodyHashHex}`;
144
+ const digest = keccak_256(new TextEncoder().encode(canonical));
145
+ const signature = await ed.signAsync(digest, keypair.secretKey);
146
+ return {
147
+ "X-Admin-Pubkey": pubkeyB58,
148
+ "X-Admin-Challenge": challenge,
149
+ "X-Admin-Signature": Buffer.from(signature).toString("base64")
150
+ };
151
+ }
121
152
  var ChallengeIntegrityError = class extends Error {
122
153
  name = "ChallengeIntegrityError";
123
154
  };
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@umbra-privacy/ceremony",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Terminal UI for the Umbra Phase 2 trusted setup ceremony",
5
5
  "type": "module",
6
6
  "bin": {
7
+ "ceremony": "./dist/index.js",
7
8
  "umbra-ceremony": "./dist/index.js"
8
9
  },
9
10
  "files": [
@@ -25,8 +26,12 @@
25
26
  "node": ">=18.0.0"
26
27
  },
27
28
  "dependencies": {
29
+ "@noble/ed25519": "^2.1.0",
30
+ "@noble/hashes": "^1.5.0",
31
+ "bs58": "^6.0.0",
28
32
  "ink": "^5.1.0",
29
33
  "ink-spinner": "^5.0.0",
34
+ "js-sha3": "^0.9.3",
30
35
  "react": "^18.3.1",
31
36
  "snarkjs": "^0.7.6"
32
37
  },