;; ported-from: src/lib/encryption.ts @ v1.0.0
;;
;; OrbitDB encryption hooks backed by the room's HKDF keys (PROTOCOL.md v2).
;;
;; `replication` encrypts the ENTIRE log entry (clock, writer key, identity ref,
;; signature, links, payload) before it becomes a content-addressed block — the
;; relay, bitswap observers, and anyone who merely learns the DB address see
;; opaque bytes. `data` additionally encrypts the payload inside the entry
;; (future-proofs a semi-trusted pinner that must validate entry structure but
;; never read content).
;;
;; Decrypt THROWS on failure — OrbitDB treats that as "reject this entry", which
;; is the whole access-control story: only secret-holders can produce entries
;; members accept (write:["*"] + decrypt-or-drop, v1 §3 transplanted).
(ns ardegazu.rooms.lib.encryption
(:require [ardegazu.rooms.js :as j]
[ardegazu.rooms.lib.crypto :as rc]
[shadow.cljs.modern :refer (js-await)]))
(defn- as-bytes
"dag-cbor hands us views into larger buffers; WebCrypto wants plain ones."
[u8]
(let [^js b u8]
(if (and (identical? 0 (.-byteOffset b))
(identical? (.-byteLength b) (.-byteLength (.-buffer b)))
(instance? js/ArrayBuffer (.-buffer b)))
b
(let [copy (js/Uint8Array. (.-byteLength b))]
(.set copy b)
copy))))
(defn- wrap [cipher]
(j/ordered
"encrypt" (fn [bytes] (rc/at-rest-seal cipher (as-bytes bytes)))
"decrypt" (fn [bytes]
(js-await [pt (rc/at-rest-open cipher (as-bytes bytes))]
(if (nil? pt)
(throw (js/Error. "Could not decrypt (not a room member or tampered block)"))
pt)))))
(defn make-log-encryption [room-crypto]
(js-await [pair (js/Promise.all
#js [(rc/log-entry-cipher room-crypto)
(rc/log-payload-cipher room-crypto)])]
(j/ordered "replication" (wrap (aget pair 0))
"data" (wrap (aget pair 1)))))