aboutsummaryrefslogtreecommitdiffstats
path: root/docs/USERGUIDE.md
blob: afe63fd51affa03b02ce642ea1d9630553f14d33 (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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
# MeshBay — User Guide

This guide is for people who **use** MeshBay and for people who **run** a node.

If you have not installed anything yet, start with
[`QUICKSTART.md`](QUICKSTART.md) and come back here.

**Contents**

1. [What MeshBay is](#1-what-meshbay-is)
2. [Your account](#2-your-account)
3. [Your devices](#3-your-devices)
4. [Joining a group](#4-joining-a-group)
5. [Using a group](#5-using-a-group)
6. [Running a node](#6-running-a-node)
7. [Managing people](#7-managing-people)
8. [What is private, and what is not](#8-what-is-private-and-what-is-not)
9. [When something breaks](#9-when-something-breaks)
10. [Reference](#10-reference)
11. [Running your own hub](#11-running-your-own-hub)
12. [What this software does not do yet](#12-what-this-software-does-not-do-yet)

---

## 1. What MeshBay is

MeshBay gives a small group of people — a family, a household, a few friends —
private access to files that live on **somebody's own machine**, with
applications over them: a chat, a file explorer, a video library, a music
player, a photo album.

It is not a public file-sharing network and it is not a cloud. Nothing is
uploaded to a company. The files stay where they already are.

### The three parts

**The hub** (meshbay.org, or one you run) holds accounts and the list of
groups, and introduces two machines to each other. Under a kilobyte of
connection setup passes through it. For a private group — the default, and what
this guide assumes — it never sees a file, a message, a file name or a key. §8
says exactly where that stops.

**The node** is a daemon on the machine that holds the files. It holds the
group's encryption key, and it is the only thing that decides who gets served.
Not the hub — the node. If the hub invented an account and put it in your
group, the node would still refuse it.

**The client** is either the web application the hub serves, or the desktop
application you install. Both are the same interface.

### The one idea that explains the rest

> **Everything about a group lives on the machine that hosts it.**

The files, the list of them, who has been let in, invitations, chat history,
which folders allow uploads, how each application is set up — all of it on that
machine. The hub keeps accounts, group names and who belongs to what, and
nothing more.

That is why the person running the group sends you the invitation code rather
than the website. It is why a hub having a bad day loses nothing. And it is why
there is no "I forgot my group" button to press.

### What a group is

A group is **people + directories + applications**.

```
  A group's contents, as members see it
  ─────────────────────────────────────
  /
  ├── Films/         →  /mnt/library/films         on the operator's machine
  ├── Music/         →  /mnt/audio                 an external drive
  └── Documents/     →  /home/them/share           read-write: members may upload
```

Each of those is a **root** — a named directory. Members see the names; they
never see, and never name, a path on the operator's disk.

---

## 2. Your account

Your account lives on a hub. It is a username, an email address, and a
passphrase — and the passphrase is the part worth understanding.

### Your passphrase is not a password

It never reaches the hub. Your browser turns it into two separate values: one
that proves who you are to the hub, and one that encrypts **your identity keys**
where they are stored — on each node you have joined.

Two consequences:

- **The hub can reset your sign-in. Nobody can reset your keys.** A hub
  operator, a node operator and the authors of this software are all equally
  unable to open your keys. There is no back door, no support ticket, no
  recovery from a database.
- **A good passphrase is worth more here than anywhere else.** Twelve
  characters is the minimum the sign-up page accepts; four unrelated words is
  the shape that really protects you. The locked copy of your keys on each
  machine you join is only as strong as what locks it.

### Your recovery key

Shown **once**, at sign-up. It is a long random secret rendered as words. Put it
in a password manager.

What it is for: a second, recovery-encrypted copy of your identity is stored on
each node beside the passphrase-encrypted one. With the recovery key, a
passphrase reset also restores your access to your groups. Without it, a reset
restores your sign-in only, and every group has to be rejoined by hand with a
fresh code from its operator.

If you missed it at sign-up, or you signed in from a new browser: **Settings →
Recovery key → Enter recovery key** adds the backup copies to every group whose
node is reachable.

### Forgetting your passphrase

**Sign-in → "Forgot your passphrase?"** You need your username **and** the
email address on the account — the page says the same thing either way, so if
no code arrives, one of the two did not match.

A code arrives by email. Enter it with a new passphrase, and your recovery key
if you have one.

A reset also signs out every device that had been signing in by itself, so each
one asks for your passphrase once more. That is on purpose: if you are
resetting because something may have gone astray, a laptop that still lets
itself in is the thing you want stopped.

### Changing a passphrase you still know

**Settings → Passphrase → Change passphrase.**

Your keys are re-encrypted on every group whose node is online **before**
anything changes on the hub — so if it fails half way, nothing has changed.
Groups whose nodes were offline are listed by name afterwards; for each one,
ask its operator to unpin you and send a fresh code.

### Deleting your account

**Settings → Delete account.** It removes your account, memberships and
notifications from the hub, and frees your username.

What it cannot reach is anything sitting on other people's machines: files you
uploaded stay where their operator keeps them, and each node remembers you
until its operator says otherwise. Connection logs are kept for a year, as the
law requires.

---

## 3. Your devices

You can use one account from several devices — a laptop browser, a phone, the
desktop application. Each one gets **its own key on each machine you join** —
they are not copies of one key, and the key you hold on one person's machine
means nothing on another's.

### Adding a device

The first time a new browser opens a group, it says *"This browser is not
linked to this node yet"* and offers a code. You then approve it **from a
device that is already linked** — Members tab → *"Linking a new device? Enter
the code it is showing."*

No operator is involved and the code never passes through the hub — one of
your own devices vouches for the new one, which is what stops anybody else
adding a device to your account.

A few limits: **five devices per account on each machine**, a code lasts an
hour, and five wrong codes in a row stop the attempt.

### Removing a device

**Settings** on the node's group, or the Members tab: *Remove*. It loses access
to that node until it is linked again. Removing a device also moves the chat
key on, so it cannot read anything written from then on.

### One passphrase, several browsers

A second browser on a machine you have already joined picks up the *same*
identity: it asks for your passphrase, unlocks the copy of your keys kept
there, and you are in. No second code, nobody to ask — which is another reason
the passphrase is worth choosing well.

### The desktop application

Worth installing if you use MeshBay more than occasionally:

| | Browser | Desktop application |
|---|---|---|
| Install | none | a package |
| Interface comes from | the hub, on every visit | inside the package, from disk |
| Keys | in the browser, plus a copy on each node | in the OS keyring, never bundled anywhere |
| Downloads | to disk where the browser allows it | native, streamed, no size limit |
| Casting to a TV | — | yes |

The difference that matters: a browser fetches its code from the hub every time
you open it, while the application carries its own and never asks the hub for
any. So the application is the one to prefer for anything you care about. The
browser stays, and is a perfectly reasonable way to use MeshBay — being able to
open a group on someone else's laptop with nothing installed is worth having.

---

## 4. Joining a group

Someone who runs a node invites you. You need an account on the same hub first.

1. **They send you a code** — eight characters like `K7P2-9WQX`, by message,
   mail, or read out loud. It is good for 7 days by default, works once, and
   only for your account in that one group.
2. **You sign in**, and the group is already in your sidebar.
3. **You open it.** It says *"This node needs to recognise you"*. Paste the
   code.
4. Done — the machine hosting the group recognises you from now on, and the
   files appear.

You will not be asked again on that browser, or on that machine.

### Joining with a link

The person running the group can send you a **link** instead of a code — the
way in when you have no account yet.

1. **Open the link.** It says *"You have been invited"*.
2. **Create an account** with the e-mail address the invitation was sent to —
   exactly that address — or sign in if you already have one. Confirm your
   address with the code the hub mails you, then sign in.
3. You are brought back to the invitation: *"… invites you to join …"*.
   **Join.**
4. The group opens, and you type no code: the link carried it.

The link works once, and only for the account registered with that address; to
anyone else it says it was sent to another address. In the desktop
application, paste the link into **Join with an invitation link** on the home
page.

**The code never passes through the hub** — unless whoever invited you asked
the hub to mail it to you — and that is the whole reason it exists: it proves
the invitation came from the person running the group, and not from the
service in the middle.

### Leaving

Group menu → **Leave group**. You lose access to its files and chat. Anything
you uploaded stays on the machine hosting the group, which also remembers you
until its operator says otherwise.

---

## 5. Using a group

A group is a set of tabs. Which ones you see is the operator's choice; **Files**
and **Settings** are always there.

### Files

The explorer. Roots are the top-level folders; below that it behaves like any
file browser — sort, select, download, preview.

- **Upload** appears only where the current folder is in a **read-write** root.
  You can also drag files and whole folders onto the file list.
- **A drop is decided before anything is sent.** A name already in the folder,
  or a name the node cannot store, cancels the whole drop and tells you which
  name caused it — so you never end up with half a copy.
- **Download a folder as a zip**, built in your browser from the same encrypted
  chunks as any other download. The node never compresses anything.
- **Delete** — you can remove a file you uploaded yourself; anything else is
  the operator's to remove. A folder has to be empty first, so nothing here can
  sweep away files you cannot see.
- **Right-click a file or folder** for the same actions as the toolbar, listing
  only the ones that apply to it. On a ticked row the menu acts on everything
  ticked, like the toolbar does.

### Chat

Per-group messages, always encrypted, with threads, attachments and link
previews.

- **Attachments** need a read-write folder in the group. Where there is none,
  the paperclip is off and says so.
- **Link previews** are fetched **by the node** — the machine hosting the group
  makes a request to whatever site somebody linked. The operator can turn it
  off.
- **History is kept on the node**, and stays readable to members. A member
  removed from the group cannot read anything written after their removal.
- Sometimes a message reads *"Written before this device could read this
  conversation"* — that is a device added later, not an error. A message marked
  *"the signature does not match the sender"* is different and worth asking
  about.

### Videos

A poster browser over the folders the operator chose for it. Two modes: a
poster grid with artwork and summaries, and a plain folder-driven list that
needs no third-party service at all.

- **Nothing appears until the operator chooses at least one folder** — the tab
  tells you so, rather than just looking empty.
- Films and shows are **one card each**, not one per file; a show expands into
  seasons and episodes.
- The operator can **correct a wrong match**, and the correction applies to the
  whole show rather than one episode.
- Streaming has **seeking, audio-track selection and subtitles**. Picture-based
  subtitle tracks (the ones stored as images rather than text) are not offered:
  they would need text recognition to display, so they are left out rather than
  listed and blank.
- A library is read **a page at a time**; the page size is your own preference
  in Settings, not the group's.

### Music

An album browser and a player, over the folders the operator chose for it.

- Tags in your files come first, then folder and filename, then a lookup for
  cover art or canonical spelling.
- **The player survives leaving the tab** — go to Files, go to another group,
  the music keeps playing.
- **Playlists are yours, not the group's**, and follow you across groups and
  devices. Favourites, queues saved as playlists, drag to reorder.

### Photos

An album browser over the folders the operator chose for it, where **an album
is a folder**. Thumbnails come from the node, already rotated correctly.

**Location data is never shown.** Photos shows when a picture was taken and
what took it, and no coordinates anywhere. Worth knowing, though: the
coordinates are still inside the photo itself, as your phone wrote them, so
anyone who downloads the original file has them. Strip them before sharing if
that matters to you.

### Search

The magnifying glass in the sidebar searches **across every group you are in**
at once, with a Files / Videos / Music / Photos view each.

A file that two groups both have is **one result**, not two — identity is the
content, not the path. Each result says which group it came from, or how many.

An operator can keep a group out of Search. It is a tidiness setting and
protects nothing: members still see everything by opening the group.

### Transfers

The transfers panel shows what is moving. Downloads queue, run, pause and
resume.

- The node runs a limited number at once, and each member has their own share
  so nobody can take the machine. Queued transfers say what they are waiting
  for.
- **Pausing needs a download folder** chosen in Settings → Downloads. Without
  one, your browser decides where files go and a transfer cannot be resumed.
- **Browsing is never queued.** Posters, thumbnails, opening a photo or a
  document to look at it — none of it takes a transfer slot. A busy group
  browses exactly like an idle one.

### Casting to a TV

**Desktop application only.** A film playing in the application can be sent to a
cast-capable TV or dongle on the same network: *Cast to device* in the player,
pick one from the list.

The application decrypts the film and relays it to the TV itself, over your LAN.
The TV is not a group member and holds no key — which is also why the relay's
ports have to be reachable on the local network (§10).

Subtitles travel with it. Other TV protocols — the UPnP/DLNA family — are
designed and not built.

### Notifications and settings worth knowing

**Settings → Downloads** — save automatically to a folder, or ask every time.
**Settings → Defaults** — which tab a group opens on, how many items per page.
**Settings → Appearance** — theme and language (ten languages ship).
**Group menu → Mute** — stop notifications for one group.

---

## 6. Running a node

This section is for the person whose machine holds the files.

### What you decide

Your node, not the hub, decides who gets served and what gets served — from a
list you build yourself with invitation codes. Two things follow from that:

- The hub can tell somebody your group exists and point them at your machine,
  but it cannot get them let in. Only your invitation does that.
- **Your own browser counts as a stranger until you pair it**
  (`meshbay-node operator pair`). Until then it cannot invite anyone or delete
  anything — which is a little surprising the first time, and is what keeps the
  decision yours.

### Two ways in

| | |
|---|---|
| **The CLI**, over SSH | no browser needed, and it works while the daemon is stopped |
| **A paired browser** | the group's Settings and Members tabs, and the Node page in the desktop application |

On a headless server the CLI is the only path, and it covers everything you
need to run a group. One gap is known: removing **one** device of one member is
only doable from the interface (§7). Start with:

```bash
meshbay-node status
```

It reports what is configured, what is running, and — when something is
missing — the command that fixes it.

### Directories (roots)

A group's content is a set of **named directories**. The name members see is
the directory's own basename, fixed when you add it.

```bash
meshbay-node root list
meshbay-node root add /mnt/library/films --name Films
meshbay-node root add /mnt/usb/archive --removable
meshbay-node root set Films --writable
meshbay-node root remove Films
```

Rules that will bite you if you do not know them:

- **Two roots cannot share a basename**, even on different drives. `/mnt/a/Films`
  and `/mnt/b/Films` is refused; name one of them explicitly.
- **No root inside another.** The same bytes would be indexed twice under two
  identities.
- **Renaming a root rewrites every path under it**, so it is an explicit act,
  not a cosmetic one.
- The first directory of a new group is **read-write**; every root added later
  is **read-only** unless you say otherwise.

### Read-only and read-write

A read-only directory is read-only **for everybody, including you**. That is
intentional: a library you have published as read-only should stay as you
arranged it, and an accidental drag-and-drop from your own browser is as
unwelcome as anyone else's.

Whether uploads are allowed is decided per directory and nowhere else. A group
can have several directories open for uploads, or none at all — a group nobody
can add to is a perfectly normal thing to want.

### External drives

Mark a root `--removable` and you get **Eject** and **Plug in** beside it.

Eject before you unplug. It stops watching that directory and freezes its files
in the index — they stay listed and are reported as unavailable, rather than
looking to every member as though you deleted your library. Plug in checks the
path is really back, then rescans.

If a removable root's path disappears without an eject, the node ejects it for
you. Nothing is deleted: index entries, thumbnails, metadata and chat history
referring to those files all survive.

Remember the systemd drop-in for anything outside your home directory — both
`ReadWritePaths` and `RequiresMountsFor`. It is in
[`QUICKSTART.md` Step 5](QUICKSTART.md#step-5--start-the-node).

### Indexing

The node watches its directories and re-checks them periodically — the periodic
pass is not a backstop, it is required, because filesystem events are dropped
under load and are unreliable on network and FUSE mounts.

Files over 40 MB are identified by reading their beginning, end and middle
rather than the whole file. A 4 TB library does not need 4 TB of reading to be
catalogued.

Group → Settings has the re-check interval and how long the node waits after a
file changes before indexing it. Members see indexing progress while it runs.

One thing that surprises people: **two identical files in one group are one
entry**, because a file is identified by its content. A scan that reports ten
files and indexes nine has not lost anything.

### Applications and their folders

Group → **Members → Applications** turns applications on and off for everyone.
Files and Settings always stay.

Group → **Settings** points each application at folders:

- **Videos**, **Music** and **Photos** — as many folders as you like for each.
  A library is rarely in one place, so pick every folder that belongs to it and
  leave out the rest. Each tab stays empty until at least one is chosen.
- **Chat** — one folder, for attachments. It has to be one members can write
  to.

This is not a personal view: it decides what **everyone** in the group sees in
that tab. The change is signed by your paired browser and reaches connected
members straight away.

### Metadata from third parties

**Videos** uses a film and TV database for posters, summaries and cast. It ships
with a default credential and you can set your own; the language is a
group-wide setting, because there is one shared cache rather than a request per
viewer. Turn it off and Videos falls back to thumbnails and cleaned filenames,
with no outside request at all.

**Music** uses a music database for cover art and canonical spelling when a
track carries none. It needs no credential.

Both lookups are made **by the node**, once per title, for everybody. Your
members' devices never talk to a third party.

### Node settings

Group Settings covers a group; **Node settings** covers the machine. From the
desktop application's Node page, or by editing `~/.config/meshbay/node.toml`
and running `meshbay-node reload`:

| Setting | Default | What it decides |
|---|---|---|
| `invite_ttl_hours` | 168 (7 days) | how long an invitation stays usable |
| `pair_ttl_hours` | 24 | how long an operator pairing code lasts |
| `device_request_ttl_minutes` | 60 | how long a device request waits for approval |
| `max_concurrent_streams` | 8 | how many people can watch video at once |
| `max_concurrent_downloads` | 8 | node-wide download slots |
| `max_concurrent_uploads` | 8 | node-wide upload slots |
| `max_upload_gb` | 8 | the largest single file a member may send you |
| `transcode_incompatible_video` | true | re-encode video no browser can play |
| `hardware_video_encode` | true | use the GPU for that, if one actually works |

`max_concurrent_streams` is the one to think about: a stream costs a video
process for as long as the film lasts, so this counts **viewers**, not
requests.

`max_upload_gb` is the only one of these about your disk rather than this
machine's work. Fractions are allowed — `0.5` is 512 MB — and the new ceiling
applies to an upload already in progress, so raising it unblocks a file that
was about to be refused. There is no total quota behind it: a member who can
write to a folder can still fill the disk one capped file at a time.

Turning transcoding off does two different things depending on the video: one
your viewers' browsers can decode by themselves plays as it is, and one they
cannot is refused with a message pointing at this setting.

Changes are saved to the database for immediate effect **and** written back
into `node.toml` so they survive a reinstall. Your hand-written comments in
that file are left alone.

---

## 7. Managing people

### Inviting

```bash
meshbay-node member invite alice_dupont
```

Or the group's **Members** tab, from a paired browser.

They need an account on the same hub first. The invitation registers their
membership on the hub and produces a code that never goes near it. Send the
code out of band; they enter it the first time they open the group. You do not
need to be online then.

**Inviting someone who has no account yet** is the **Invite by link** box, under
the first one: type their e-mail address and **Create link**. Send them the
link, or leave **Send the invitation by e-mail** ticked and the hub mails it.
They register with that address and land in the group without typing a code.
The link works once and only for an account with that address, so a copy that
travels further — a forwarded mail, a chat — lets nobody else in. Pending links
are listed under the box, and **Cancel** takes one back. A hub mails at most ten
links a day for one account (an administrator can change that).

The Members tab offers **Send the invitation by e-mail**, ticked by default: the
hub mails the code to the address on their account, so nobody has to copy it.
That is a trade: **the hub then holds the code**, and a hub that wanted to could
use it to join in their place. For a group where that matters, untick it and
send the code yourself — the box remembers your choice. The CLI never mails
anything.

### Seeing who is in

```bash
meshbay-node member list
```

Names, roles, when each identity was pinned and how, plus any pending
invitations.

### Removing someone

```bash
meshbay-node member revoke alice_dupont
meshbay-node gek rotate --group "Family Photos"
```

**Both lines, and the second one matters.** Revoking means the node stops
handing them the group key on their next connection. It does not take back the
key they already have — no protocol can. Rotating replaces it: every member
still in the group gets the new one automatically, and the person you removed
keeps the old one, which opens nothing written from now on.

Anything they already downloaded stays theirs. Once a file has been copied, no
software can reach back and take it away.

Or the group's **Members** tab, from a paired browser: *Remove*. It does both
halves — the node stops serving them, and the hub stops letting them reach it.

**Somebody you invited by mistake** is removed the same way, from either, and
it also cancels the code you sent them: until it is redeemed there is no
membership yet, only an invitation, and taking one back has to take back the
other. Nothing to rotate in that case — they never had the key, and neither
the command nor the interface will tell you to.

If you mistype the username, `member revoke` says so rather than quietly doing
nothing.

### Unpinning, and when to use it

```bash
meshbay-node member unpin alice_dupont
```

This forgets **every device** of theirs on this node, so they can pair again
with a new key. It is the fix for two specific situations:

- Someone lost their passphrase and had no recovery key. Unpin, then send a new
  invitation code.
- Someone changed their passphrase while your node was offline, and their group
  is now unreadable to them.

### Devices

A member's devices are managed **from the interface, not from the CLI** — their
own *Your devices on this node* list, or your group's Members tab from a paired
browser. A removed device is remembered as removed, so the same key cannot
quietly reappear later.

`meshbay-node member unpin <user>` is the CLI's blunt version: it removes
**every** device that person has on this node, and they pair again from scratch.
There is no per-device CLI verb today — noted in
[`MESHBAY_DESIGN.md` §15.3](MESHBAY_DESIGN.md#153-open-and-why-each-is-where-it-is).

### Rotating the group key

```bash
meshbay-node gek rotate --group "Family Photos"
```

Connected members get the new key with no action on their part. Anyone revoked
keeps the old one and loses everything from that point on. Nothing already
downloaded is affected.

### The audit log

Every admission, refusal, invitation and deletion is recorded on the node. The
desktop application's Node page shows it and exports it as CSV.

---

## 8. What is private, and what is not

**The short version: your files stay on the machine that hosts them.** They
travel encrypted and directly to the people that machine has been told to
serve. The hub that introduced everybody never holds them, and cannot read
them.

For most people that is the whole answer. The rest of this section is for
deciding what belongs in a group and what is better kept elsewhere.

### What you can rely on

- **Nothing goes through the hub** — not your files, not their names, not even
  the list of them. Your devices talk to the node directly.
- **The hub cannot open your group.** It holds none of the keys, and for a
  private group it does not know what is in it.
- **The hub cannot let anybody in.** Only the node decides who it serves, from
  the list its operator built with invitation codes. An account the hub added by
  itself gets nowhere.
- **Only your own devices can add another of your devices.** The hub cannot,
  and neither can an operator.
- **You get separate keys in each group you join**, so two people hosting you
  cannot work out that you are the same person.
- **Chat history is encrypted where it is stored.**
- **Your client remembers each node** and refuses one whose identity has
  changed — which is what stops a machine being quietly swapped for another.
- **People you have already seen in a group stay checked** every time they post
  after that.

### Worth knowing before you share something

- **Whoever hosts a group can read what is in it.** The files sit on their
  machine in the ordinary way, because that is what hosting is. It is the same
  trust you extend to a friend keeping a spare key to your flat — reasonable,
  and worth being conscious of.
- **Everyone in a group sees everything in it.** There is nothing below group
  level: no per-person permissions, no private corner inside a shared library.
  If two sets of people should not see the same things, make two groups.
- **The desktop application protects you a little better than a browser.** A
  browser downloads its code from the hub every time you open it; the
  application carries its own and never asks the hub for any. For anything you
  would rather not stake on the hub behaving, prefer the application.
- **Your passphrase is what guards your keys.** A copy of them, locked with it,
  sits on each machine you have joined. A long one puts that out of reach; a
  guessable one does not. This is the single thing most worth getting right.
- **An open group is open.** Anybody can walk into one, which is what open
  means. Invite-only is the default, and is what you want for anything personal.
- **The hub sees who is in which group, and when.** Never what was said or
  shared — but the pattern of it is visible to whoever runs the hub.
- **Deleting your account does not delete what you shared.** Files you uploaded
  stay on the machines hosting them, and each node remembers you until its
  operator says otherwise. Ask them if it matters.

## 9. When something breaks

### Start here

```bash
meshbay-node status
journalctl --user -u meshbay-node -f
```

`status` works whether or not the daemon is running, and names the command for
anything missing.

### The common ones

**"No nodes are currently online for this group."**
The node is not running, is not reachable, or has not linked its key to the
hub. On the node: `meshbay-node status`, then Step 4 and 5 of the quickstart.

**A member sees the group but no files.**
They never redeemed an invitation code, or the group has no key
(`meshbay-node gek init`), or nothing has been indexed yet.

**Members on other networks connect, members on your own LAN do not.**
The firewall. A browser on your LAN has to be able to call the node, and a node
refusing unsolicited inbound UDP cannot be called. See
[`QUICKSTART.md` Step 9](QUICKSTART.md#step-9--let-people-reach-you).

**A shared directory reads as empty and everything else looks right.**
A mount the service cannot see. The systemd drop-in needs
`RequiresMountsFor` as well as `ReadWritePaths` — the service has its own mount
namespace, so a volume mounted after it started is invisible to it.

**"Invitations are signed with the key this node pinned for your browser."**
The browser is not paired. `meshbay-node operator pair`, then enter the code in
the Members tab.

**A member changed their passphrase while the node was down.**
`meshbay-node member unpin <user>`, then a fresh invitation code.

**Video says the codec is not supported.**
The source codec has no decoder in that browser and transcoding is off, or
ffmpeg is missing. Check `transcode_incompatible_video` and that ffmpeg is
installed.

**"Server busy" when starting a film.**
Every streaming slot is taken. `max_concurrent_streams` counts viewers, and
each one holds a slot for the whole film.

**A download stops near the end in the browser.**
Choose a download folder in Settings → Downloads, which switches the browser to
writing straight to disk, and retry. The desktop application does not have this
class of problem.

**Nothing appears in Videos, Music or Photos.**
No folders have been chosen for that application yet. Group → Settings. The tab
says so rather than just looking empty, but it is easy to miss.

### After changing config by hand

```bash
meshbay-node reload          # re-read node.toml without dropping anyone
meshbay-node restart-daemon  # full restart — drops live streams
```

Prefer `reload`. A restart kills every connection, which for someone watching a
film looks like a failure they caused.

---

## 10. Reference

### Node commands

```
meshbay-node status                          what is configured and running
meshbay-node init                            first-time setup
meshbay-node reset                           erase all node state (destructive)

meshbay-node group list|add|remove           groups this node hosts
meshbay-node root list|add|remove|set        directories in a group
meshbay-node root eject|plug                 removable drives
meshbay-node gek init|rotate                 the group's encryption key

meshbay-node operator pair                   authorise a browser
meshbay-node member list|invite|revoke|unpin people

meshbay-node file list|rm                    files, from the machine itself
meshbay-node chat status|rotate|encrypt-history|prune
meshbay-node transfers show|set|max-size|per-member
                                             transfer limits, and the
                                             largest single upload
meshbay-node denylist show|clear
meshbay-node stun list|add|remove|reset      NAT traversal servers
meshbay-node video rematch                   re-resolve video metadata

meshbay-node reload                          re-read node.toml, hot
meshbay-node restart-daemon                  full restart
```

`--group <name>` selects a group where you host more than one. `--yes` skips
the confirmation on destructive commands. `man meshbay-node` has the full page.

### Where things live

| | |
|---|---|
| `~/.config/meshbay/node.toml` | configuration — hand-edited, commented, preserved |
| `~/.config/meshbay/node.env` | environment: keystore unlock, third-party tokens |
| `~/.config/meshbay/keystore.enc` | the node's own keys. **Back this up.** |
| `~/.config/meshbay/unlock.key` | what opens the keystore. Mode 0600. |
| `~/.local/share/meshbay/` | roster, indexes, chat, caches, thumbnails |
| `/opt/meshbay-common/venv/` | the shared Python environment |

Losing the keystore means a new node identity: every group has to be re-linked
and every member re-admitted. It is small — back it up somewhere safe.

### Ports

| | |
|---|---|
| **inbound UDP, ephemeral** | peer connections. Scope the rule to your LAN. |
| **127.0.0.1:18000** | the node's own control API. Loopback only, behind a per-run token, never exposed. |
| **TCP 19550-19553, UDP 5353** | casting to a TV, desktop application only, LAN only |

### Defaults worth remembering

| | |
|---|---|
| Invitation code | 7 days, single use, one account, one group |
| Operator pairing code | 24 hours |
| Device linking code | 1 hour |
| Devices per account per node | 5 |
| Upload size limit | 8 GB per file, settable on the node |
| Transfers at once | 8 node-wide, 2 per member per group |
| Video streams at once | 8 |

---

## 11. Running your own hub

You do not need to. meshbay.org exists, is free, and sees nothing of your
content. Run your own if you want nobody else holding your account list, or you
want a hub that is not reachable from the internet at all.

A hub is a Linux server with PostgreSQL, a reverse proxy for HTTPS, and
somewhere to send mail from. The steps are in:

- [`PACKAGING-GUIDE.md`](PACKAGING-GUIDE.md) — install, database, configuration, first start
- [`HTTPS.md`](HTTPS.md) — the reverse proxy and certificates
- [`MAIL-SERVER.md`](MAIL-SERVER.md) — outgoing mail, which sign-up and recovery need

Two things to know before you start. **Your hub serves the web application**,
so anyone using a browser against it is trusting you with their keys — the
same relationship you have with meshbay.org, pointed at you. And **a hub cannot
be moved**: accounts, group registrations and node links are all on it.

---

## 12. What this software does not do yet

Better to know now than to go looking for it:

- **Packages are not signed**, and there is no signed repository yet, so there
  is nothing to check a download against and no updates through your
  distribution. Until that ships, take them from the download page and from
  nowhere else.
- **There is no Android client.** A phone browser works.
- **A node cannot be hosted on Android**, and is not planned to be.
- **Hubs do not talk to each other yet.** Everyone in a group needs an account
  on the same hub.
- **Casting reaches Chromecast devices** from the desktop application. Support
  for other TV protocols is designed but not built.
- **Some subtitle tracks cannot be shown** — the ones stored as images rather
  than text, roughly one embedded track in five. Displaying them would need
  text recognition.
- **There is no overall storage quota.** Files are capped at 8 GB each — lower
  or raise it on the node, above — but somebody can still fill a disk one file
  at a time. Worth a glance now and then if you have opened a folder to people
  you do not know well.
- **Searching the film database by hand has no per-member limit**, and it draws
  on the node's own quota. Only likely to matter on a large group.
- **The record of who uploaded what belongs to the node.** It is kept and it is
  accurate, but other members have no way to check it for themselves.
- **Chat history stays readable to everyone in the group**, including people
  who join later. That is what makes it a shared history rather than
  disappearing messages — but if a conversation should leave no trace, it does
  not belong here.
- **Your client remembers each node's identity, but not the hub's.** It matters
  less than it sounds: a stand-in hub still cannot read anything, and cannot
  touch the desktop application at all.