aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/src/meshbay_cli/commands/browser_access.py
blob: e2b0b8ed727848ae2369091ec2fca13d3fa1dc11 (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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
`browser-access`: whether this machine leaves, on each node, a copy of its keys
a browser can open with the passphrase — the application's Profile → Browser
access, kept by this machine (docs/MESHBAY_DESIGN.md §3.7).

`on`: each group opened here leaves a copy sealed under the passphrase-derived
key, when its node holds none or an outdated one. `off`: the copy a node holds
is withdrawn. Never set: nothing is written or withdrawn, so a CLI nobody
configured never undoes what the application of another computer does.

Set here and nowhere else. The hub keeps a mirror of it, written here as the
application writes it, but a mirror anyone with a hub session can write must
never make this machine upload keys: read, it only produces a message.
"""

import json

from ..client.hub import HubError
from ..errors import AUTH, CliError
from ..output import err, sentence
from .context import Context

HELP = "whether a browser may open your groups: leave a copy of your keys on nodes, or not"

EFFECT = {
    "on": "Each group opened here from now on leaves a copy of your keys on its node, "
          "sealed under your passphrase, so that a browser can open it.",
    "off": "Each group opened here from now on withdraws the copy of your keys its node "
           "holds; a browser will no longer open it with your passphrase.",
}


def add_parser(sub, parent) -> None:
    p = sub.add_parser("browser-access", parents=[parent], help=HELP,
                       description=sentence(HELP) + ". As the application's Browser "
                       "access, for this machine. With no argument, shows the setting.")
    p.add_argument("state", nargs="?", choices=("on", "off"))


async def run(ctx: Context) -> int:
    a = ctx.args
    account = ctx.account()
    if not account.remembered:
        raise CliError(AUTH, "This setting is kept with the saved session; run "
                             "`meshbay-cli login` first.")
    if a.state is None:
        try:
            mirror = (await account.call(account.hub.preferences)).get("browser_access")
        except (HubError, CliError):
            mirror = None
        mine = account.browser_access
        if a.json:
            print(json.dumps({"this_machine": mine, "hub": mirror}))
        else:
            print(f"This machine: {mine or 'not set (leaves the nodes as they are)'}")
            print(f"The hub's copy: {mirror or 'none'} (informative: it sets nothing here)")
        return 0

    def put(state: dict, secrets: dict) -> None:
        state["browser_access"] = a.state
    await account.update(put)
    try:
        await account.call(account.hub.set_preference, "browser_access", a.state)
    except (HubError, CliError) as e:
        err(f"meshbay-cli: warning: the hub's copy of the setting was not updated "
            f"({getattr(e, 'detail', None) or getattr(e, 'message', e)}); a browser may "
            "explain a closed group less well.")
    if a.json:
        print(json.dumps({"this_machine": a.state}))
    else:
        print(f"Browser access: {a.state}. {EFFECT[a.state]}")
    return 0