diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/crypto.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/crypto.js | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/crypto.js b/packages/meshbay-hub/src/meshbay_hub/static/crypto.js index 5ebf624..2346fa2 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/crypto.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/crypto.js @@ -230,6 +230,42 @@ function b64encode(bytes) { return btoa(String.fromCharCode(...bytes)); } +// ── Admin operation transcript ─────────────────────────────────────────────── +// Mirrors meshbay_common/adminop.py::admin_transcript(). Both sides build these +// bytes independently; they are never taken off the wire. +// +// Finding H5: the client used to sign 32 raw random bytes chosen by the node — a +// blind signing oracle. It now reconstructs a domain-separated, length-prefixed +// transcript naming the operation, subject, node and group, so the UI can show the +// user what they are authorizing and a signature cannot be reused elsewhere. + +const ADMIN_TRANSCRIPT_PREFIX = new TextEncoder().encode('meshbay:admin:v1'); + +function adminTranscript(op, nodePkB64, groupId, subject, nonceB64, ts) { + const enc = new TextEncoder(); + const fields = [ + enc.encode(op), + enc.encode(nodePkB64), + enc.encode(groupId), + enc.encode(subject), + b64decode(nonceB64), + enc.encode(String(ts)), + ]; + let total = ADMIN_TRANSCRIPT_PREFIX.length; + for (const f of fields) total += 4 + f.length; + + const out = new Uint8Array(total); + out.set(ADMIN_TRANSCRIPT_PREFIX, 0); + let off = ADMIN_TRANSCRIPT_PREFIX.length; + for (const f of fields) { + new DataView(out.buffer).setUint32(off, f.length, false); + off += 4; + out.set(f, off); + off += f.length; + } + return out; +} + // ── GEK proof (HMAC-SHA256 for handshake challenge) ───────────────────────── async function hmacGEK(gekRaw, nonceB64, offerFp, answerFp) { @@ -249,5 +285,5 @@ async function hmacGEK(gekRaw, nonceB64, offerFp, answerFp) { window.MeshBayCrypto = { importGEK, deriveChunkKey, decryptChunk, decryptChunkBin, decryptFile, generateGEK, wrapGEK, unwrapGEK, encryptChunk, b64encode, b64decode, - hmacGEK, + hmacGEK, adminTranscript, }; |