Merge pull request #58 from schlagmichdoch/define_turn_config_dynamically
STUN/TURN config can now be changed dynamically via environment variable 🎉
This commit is contained in:
commit
827b10219d
6 changed files with 130 additions and 47 deletions
|
@ -63,6 +63,7 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
|
||||||
* Automatic restart on error (Thanks [@KaKi87](https://github.com/KaKi87))
|
* Automatic restart on error (Thanks [@KaKi87](https://github.com/KaKi87))
|
||||||
* Lots of stability fixes (Thanks [@MWY001](https://github.com/MWY001) [@skiby7](https://github.com/skiby7) and [@willstott101](https://github.com/willstott101))
|
* Lots of stability fixes (Thanks [@MWY001](https://github.com/MWY001) [@skiby7](https://github.com/skiby7) and [@willstott101](https://github.com/willstott101))
|
||||||
* To host PairDrop on your local network (e.g. on Raspberry Pi): [All peers connected with private IPs are discoverable by each other](https://github.com/RobinLinus/snapdrop/pull/558)
|
* To host PairDrop on your local network (e.g. on Raspberry Pi): [All peers connected with private IPs are discoverable by each other](https://github.com/RobinLinus/snapdrop/pull/558)
|
||||||
|
* When hosting PairDrop yourself you can [set your own STUN/TURN servers](/docs/host-your-own.md#specify-stunturn-servers)
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
|
@ -17,7 +17,7 @@ docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 ls
|
||||||
Set options by using the following flags in the `docker run` command:
|
Set options by using the following flags in the `docker run` command:
|
||||||
|
|
||||||
##### Port
|
##### Port
|
||||||
```
|
```bash
|
||||||
-p 127.0.0.1:8080:3000
|
-p 127.0.0.1:8080:3000
|
||||||
```
|
```
|
||||||
> Specify the port used by the docker image
|
> Specify the port used by the docker image
|
||||||
|
@ -30,7 +30,7 @@ Set options by using the following flags in the `docker run` command:
|
||||||
> Limits clients to 1000 requests per 5 min
|
> Limits clients to 1000 requests per 5 min
|
||||||
|
|
||||||
##### Websocket Fallback (for VPN)
|
##### Websocket Fallback (for VPN)
|
||||||
```
|
```bash
|
||||||
-e WS_FALLBACK=true
|
-e WS_FALLBACK=true
|
||||||
```
|
```
|
||||||
> Provides PairDrop to clients with an included websocket fallback if the peer to peer WebRTC connection is not available to the client.
|
> Provides PairDrop to clients with an included websocket fallback if the peer to peer WebRTC connection is not available to the client.
|
||||||
|
@ -42,6 +42,36 @@ Set options by using the following flags in the `docker run` command:
|
||||||
> Beware that the traffic routed via this fallback is readable by the server. Only ever use this on instances you can trust.
|
> Beware that the traffic routed via this fallback is readable by the server. Only ever use this on instances you can trust.
|
||||||
> Additionally, beware that all traffic using this fallback debits the servers data plan.
|
> Additionally, beware that all traffic using this fallback debits the servers data plan.
|
||||||
|
|
||||||
|
##### Specify STUN/TURN Servers
|
||||||
|
```bash
|
||||||
|
-e RTC_CONFIG="rtc_config.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
> Specify the STUN/TURN servers PairDrop clients use by setting `RTC_CONFIG` to a JSON file including the configuration.
|
||||||
|
> You can use `pairdrop/rtc_config_example.json` as a starting point.
|
||||||
|
>
|
||||||
|
> Default configuration:
|
||||||
|
> ```json
|
||||||
|
> {
|
||||||
|
> "sdpSemantics": "unified-plan",
|
||||||
|
> "iceServers": [
|
||||||
|
> {
|
||||||
|
> "urls": "stun:stun.l.google.com:19302"
|
||||||
|
> },
|
||||||
|
> {
|
||||||
|
> "urls": "stun:openrelay.metered.ca:80"
|
||||||
|
> },
|
||||||
|
> {
|
||||||
|
> "urls": "turn:openrelay.metered.ca:443",
|
||||||
|
> "username": "openrelayproject",
|
||||||
|
> "credential": "openrelayproject"
|
||||||
|
> }
|
||||||
|
> ]
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
### Docker Image from GHCR
|
### Docker Image from GHCR
|
||||||
```bash
|
```bash
|
||||||
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 ghcr.io/schlagmichdoch/pairdrop npm run start:prod
|
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 ghcr.io/schlagmichdoch/pairdrop npm run start:prod
|
||||||
|
@ -141,6 +171,38 @@ $env:PORT=3010; npm start
|
||||||
```
|
```
|
||||||
> Specify the port PairDrop is running on. (Default: 3000)
|
> Specify the port PairDrop is running on. (Default: 3000)
|
||||||
|
|
||||||
|
#### Specify STUN/TURN Server
|
||||||
|
On Unix based systems
|
||||||
|
```bash
|
||||||
|
RTC_CONFIG="rtc_config.json" npm start
|
||||||
|
```
|
||||||
|
On Windows
|
||||||
|
```bash
|
||||||
|
$env:RTC_CONFIG="rtc_config.json"; npm start
|
||||||
|
```
|
||||||
|
> Specify the STUN/TURN servers PairDrop clients use by setting `RTC_CONFIG` to a JSON file including the configuration.
|
||||||
|
> You can use `pairdrop/rtc_config_example.json` as a starting point.
|
||||||
|
>
|
||||||
|
> Default configuration:
|
||||||
|
> ```json
|
||||||
|
> {
|
||||||
|
> "sdpSemantics": "unified-plan",
|
||||||
|
> "iceServers": [
|
||||||
|
> {
|
||||||
|
> "urls": "stun:stun.l.google.com:19302"
|
||||||
|
> },
|
||||||
|
> {
|
||||||
|
> "urls": "stun:openrelay.metered.ca:80"
|
||||||
|
> },
|
||||||
|
> {
|
||||||
|
> "urls": "turn:openrelay.metered.ca:443",
|
||||||
|
> "username": "openrelayproject",
|
||||||
|
> "credential": "openrelayproject"
|
||||||
|
> }
|
||||||
|
> ]
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
|
||||||
### Options / Flags
|
### Options / Flags
|
||||||
#### Local Run
|
#### Local Run
|
||||||
```bash
|
```bash
|
||||||
|
@ -262,13 +324,13 @@ server {
|
||||||
|
|
||||||
### Using Apache
|
### Using Apache
|
||||||
install modules `proxy`, `proxy_http`, `mod_proxy_wstunnel`
|
install modules `proxy`, `proxy_http`, `mod_proxy_wstunnel`
|
||||||
```shell
|
```bash
|
||||||
a2enmod proxy
|
a2enmod proxy
|
||||||
```
|
```
|
||||||
```shell
|
```bash
|
||||||
a2enmod proxy_http
|
a2enmod proxy_http
|
||||||
```
|
```
|
||||||
```shell
|
```bash
|
||||||
a2enmod proxy_wstunnel
|
a2enmod proxy_wstunnel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -278,7 +340,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||||
|
|
||||||
**pairdrop.conf**
|
**pairdrop.conf**
|
||||||
#### Allow http and https requests
|
#### Allow http and https requests
|
||||||
```
|
```apacheconf
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ProxyPass / http://127.0.0.1:3000/
|
ProxyPass / http://127.0.0.1:3000/
|
||||||
RewriteEngine on
|
RewriteEngine on
|
||||||
|
@ -295,7 +357,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
#### Automatic http to https redirect:
|
#### Automatic http to https redirect:
|
||||||
```
|
```apacheconf
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
Redirect permanent / https://127.0.0.1:3000/
|
Redirect permanent / https://127.0.0.1:3000/
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
@ -308,10 +370,10 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
Activate the new virtual host and reload apache:
|
Activate the new virtual host and reload apache:
|
||||||
```shell
|
```bash
|
||||||
a2ensite pairdrop
|
a2ensite pairdrop
|
||||||
```
|
```
|
||||||
```shell
|
```bash
|
||||||
service apache2 reload
|
service apache2 reload
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -322,7 +384,7 @@ All files needed for developing are available on the branch `dev`.
|
||||||
First, [Install docker with docker-compose.](https://docs.docker.com/compose/install/)
|
First, [Install docker with docker-compose.](https://docs.docker.com/compose/install/)
|
||||||
|
|
||||||
Then, clone the repository and run docker-compose:
|
Then, clone the repository and run docker-compose:
|
||||||
```shell
|
```bash
|
||||||
git clone https://github.com/schlagmichdoch/PairDrop.git
|
git clone https://github.com/schlagmichdoch/PairDrop.git
|
||||||
|
|
||||||
cd PairDrop
|
cd PairDrop
|
||||||
|
@ -347,7 +409,7 @@ The nginx container creates a CA certificate and a website certificate for you.
|
||||||
|
|
||||||
If you want to test PWA features, you need to trust the CA of the certificate for your local deployment. For your convenience, you can download the crt file from `http://<Your FQDN>:8080/ca.crt`. Install that certificate to the trust store of your operating system.
|
If you want to test PWA features, you need to trust the CA of the certificate for your local deployment. For your convenience, you can download the crt file from `http://<Your FQDN>:8080/ca.crt`. Install that certificate to the trust store of your operating system.
|
||||||
- On Windows, make sure to install it to the `Trusted Root Certification Authorities` store.
|
- On Windows, make sure to install it to the `Trusted Root Certification Authorities` store.
|
||||||
- On MacOS, double click the installed CA certificate in `Keychain Access`, expand `Trust`, and select `Always Trust` for SSL.
|
- On macOS, double-click the installed CA certificate in `Keychain Access`, expand `Trust`, and select `Always Trust` for SSL.
|
||||||
- Firefox uses its own trust store. To install the CA, point Firefox at `http://<Your FQDN>:8080/ca.crt`. When prompted, select `Trust this CA to identify websites` and click OK.
|
- Firefox uses its own trust store. To install the CA, point Firefox at `http://<Your FQDN>:8080/ca.crt`. When prompted, select `Trust this CA to identify websites` and click OK.
|
||||||
- When using Chrome, you need to restart Chrome so it reloads the trust store (`chrome://restart`). Additionally, after installing a new cert, you need to clear the Storage (DevTools -> Application -> Clear storage -> Clear site data).
|
- When using Chrome, you need to restart Chrome so it reloads the trust store (`chrome://restart`). Additionally, after installing a new cert, you need to clear the Storage (DevTools -> Application -> Clear storage -> Clear site data).
|
||||||
|
|
||||||
|
|
24
index.js
24
index.js
|
@ -2,6 +2,7 @@ const process = require('process')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const {spawn} = require('child_process')
|
const {spawn} = require('child_process')
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
// Handle SIGINT
|
// Handle SIGINT
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
|
@ -50,6 +51,25 @@ if (process.argv.includes('--auto-restart')) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rtcConfig = process.env.RTC_CONFIG
|
||||||
|
? fs.readFileSync(process.env.RTC_CONFIG, 'utf8')
|
||||||
|
: {
|
||||||
|
"sdpSemantics": "unified-plan",
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": "stun:stun.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "stun:openrelay.metered.ca:80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:openrelay.metered.ca:443",
|
||||||
|
"username": "openrelayproject",
|
||||||
|
"credential": "openrelayproject"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const RateLimit = require('express-rate-limit');
|
const RateLimit = require('express-rate-limit');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
@ -113,6 +133,10 @@ class PairDropServer {
|
||||||
peer.socket.on('message', message => this._onMessage(peer, message));
|
peer.socket.on('message', message => this._onMessage(peer, message));
|
||||||
peer.socket.onerror = e => console.error(e);
|
peer.socket.onerror = e => console.error(e);
|
||||||
this._keepAlive(peer);
|
this._keepAlive(peer);
|
||||||
|
this._send(peer, {
|
||||||
|
type: 'rtc-config',
|
||||||
|
config: rtcConfig
|
||||||
|
});
|
||||||
this._joinRoom(peer);
|
this._joinRoom(peer);
|
||||||
|
|
||||||
// send displayName
|
// send displayName
|
||||||
|
|
|
@ -59,10 +59,17 @@ class ServerConnection {
|
||||||
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setRtcConfig(config) {
|
||||||
|
window.rtcConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
_onMessage(msg) {
|
_onMessage(msg) {
|
||||||
msg = JSON.parse(msg);
|
msg = JSON.parse(msg);
|
||||||
if (msg.type !== 'ping') console.log('WS:', msg);
|
if (msg.type !== 'ping') console.log('WS:', msg);
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
|
case 'rtc-config':
|
||||||
|
this._setRtcConfig(msg.config);
|
||||||
|
break;
|
||||||
case 'peers':
|
case 'peers':
|
||||||
Events.fire('peers', msg);
|
Events.fire('peers', msg);
|
||||||
break;
|
break;
|
||||||
|
@ -512,7 +519,7 @@ class RTCPeer extends Peer {
|
||||||
_openConnection(peerId, isCaller) {
|
_openConnection(peerId, isCaller) {
|
||||||
this._isCaller = isCaller;
|
this._isCaller = isCaller;
|
||||||
this._peerId = peerId;
|
this._peerId = peerId;
|
||||||
this._conn = new RTCPeerConnection(RTCPeer.config);
|
this._conn = new RTCPeerConnection(window.rtcConfig);
|
||||||
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
||||||
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
||||||
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
||||||
|
@ -862,20 +869,3 @@ class Events {
|
||||||
return window.removeEventListener(type, callback, false);
|
return window.removeEventListener(type, callback, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCPeer.config = {
|
|
||||||
'sdpSemantics': 'unified-plan',
|
|
||||||
'iceServers': [
|
|
||||||
{
|
|
||||||
urls: 'stun:stun.l.google.com:19302'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
urls: 'stun:openrelay.metered.ca:80'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
urls: 'turn:openrelay.metered.ca:443',
|
|
||||||
username: 'openrelayproject',
|
|
||||||
credential: 'openrelayproject',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -57,10 +57,17 @@ class ServerConnection {
|
||||||
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setRtcConfig(config) {
|
||||||
|
window.rtcConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
_onMessage(msg) {
|
_onMessage(msg) {
|
||||||
msg = JSON.parse(msg);
|
msg = JSON.parse(msg);
|
||||||
if (msg.type !== 'ping') console.log('WS:', msg);
|
if (msg.type !== 'ping') console.log('WS:', msg);
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
|
case 'rtc-config':
|
||||||
|
this._setRtcConfig(msg.config);
|
||||||
|
break;
|
||||||
case 'peers':
|
case 'peers':
|
||||||
Events.fire('peers', msg);
|
Events.fire('peers', msg);
|
||||||
break;
|
break;
|
||||||
|
@ -522,7 +529,7 @@ class RTCPeer extends Peer {
|
||||||
_openConnection(peerId, isCaller) {
|
_openConnection(peerId, isCaller) {
|
||||||
this._isCaller = isCaller;
|
this._isCaller = isCaller;
|
||||||
this._peerId = peerId;
|
this._peerId = peerId;
|
||||||
this._conn = new RTCPeerConnection(RTCPeer.config);
|
this._conn = new RTCPeerConnection(window.rtcConfig);
|
||||||
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
||||||
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
||||||
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
||||||
|
@ -940,20 +947,3 @@ class Events {
|
||||||
return window.removeEventListener(type, callback, false);
|
return window.removeEventListener(type, callback, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCPeer.config = {
|
|
||||||
'sdpSemantics': 'unified-plan',
|
|
||||||
'iceServers': [
|
|
||||||
{
|
|
||||||
urls: 'stun:stun.l.google.com:19302'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
urls: 'stun:openrelay.metered.ca:80'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
urls: 'turn:openrelay.metered.ca:443',
|
|
||||||
username: 'openrelayproject',
|
|
||||||
credential: 'openrelayproject',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
16
rtc_config_example.json
Normal file
16
rtc_config_example.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"sdpSemantics": "unified-plan",
|
||||||
|
"iceServers": [
|
||||||
|
{
|
||||||
|
"urls": "stun:stun.l.google.com:19302"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "stun:openrelay.metered.ca:80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls": "turn:openrelay.metered.ca:443",
|
||||||
|
"username": "openrelayproject",
|
||||||
|
"credential": "openrelayproject"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue