Update 'ToxMultiDevice'

emdee 2022-09-30 18:36:02 +02:00
parent a5fbf89ac7
commit e6a15a6469
1 changed files with 305 additions and 0 deletions

305
ToxMultiDevice.md Normal file

@ -0,0 +1,305 @@
# Toxcore Multi-Device Support Design Proposal
<https://docs.google.com/document/d/1op6zGR0KYdF7tTWSSX79KQieJu30vLZ6XG327kIBhxQ/>
To be a useable communication system, Tox needs to support multiple devices per user.
## Objective
This proposal is an RFC for a possible implementation of multi-device
support for the Toxcore Messenger system. With the goal of replacing
Skype we must come close to feature parity, as well as ease of
use. Currently Tox clients need to share a ToxID. This ID inhibits
connecting with existing friends as it is only well-suited to machine
reading.
The primary goal is to make it simple for clients to securely implement multi-device support, without having to know or manage anything about a contacts devices.
The following implementation requires some additional features to be
added to Toxcore. These features have been requested before; however,
the goal of this implementation is to add Multi-Device support
only. The additional APIs that would be required (see next section)
would only need to be minimal implementations to get multi-device
working. And while their feature set should be expanded, thats not
the goal of this implementation.
## Background
ToxIDs are difficult to share without having an existing textual
communication connection (anything you can copy from or paste
to). Sharing ToxIDs in other ways is problematic.
When it comes to multi-device support, at the present time we are
lagging behind well-known centralized messenger systems. A few
examples are Google Hangouts, Facebook Messenger, and Skype. Every one
of these syncs messages to every device which connects to their
network. If you need an address, number, or entire friend list its a
simple login away.
Not the goal of this project but an important benefit, Multi-Device support would solve some of the issues sharing a ToxID: it would allow the clients to connect with mobile devices (NFC, QR codes, other) and be available anywhere.
## Prerequisites
### Data Syncing (Friends and Messages):
Devices may go online and offline. Its required that an online device be able to keep other devices in the “device group” in sync, Updating both friends and messages.[a][^1][b][^2]
### Contact Syncing
Contacts (called friends in the Toxcore API) are synced across all
devices using a transactional method. As a pair the devices decide
which will have the primary role, and which will take
secondary. Throughout the entire syncing process, the primary device
will send its data, followed by a “done” packet. The secondary will
then send its data, followed by its own “done” packet. The primary
device will then send a “commit” packet, and will then commit the data
from temporary storage, into active use. Once receiving the “commit”
packet, the secondary device will do the same.
Either Client can send an Error packet at either time, which will then
Message ordering
Devices may sync out of order, but messages need to be consistently
ordered. To simplify this, messages will be separated into “connection
sessions”, each getting a pseudorandom tox_session_ID. Messages will
then be ordered within that session by a delta_t. Delta_t in this case
will be the elapsed seconds from the start of the tox instances first
current connection to that peer.
Each session will be identified by a pseudo-unique hash from the
previous connect that included a confirmed message receipt. This will
ensure that both sessions and messages are ordered correctly once each
client is completely synced. (Optionally robust verifiability can be
gained by a git style hash of the x parent sessions)
### Pseudo-unique Message IDs
#### Update
```
typedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, void *user_data);
```
with
```
typedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, uint64_t message_id, uint64_t delta_t, void *user_data);
```
Required for syncing messages between friends * devices. Each message
would include a message_id that would increment with each message. and
reset with each new tox_instance (starting message ID is currently
undecided). Messages id sections would have to be grouped by a client
coming online or going offline. These are per friend, per
connection. And would be the same when sending the same message to
multiple devices of a single friend.
Each of these are pending an implementation spec. But are self-evident
in their use and general implementation.
## Implementation
Security and safety is the primary concern, however this needs to be tempered with usability. The user needs to be prompted to choose high availability or high security.
### Device IDs
Device IDs need to be unique and never changing. On each connect, each client should query each friend they connect to, to verify if they support multi-device AND are in a group. This can be done by asking for the deviceID at ```__device0```. If there is a device at that address; then enumerate for each other device.
Devices will be found by the string_to_id service using the protected `__device[0-9]+` group. (Toxcore must protect strings that start with two underscores such as “__[string]”, and not allow a client to use them in the string_to_id API.)
Starting with ```__device0```, the client will attempt to resolve the
ToxID at each incrementing ```__device#```. Once a ```__device#```
returns empty, the client should stop. Each ```__device#``` string
should be queried separately, ideally in a pseudo-random order to
prevent clear text attacks on the encryption. {under discussion} For
each ToxID at each ```__device#``` the client must add them to their
list of devices for this friend/user, and probe each device in the
same way. The default should be high security mode, in which if any
list at any device do not match, toxcore should report that friend to
be in an unsecure state, and shouldnt send any messages to any of the
devices.
The ```__device#``` list for every client must match exactly to what every other device reports. And each ```__device#``` once used must always resolve to that ID.
To enhance security once a ```__device#``` (number) is taken by a
device, that ```__device#``` must always resolve to either the same
ToxID, or to all zeroes [0] if the device has been removed from the
Tox “group” by the user, in a case such as losing the private key, or
uninstalling the Tox client. Toxcore will maintain a local list of
each device for each user, changes to a ```__device#``` will be
assumed to be an impersonation attack. Removed devices will still keep
their ```__device#```, but that ```__device#``` will instead resolve
to zeros. A string of zeros signifies that there was a device, but it
was removed intentionally. A ```__device#``` once resolved to zeros,
must never change back to a ToxID.
To remove or add a device, you will tell toxcore to add the device at
ToxID to this group. That toxcore instance will then, try to connect
to that device and verify that it also wants to connect to the
existing device group. Once accepted, the toxcore instance on the
primary device will assign a ```__device#``` to the new device, and
sync both its ID, to the other devices already in the group, as well
as the existing devices to the new device. Once all the devices in the
group are in sync, any of the existing and online devices can sync the
friend/contact list, and the selected amount of history text history
to the new device.
A max limit of devices will need to be chosen later to limit worst case usage of enumerating devices. (Additional protocol requirements will be detailed later, i.a. security limitations, verifiable, master device, slave device, deauthed devices.)
## Message sending
When a client sends a message to a friend/user, Toxcore will only
attempt to send the message to the last 3 devices that sent data from
the user that are online.[c][^3][d][^4][e][^5] E.g., Device_A sends a
message, Device_B comes online, Device_C sends a file, Device_D sends
a message then goes off line, Device_F sends a picture, Device_H comes
online. Toxcore will attempt to send only to devices A, C and F. While
H did have the latest data sent/received, it wasnt data generated by
the user, so we assume that the user is most likely to be on one of
those 3 devices. Toxcore will only have to verify that one client
received the message, and may stop. This will protect the sender from
having to maintain a list of who needs what message, and leave the
additional data syncing up to the receiving client.
It is considered the job of the receiving client to keep all the other devices in sync with the rest of the group.
### Alternatives Considered
1. Not supporting multi-device (separate friends in the contact list for each device).
* Not considered, this feature is required to be competitive. Not user friendly, no syncing, too hard to create and maintain friend lists.
2. Sharing the private key of a single ToxID to multiple devices.
* Non starter. Security nightmare.
* Requires protocol rewrite.
3. [[]]
4. [[]]
### Unsolved Issues
How will messages be hashed to generate the seed for the message ID?
Effective and secure history syncing across devices.
How to add a user to your contact list
* By Primary ToxID[f][^6][g][^7]
* By any deviceID
* Something else?
## Roadmap
1. Unique message IDs
1. incrementing numbers
2. delta-from last
2. Device network
1. deviceID vs toxID
2. Adding a device
3. Removing a device
4. Sending a message to more than one device
3. Syncing data
1. contact list
2. messages
3. other?
## Notes & FAQ:
Conversations that need to be added to the spec:
```
<nurupo> say Alice has a tox client running on a phone and another tox client on pc. Alice has Bob in contacts. Bob is online and sends Alice a file.
<nurupo> will Alice see the file request on both clients?
<grayhatter> the file request will go to all online devices
<nurupo> ok, i'm not finished
<grayhatter> then the file will get canceled / "marked as accpeted on a different device"
<nurupo> so, Alice accepts and completes the file transfer on her phone
```
[h][^8][i][^9][j][^10]
```
<nurupo> hm
<nurupo> ok
<nurupo> i guess you answered what i wanted to know
<nurupo> what if race condition happends?
<grayhatter> but I hadn't considered that detail... It'll break the existing file transfer API...
<nurupo> Alice accepts files at the same time both on pc and phone?
<grayhatter> nurupo, can't happen
<nurupo> why it can't happen?
<grayhatter> the accept will processed by toxcore on the "sending" device in a single thread, it'll accept for the first device that accepts the transfer, then cancel all other divices
<grayhatter> if two devices accept at the same time, toxcore will choose the device in the lowest number slot only because the loop will start at 0
<nurupo> what if Alice accepts a file on another device before it gets the cancel message?
<grayhatter> it'll show inprogress on that device, with 0 transfer, then toxcore on the sending device will still send the cancel to that device
<nurupo> Bob will get two accepts from two devices of Alice?
<grayhatter> yes, but it will ignore the 2nd
<nurupo> how it knows which to ignore?
<grayhatter> (I'm saying all of this from what my plans are, I haven't even started on filetransfers yet)
<grayhatter> psudo code ->
<nurupo> Alice might have accepted the file transfer on the phone first, but because of network latency, Bob received the acceptance from pc first and only then from the phone
<grayhatter> OH
<grayhatter> bob will in that case cancel the phone then
```
[k][^11]
<nurupo> fair enough
<grayhatter> no reason to make it more complicated then it needs to be
```
### Feature requests:
(Requested publicly, no suggestions have been reviewed or accepted yet.)
* Per device id priority like with XMPP https://wiki.xmpp.org/web/Jabber_Resources
* Per status+deviceid priority, XMPP does that as well
* Ability to address device id explicitly
* [a][^1]Does this design document define a way in which friends (and perhaps groups) are to be synced? And how would friend/group syncing work across multi-devices that don't have a common time base?
* [b][^2] I haven't fully decided on the final spec for this question.
Currently my plan is to retain information about changes as a numerical delta, and use the largest delta. But as I haven't started on this section, really I have no idea.
* [c][^3]What about in the case of an A/V call? Does that get broadcast to call connected clients or only the last 3? A tox client running on a mobile device that had not sent a user-generated message missing a call would be bad.
* [d][^4]I'm likely to drop that idea in total.
Currently toxcore sends everything to all devices.
* [e][^5]With other services such as Discord, when a call comes in depending on what is on, I could have two PCs, a laptop and cellphone all ring, but whatever device I answer on obviously gets the call.
* [f][^6]how is primary toxID different from any other ID? which device is the primary one? as far as I understood they are all equal.
* [g][^7]I'm not sure there's going to be anything like a primary ID in the final source. When discussing it, the idea of a master device came up as a security tool. But the longer I consider it, the less I think it'll help at all
* [h][^8]Does it make sense to think about sending the file to both
clients, if the user accepts on multiple devices? Especially for
bigger files or multiple recipients a P2P protocol (e.g. torrent)
may be useful.
* [i][^9]Yeah, I've given that a little thought. The current idea
floating around has been to implement something torrent like inside
group chats. Maybe we could use that as well? As far as multiple
devices, what I think is best is transfer the file to the first to
accept, then let the other devices sync the file themselves. That
way the sender doesn't have to spend the extra data for the
receivers convenience.
* [j][^10]I like that idea. Especially if one thinks about those users
on a phone with limited traffic. You wouldn't want to use all your
available data just so others can sync. You could add a button on
top of lets say a picture saying "sync with my other devices" to
start the transfer of that picture to all your other devices. But
just sending it once should be a lot easier. I'd consider media sync
between my devices as a nice-to-have.
* [k][^11] Could it be a good idea to allow sync incomplete downloaded files from device A to device B and then start downloading from device B