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 | 40 |
1 files changed, 39 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 b74732c..0ca8ee5 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/crypto.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/crypto.js @@ -307,6 +307,43 @@ function b64encode(bytes) { return btoa(String.fromCharCode(...bytes)); } +// ── Admin operation subjects ──────────────────────────────────────────────── +// Mirrors meshbay_common/adminop.py. The subject is what the signature covers of +// a request, so an operation whose effect is several values names them all. +// Canonical JSON — sorted keys, no whitespace — so both sides build the same +// bytes, and `null`, `""` and a value stay distinct. + +function adminSubject(fields) { + const sorted = {}; + for (const k of Object.keys(fields).sort()) sorted[k] = fields[k]; + return JSON.stringify(sorted); +} + +// A secret named without being written: null (unchanged) and '' (clear) as +// themselves, anything else as its SHA-256. +async function secretDigest(value) { + if (!value) return value; + const d = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value)); + return 'sha256:' + Array.from(new Uint8Array(d)) + .map((b) => b.toString(16).padStart(2, '0')).join(''); +} + +function rootAddSubject(path, name, kind, writable, removable) { + return adminSubject({ path, name, kind, writable, removable }); +} + +function groupAttachSubject(name, sharedDir, writable) { + return adminSubject({ name, shared_dir: sharedDir, writable }); +} + +function inviteCreateSubject(userId, username) { + return adminSubject({ user_id: userId, username }); +} + +async function tmdbConfigSubject(token, language) { + return adminSubject({ token: await secretDigest(token), language }); +} + // ── Admin operation transcript ─────────────────────────────────────────────── // Mirrors meshbay_common/adminop.py::admin_transcript(). Both sides build these // bytes independently; they are never taken off the wire. @@ -535,7 +572,8 @@ window.MeshBayCrypto = { importGEK, deriveChunkKey, decryptChunkBin, openGroup, sealGroup, unwrapGEK, b64encode, b64decode, - adminTranscript, handshakeTranscript, handshakeProof, webrtcBinding, + adminTranscript, adminSubject, rootAddSubject, groupAttachSubject, + inviteCreateSubject, tmdbConfigSubject, handshakeTranscript, handshakeProof, webrtcBinding, challengeTranscript, joinTranscript, verifyNodeSignature, constantTimeEqual, deviceRequestTranscript, deviceAddTranscript, deviceHelloTranscript, deviceCodeHash, |