Merge 648f5507e6
into ecf996389f
commit
5794a96da6
@ -0,0 +1,164 @@
|
|||||||
|
# MSC2354 - Device to device streaming file transfers
|
||||||
|
|
||||||
|
File transfer in matrix currently works by uploading a file to the server, which is then distributed over
|
||||||
|
the participating servers in the room, and is available through an HTTP get request to everyone who knows
|
||||||
|
the URL. By necessity this has a maximum filesize and also results in a more or less permanent availability
|
||||||
|
of said file. For larger files, and/or files that should only be sent from point-to-point, it may be desirable
|
||||||
|
to be able to send from device to device. As matrix already implements
|
||||||
|
[WebRTC signalling for voip](https://matrix.org/docs/spec/client_server/r0.6.0#voice-over-ip), this
|
||||||
|
functionality can be replicated for streaming file transfers from device to device. It can even be possible
|
||||||
|
to send files not between devices of two matrix users, but two matrix devices owned by the same user. For
|
||||||
|
this we can use the webrtc datachannel.
|
||||||
|
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
To allow the device to device streaming data tranfser we propose to add events mirroring setting up a
|
||||||
|
WebRTC VoIP session.
|
||||||
|
|
||||||
|
To start a file transfer a user first selects the file to be transferred, after which the sending client
|
||||||
|
sends an `m.d2dfile.invite` event with:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"transfer_id": "12345",
|
||||||
|
"lifetime": 60000,
|
||||||
|
"filename": "example.doc",
|
||||||
|
"info": {
|
||||||
|
"mimetype": "application/msword",
|
||||||
|
"size": 46144
|
||||||
|
},
|
||||||
|
"offer": {
|
||||||
|
"sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
|
||||||
|
"type": "offer"
|
||||||
|
},
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"event_id": "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.d2dfile.invite",
|
||||||
|
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This triggers other devices in the room to alert the user about the offered transfer, displaying the filename, filetype and filesize.
|
||||||
|
|
||||||
|
In order to establish an RTCDataChannel, the sending device can gather candidates.
|
||||||
|
This is done following the spec detailing how to find a turnserver by sending an
|
||||||
|
authenticated get request to `https://example.org/_matrix/client/r0/voip/turnServer`.
|
||||||
|
Following the same course as used for setting up a VoIP call, this returns
|
||||||
|
the address of the turnserver and a username and password. This turnserver can then be used
|
||||||
|
to find the peer to peer candidates and/or a relay. Otherwise the external (possibly local)
|
||||||
|
ip address can be used to create a candidate.
|
||||||
|
|
||||||
|
These candidates are then sent using:
|
||||||
|
`m.d2dfile.candidates` with:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"transfer_id": "12345",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate": "candidate:863018703 1 tcp 2122260223 10.9.64.156 43670 typ host generation 0",
|
||||||
|
"sdpMLineIndex": 0,
|
||||||
|
"sdpMid": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"event_id": "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.d2dfile.candidates",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a device accepts the filetransfer the device in turn sends an `m.d2dfile.answer` event, containing:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"answer": {
|
||||||
|
"sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
|
||||||
|
"type": "answer"
|
||||||
|
},
|
||||||
|
"transfer_id": "12345",
|
||||||
|
"lifetime": 60000,
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"event_id": "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.d2dfile.answer",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The accepting device also sends a `m.d2dfile.candidates` in order to establish the data connection.
|
||||||
|
|
||||||
|
To cancel a filetransfer or reject an offer the `m.d2dfile.cancel` event is sent, as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"transfer_id": "12345",
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"event_id": "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.d2dfile.cancel",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Potential issues
|
||||||
|
It's tempting to want to use this for device to device transfer in public rooms,
|
||||||
|
but an evil homeserver could hijack the webrtc session by pretending to be a device
|
||||||
|
for the intended recipient (if that user has an account on the evil server). As such this
|
||||||
|
should be limited to private rooms.
|
||||||
|
Otherwise the matrix logic is quite simple here, basically following the same flow as 1:1 VoIP calls,
|
||||||
|
however: most guides (including the synapse github how-to) advice to disable TCP relays in the turnserver,
|
||||||
|
which may be unwanted for file transfers.
|
||||||
|
|
||||||
|
Both sender and reciever need to be online simultaneously for this mode of file transfer
|
||||||
|
to work, which is unexpected in the context of the existing matrix file transfer.
|
||||||
|
|
||||||
|
This file transfer will only send the file once, from one device to another.
|
||||||
|
|
||||||
|
While this proposal focusses on streaming file transfer,
|
||||||
|
a webrtc datachannel could be used for any generic data transfer,
|
||||||
|
for the use of any other application, such as games for instance.
|
||||||
|
If such application is wanted, the d2dfile event type may be a poorly chosen name.
|
||||||
|
For this proposal other uses for a webrtc datachannel is deemed out of scope.
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
The current way of sending files is a valid alternative,
|
||||||
|
the biggest upside of adding this proposal is that this allows for
|
||||||
|
streaming file transfer outside of matrix and is thus not limited in filesize
|
||||||
|
and negates the need for the matrix server to host any of the files.
|
||||||
|
Since filetransfer over matrix isn't unique with the device to device transfer,
|
||||||
|
and implementation of filetransfers over webrtc is probably not trivial,
|
||||||
|
this feature could be marked as optional.
|
||||||
|
|
||||||
|
## Security considerations
|
||||||
|
Using RTCDataChannel to transfer files could be abused to send malware
|
||||||
|
without having the possibility of checking for this in between on the serverside.
|
||||||
|
This could be mitigated similarly to how DINUM does this,
|
||||||
|
by sending the file to a virus scanning server first,
|
||||||
|
but that negates (some of) the advantage of streaming filetransfers.
|
Loading…
Reference in New Issue