aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_identity_seam.py
blob: 15db6d84ccde08e38a172c86dbda02e2d3b872d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
"""
Nothing in the interface reads an identity private key except the identity.

The transport sees an identity on a node as two public keys, a signature and an
X25519 agreement (`transport.js`, `_identityFromKeys`). In a browser that object
wraps keys held in the page; in the desktop application the keys stay in the
main process and the same object asks it to sign. That only holds if no other
code reaches past the object for a key — which is what every admin op, device
link, chat message and app used to do, twenty times over, and is what this
test refuses.
"""

import re

from spa_source import STATIC

# Where a private key may be named: minted and sealed (keyderive.js), wrapped
# into an identity (transport.js), re-sealed during a passphrase change in a
# browser (transport-rewrap.js).
ALLOWED = {"keyderive.js", "transport.js", "transport-rewrap.js"}


def test_only_the_identity_touches_a_private_key():
    offenders = []
    for path in STATIC.glob("*.js"):
        if path.name in ALLOWED:
            continue
        text = path.read_text(encoding="utf-8")
        if re.search(r"skEdB64|skXB64|sessionKeys|signBytes\(", text):
            offenders.append(path.name)
    assert not offenders, f"these read a private key directly: {offenders}"


def test_in_the_transport_only_the_identity_factory_signs_with_a_raw_key():
    text = (STATIC / "transport.js").read_text(encoding="utf-8")
    factory = text[text.index("async function _identityFromKeys"):]
    factory = factory[:factory.index("\n}\n")]
    rest = text.replace(factory, "")
    assert "signBytes(" in factory
    assert "signBytes(" not in rest, "the transport signs with a raw key outside the identity"
    assert "skXB64" not in rest.replace("id.skXB64", ""), \
        "the transport reads the X25519 private key outside the identity"


def test_a_group_key_is_unwrapped_through_the_identity():
    crypto = (STATIC / "crypto.js").read_text(encoding="utf-8")
    unwrap = crypto[crypto.index("async function unwrapGEK"):]
    unwrap = unwrap[:unwrap.index("\n}\n")]
    assert "shared(pkEphRaw)" in unwrap and "pkcs8" not in unwrap