mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2026-04-12 20:32:15 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67a1b04da2 | ||
|
|
8b2eb67266 | ||
|
|
827b10219d | ||
|
|
e7ab5e26cc | ||
|
|
8bcaa3f60f | ||
|
|
c0a4224a59 | ||
|
|
1e35bab327 | ||
|
|
bb0493d071 | ||
|
|
bfb5aa8546 | ||
|
|
de76da52fe | ||
|
|
66359da2ca | ||
|
|
74b88c2e7d |
@@ -63,6 +63,7 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
|
||||
* 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))
|
||||
* 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
|
||||
<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:
|
||||
|
||||
##### Port
|
||||
```
|
||||
```bash
|
||||
-p 127.0.0.1:8080:3000
|
||||
```
|
||||
> 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
|
||||
|
||||
##### Websocket Fallback (for VPN)
|
||||
```
|
||||
```bash
|
||||
-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.
|
||||
@@ -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.
|
||||
> 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
|
||||
```bash
|
||||
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 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
|
||||
#### Local Run
|
||||
```bash
|
||||
@@ -262,13 +324,13 @@ server {
|
||||
|
||||
### Using Apache
|
||||
install modules `proxy`, `proxy_http`, `mod_proxy_wstunnel`
|
||||
```shell
|
||||
```bash
|
||||
a2enmod proxy
|
||||
```
|
||||
```shell
|
||||
```bash
|
||||
a2enmod proxy_http
|
||||
```
|
||||
```shell
|
||||
```bash
|
||||
a2enmod proxy_wstunnel
|
||||
```
|
||||
|
||||
@@ -278,7 +340,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||
|
||||
**pairdrop.conf**
|
||||
#### Allow http and https requests
|
||||
```
|
||||
```apacheconf
|
||||
<VirtualHost *:80>
|
||||
ProxyPass / http://127.0.0.1:3000/
|
||||
RewriteEngine on
|
||||
@@ -295,7 +357,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||
</VirtualHost>
|
||||
```
|
||||
#### Automatic http to https redirect:
|
||||
```
|
||||
```apacheconf
|
||||
<VirtualHost *:80>
|
||||
Redirect permanent / https://127.0.0.1:3000/
|
||||
</VirtualHost>
|
||||
@@ -308,10 +370,10 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||
</VirtualHost>
|
||||
```
|
||||
Activate the new virtual host and reload apache:
|
||||
```shell
|
||||
```bash
|
||||
a2ensite pairdrop
|
||||
```
|
||||
```shell
|
||||
```bash
|
||||
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/)
|
||||
|
||||
Then, clone the repository and run docker-compose:
|
||||
```shell
|
||||
```bash
|
||||
git clone https://github.com/schlagmichdoch/PairDrop.git
|
||||
|
||||
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.
|
||||
- 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.
|
||||
- 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 {spawn} = require('child_process')
|
||||
const WebSocket = require('ws');
|
||||
const fs = require('fs');
|
||||
|
||||
// Handle 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 RateLimit = require('express-rate-limit');
|
||||
const http = require('http');
|
||||
@@ -113,6 +133,10 @@ class PairDropServer {
|
||||
peer.socket.on('message', message => this._onMessage(peer, message));
|
||||
peer.socket.onerror = e => console.error(e);
|
||||
this._keepAlive(peer);
|
||||
this._send(peer, {
|
||||
type: 'rtc-config',
|
||||
config: rtcConfig
|
||||
});
|
||||
this._joinRoom(peer);
|
||||
|
||||
// send displayName
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pairdrop",
|
||||
"version": "1.2.1",
|
||||
"version": "1.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pairdrop",
|
||||
"version": "1.2.1",
|
||||
"version": "1.3.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pairdrop",
|
||||
"version": "1.2.1",
|
||||
"version": "1.3.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -242,14 +242,14 @@
|
||||
</div>
|
||||
<!-- About Page -->
|
||||
<x-about id="about" class="full center column">
|
||||
<header class="row-reverse fade-in">
|
||||
<a href="#" class="close icon-button">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#close-icon" />
|
||||
</svg>
|
||||
</a>
|
||||
</header>
|
||||
<section class="center column fade-in">
|
||||
<header class="row-reverse">
|
||||
<a href="#" class="close icon-button">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#close-icon" />
|
||||
</svg>
|
||||
</a>
|
||||
</header>
|
||||
<svg class="icon logo">
|
||||
<use xlink:href="#wifi-tethering" />
|
||||
</svg>
|
||||
|
||||
@@ -36,6 +36,7 @@ class ServerConnection {
|
||||
_onOpen() {
|
||||
console.log('WS: server connected');
|
||||
Events.fire('ws-connected');
|
||||
if (this._isReconnect) Events.fire('notify-user', 'Connected.');
|
||||
}
|
||||
|
||||
_sendRoomSecrets(roomSecrets) {
|
||||
@@ -58,10 +59,17 @@ class ServerConnection {
|
||||
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
||||
}
|
||||
|
||||
_setRtcConfig(config) {
|
||||
window.rtcConfig = config;
|
||||
}
|
||||
|
||||
_onMessage(msg) {
|
||||
msg = JSON.parse(msg);
|
||||
if (msg.type !== 'ping') console.log('WS:', msg);
|
||||
switch (msg.type) {
|
||||
case 'rtc-config':
|
||||
this._setRtcConfig(msg.config);
|
||||
break;
|
||||
case 'peers':
|
||||
Events.fire('peers', msg);
|
||||
break;
|
||||
@@ -145,15 +153,17 @@ class ServerConnection {
|
||||
this._socket.close();
|
||||
this._socket = null;
|
||||
Events.fire('ws-disconnected');
|
||||
this._isReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
_onDisconnect() {
|
||||
console.log('WS: server disconnected');
|
||||
Events.fire('notify-user', 'No server connection. Retry in 5s...');
|
||||
Events.fire('notify-user', 'Connecting..');
|
||||
clearTimeout(this._reconnectTimer);
|
||||
this._reconnectTimer = setTimeout(_ => this._connect(), 5000);
|
||||
Events.fire('ws-disconnected');
|
||||
this._isReconnect = true;
|
||||
}
|
||||
|
||||
_onVisibilityChange() {
|
||||
@@ -319,25 +329,25 @@ class Peer {
|
||||
this._onChunkReceived(message);
|
||||
return;
|
||||
}
|
||||
message = JSON.parse(message);
|
||||
switch (message.type) {
|
||||
const messageJSON = JSON.parse(message);
|
||||
switch (messageJSON.type) {
|
||||
case 'request':
|
||||
this._onFilesTransferRequest(message);
|
||||
this._onFilesTransferRequest(messageJSON);
|
||||
break;
|
||||
case 'header':
|
||||
this._onFilesHeader(message);
|
||||
this._onFilesHeader(messageJSON);
|
||||
break;
|
||||
case 'partition':
|
||||
this._onReceivedPartitionEnd(message);
|
||||
this._onReceivedPartitionEnd(messageJSON);
|
||||
break;
|
||||
case 'partition-received':
|
||||
this._sendNextPartition();
|
||||
break;
|
||||
case 'progress':
|
||||
this._onDownloadProgress(message.progress);
|
||||
this._onDownloadProgress(messageJSON.progress);
|
||||
break;
|
||||
case 'files-transfer-response':
|
||||
this._onFileTransferRequestResponded(message);
|
||||
this._onFileTransferRequestResponded(messageJSON);
|
||||
break;
|
||||
case 'file-transfer-complete':
|
||||
this._onFileTransferCompleted();
|
||||
@@ -346,7 +356,7 @@ class Peer {
|
||||
this._onMessageTransferCompleted();
|
||||
break;
|
||||
case 'text':
|
||||
this._onTextReceived(message);
|
||||
this._onTextReceived(messageJSON);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -509,7 +519,7 @@ class RTCPeer extends Peer {
|
||||
_openConnection(peerId, isCaller) {
|
||||
this._isCaller = isCaller;
|
||||
this._peerId = peerId;
|
||||
this._conn = new RTCPeerConnection(RTCPeer.config);
|
||||
this._conn = new RTCPeerConnection(window.rtcConfig);
|
||||
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
||||
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
||||
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
||||
@@ -570,8 +580,7 @@ class RTCPeer extends Peer {
|
||||
|
||||
_onMessage(message) {
|
||||
if (typeof message === 'string') {
|
||||
message = JSON.parse(message);
|
||||
console.log('RTC:', message);
|
||||
console.log('RTC:', JSON.parse(message));
|
||||
}
|
||||
super._onMessage(message);
|
||||
}
|
||||
@@ -860,20 +869,3 @@ class Events {
|
||||
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',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||
this.createPreviewElement(files[0]).finally(_ => {
|
||||
document.title = files.length === 1
|
||||
? 'File received - PairDrop'
|
||||
: `(${files.length}) Files received - PairDrop`;
|
||||
: `${files.length} Files received - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
Events.fire('set-progress', {peerId: peerId, progress: 1, status: 'process'})
|
||||
this.show();
|
||||
@@ -1143,7 +1143,7 @@ class ReceiveTextDialog extends Dialog {
|
||||
_setDocumentTitleMessages() {
|
||||
document.title = !this._receiveTextQueue.length
|
||||
? 'Message Received - PairDrop'
|
||||
: `(${this._receiveTextQueue.length + 1}) Messages Received - PairDrop`;
|
||||
: `${this._receiveTextQueue.length + 1} Messages Received - PairDrop`;
|
||||
}
|
||||
|
||||
async _onCopy() {
|
||||
@@ -1424,7 +1424,7 @@ class NetworkStatusUI {
|
||||
constructor() {
|
||||
Events.on('offline', _ => this._showOfflineMessage());
|
||||
Events.on('online', _ => this._showOnlineMessage());
|
||||
Events.on('ws-connected', _ => this._showOnlineMessage());
|
||||
Events.on('ws-connected', _ => this._onWsConnected());
|
||||
Events.on('ws-disconnected', _ => this._onWsDisconnected());
|
||||
if (!navigator.onLine) this._showOfflineMessage();
|
||||
}
|
||||
@@ -1435,17 +1435,16 @@ class NetworkStatusUI {
|
||||
}
|
||||
|
||||
_showOnlineMessage() {
|
||||
window.animateBackground(true);
|
||||
if (!this.firstConnect) {
|
||||
this.firstConnect = true;
|
||||
return;
|
||||
}
|
||||
Events.fire('notify-user', 'You are back online');
|
||||
window.animateBackground(true);
|
||||
}
|
||||
|
||||
_onWsConnected() {
|
||||
window.animateBackground(true);
|
||||
}
|
||||
|
||||
_onWsDisconnected() {
|
||||
window.animateBackground(false);
|
||||
if (!this.firstConnect) this.firstConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cacheVersion = 'v1.2.1';
|
||||
const cacheVersion = 'v1.3.0';
|
||||
const cacheTitle = `pairdrop-cache-${cacheVersion}`;
|
||||
const urlsToCache = [
|
||||
'index.html',
|
||||
|
||||
@@ -939,6 +939,13 @@ button::-moz-focus-inner {
|
||||
margin: 8px 8px -16px;
|
||||
}
|
||||
|
||||
#about section {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#about header {
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ class ServerConnection {
|
||||
_onOpen() {
|
||||
console.log('WS: server connected');
|
||||
Events.fire('ws-connected');
|
||||
if (this._isReconnect) Events.fire('notify-user', 'Connected.');
|
||||
}
|
||||
|
||||
_sendRoomSecrets(roomSecrets) {
|
||||
@@ -56,10 +57,17 @@ class ServerConnection {
|
||||
this.send({ type: 'pair-device-join', roomKey: roomKey })
|
||||
}
|
||||
|
||||
_setRtcConfig(config) {
|
||||
window.rtcConfig = config;
|
||||
}
|
||||
|
||||
_onMessage(msg) {
|
||||
msg = JSON.parse(msg);
|
||||
if (msg.type !== 'ping') console.log('WS:', msg);
|
||||
switch (msg.type) {
|
||||
case 'rtc-config':
|
||||
this._setRtcConfig(msg.config);
|
||||
break;
|
||||
case 'peers':
|
||||
Events.fire('peers', msg);
|
||||
break;
|
||||
@@ -155,15 +163,17 @@ class ServerConnection {
|
||||
this._socket.close();
|
||||
this._socket = null;
|
||||
Events.fire('ws-disconnected');
|
||||
this._isReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
_onDisconnect() {
|
||||
console.log('WS: server disconnected');
|
||||
Events.fire('notify-user', 'No server connection. Retry in 5s...');
|
||||
Events.fire('notify-user', 'Connecting..');
|
||||
clearTimeout(this._reconnectTimer);
|
||||
this._reconnectTimer = setTimeout(_ => this._connect(), 5000);
|
||||
Events.fire('ws-disconnected');
|
||||
this._isReconnect = true;
|
||||
}
|
||||
|
||||
_onVisibilityChange() {
|
||||
@@ -329,25 +339,25 @@ class Peer {
|
||||
this._onChunkReceived(message);
|
||||
return;
|
||||
}
|
||||
message = JSON.parse(message);
|
||||
switch (message.type) {
|
||||
const messageJSON = JSON.parse(message);
|
||||
switch (messageJSON.type) {
|
||||
case 'request':
|
||||
this._onFilesTransferRequest(message);
|
||||
this._onFilesTransferRequest(messageJSON);
|
||||
break;
|
||||
case 'header':
|
||||
this._onFilesHeader(message);
|
||||
this._onFilesHeader(messageJSON);
|
||||
break;
|
||||
case 'partition':
|
||||
this._onReceivedPartitionEnd(message);
|
||||
this._onReceivedPartitionEnd(messageJSON);
|
||||
break;
|
||||
case 'partition-received':
|
||||
this._sendNextPartition();
|
||||
break;
|
||||
case 'progress':
|
||||
this._onDownloadProgress(message.progress);
|
||||
this._onDownloadProgress(messageJSON.progress);
|
||||
break;
|
||||
case 'files-transfer-response':
|
||||
this._onFileTransferRequestResponded(message);
|
||||
this._onFileTransferRequestResponded(messageJSON);
|
||||
break;
|
||||
case 'file-transfer-complete':
|
||||
this._onFileTransferCompleted();
|
||||
@@ -356,7 +366,7 @@ class Peer {
|
||||
this._onMessageTransferCompleted();
|
||||
break;
|
||||
case 'text':
|
||||
this._onTextReceived(message);
|
||||
this._onTextReceived(messageJSON);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -519,7 +529,7 @@ class RTCPeer extends Peer {
|
||||
_openConnection(peerId, isCaller) {
|
||||
this._isCaller = isCaller;
|
||||
this._peerId = peerId;
|
||||
this._conn = new RTCPeerConnection(RTCPeer.config);
|
||||
this._conn = new RTCPeerConnection(window.rtcConfig);
|
||||
this._conn.onicecandidate = e => this._onIceCandidate(e);
|
||||
this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
|
||||
this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
|
||||
@@ -580,8 +590,7 @@ class RTCPeer extends Peer {
|
||||
|
||||
_onMessage(message) {
|
||||
if (typeof message === 'string') {
|
||||
message = JSON.parse(message);
|
||||
console.log('RTC:', message);
|
||||
console.log('RTC:', JSON.parse(message));
|
||||
}
|
||||
super._onMessage(message);
|
||||
}
|
||||
@@ -938,20 +947,3 @@ class Events {
|
||||
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',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -663,7 +663,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||
this.createPreviewElement(files[0]).finally(_ => {
|
||||
document.title = files.length === 1
|
||||
? 'File received - PairDrop'
|
||||
: `(${files.length}) Files received - PairDrop`;
|
||||
: `${files.length} Files received - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
Events.fire('set-progress', {peerId: peerId, progress: 1, status: 'process'})
|
||||
this.show();
|
||||
@@ -1144,7 +1144,7 @@ class ReceiveTextDialog extends Dialog {
|
||||
_setDocumentTitleMessages() {
|
||||
document.title = !this._receiveTextQueue.length
|
||||
? 'Message Received - PairDrop'
|
||||
: `(${this._receiveTextQueue.length + 1}) Messages Received - PairDrop`;
|
||||
: `${this._receiveTextQueue.length + 1} Messages Received - PairDrop`;
|
||||
}
|
||||
|
||||
async _onCopy() {
|
||||
@@ -1425,7 +1425,7 @@ class NetworkStatusUI {
|
||||
constructor() {
|
||||
Events.on('offline', _ => this._showOfflineMessage());
|
||||
Events.on('online', _ => this._showOnlineMessage());
|
||||
Events.on('ws-connected', _ => this._showOnlineMessage());
|
||||
Events.on('ws-connected', _ => this._onWsConnected());
|
||||
Events.on('ws-disconnected', _ => this._onWsDisconnected());
|
||||
if (!navigator.onLine) this._showOfflineMessage();
|
||||
}
|
||||
@@ -1436,17 +1436,16 @@ class NetworkStatusUI {
|
||||
}
|
||||
|
||||
_showOnlineMessage() {
|
||||
window.animateBackground(true);
|
||||
if (!this.firstConnect) {
|
||||
this.firstConnect = true;
|
||||
return;
|
||||
}
|
||||
Events.fire('notify-user', 'You are back online');
|
||||
window.animateBackground(true);
|
||||
}
|
||||
|
||||
_onWsConnected() {
|
||||
window.animateBackground(true);
|
||||
}
|
||||
|
||||
_onWsDisconnected() {
|
||||
window.animateBackground(false);
|
||||
if (!this.firstConnect) this.firstConnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cacheVersion = 'v1.2.1';
|
||||
const cacheVersion = 'v1.3.0';
|
||||
const cacheTitle = `pairdrop-included-ws-fallback-cache-${cacheVersion}`;
|
||||
const urlsToCache = [
|
||||
'index.html',
|
||||
|
||||
@@ -965,6 +965,13 @@ button::-moz-focus-inner {
|
||||
margin: 8px 8px -16px;
|
||||
}
|
||||
|
||||
#about section {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#about header {
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
|
||||
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user