(ns ird.p2p.db.identity-test
"The shared OrbitDB identity: derived deterministically from the secret,
app salt and name; two Ed25519 keys; the keystore records OrbitDB is fed."
(:require [cljs.test :refer [deftest is]]
[cljs.core.async :refer [<!]]
[ird.p2p.crypto :as p2p-crypto]
[ird.p2p.db.errors :as err]
[ird.p2p.db.identity :as identity]
[ird.p2p.db.test-util :as tu :refer [deftest-async]]
[ird.p2p.impl.bytes :as bytes]
[ird.p2p.impl.webcrypto :as wc]))
(def secret "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8")
(def salt "test/v1")
(deftest-async deterministic
(let [a (<! (identity/from-secret {:secret secret :app-salt salt :name "chat"}))
b (<! (identity/from-secret {:secret secret :app-salt salt :name "chat"}))]
(is (= a b) "same secret, salt and name: the same identity, nothing exchanged")
(is (boolean (re-matches #"[0-9a-f]{64}" (:orbit-id a))) "the id is the hex of the identity key's public key")
(is (boolean (re-matches #"[0-9a-f]{64}" (:signing-key a))))
(is (not= (:orbit-id a) (:signing-key a)) "two distinct keys")
(is (= 43 (count (:id-seed a))) (count (:sign-seed a)))
(is (= (:orbit-id a) (bytes/b64->hex (bytes/b64url->b64 (:id-public-key a)))))
(is (= (:id-public-key a) (<! (wc/ed25519-public-key (:id-seed a)))) "public keys really belong to the seeds")
(is (= (:sign-public-key a) (<! (wc/ed25519-public-key (:sign-seed a)))))
(is (not= (:orbit-id a) (:orbit-id (<! (identity/from-secret {:secret secret :app-salt salt :name "other"})))) "differs by name")
(is (not= (:orbit-id a) (:orbit-id (<! (identity/from-secret {:secret secret :app-salt "other/v1" :name "chat"})))) "differs by salt")
(is (not= (:orbit-id a) (:orbit-id (<! (identity/from-secret {:secret (p2p-crypto/random-secret) :app-salt salt :name "chat"})))) "differs by secret")
(is (err/config-error? (<! (identity/from-secret {:secret "short" :app-salt salt :name "chat"}))))
(is (err/config-error? (<! (identity/from-secret {:secret secret :app-salt salt :name "a|b"}))))))
(deftest-async keystore-records
(let [id (<! (identity/from-secret {:secret secret :app-salt salt :name "chat"}))
[k1 k2] (identity/keystore-records id)]
(is (= identity/keystore-label (:id k1)) "the identity key is filed under the label OrbitDB is asked for")
(is (= (:orbit-id id) (:id k2)) "the signing key is filed under the identity's id, where OrbitDB looks it up")
(doseq [k [k1 k2]]
(is (= 64 (bytes/byte-length (:private-key k))) "OrbitDB's raw Ed25519 form: seed ‖ public key"))
(is (= (bytes/b64url->b64 (:id-seed id)) (bytes/slice-b64 (:private-key k1) 0 32)))
(is (= (bytes/b64url->b64 (:id-public-key id)) (bytes/slice-b64 (:private-key k1) 32)))
(is (= (bytes/b64url->b64 (:sign-seed id)) (bytes/slice-b64 (:private-key k2) 0 32)))
(is (= (bytes/b64url->b64 (:sign-public-key id)) (bytes/slice-b64 (:private-key k2) 32)))))