mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2026-04-06 18:03:48 +00:00
Compare commits
5 Commits
v1.6.2
...
ask_for_pe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47e040d666 | ||
|
|
fafdbcc829 | ||
|
|
b9806d4327 | ||
|
|
fb08bdaf36 | ||
|
|
5a363e90dd |
@@ -30,7 +30,7 @@ Set options by using the following flags in the `docker run` command:
|
||||
> - 3000 -> `-p 127.0.0.1:3000:3000`
|
||||
> - 8080 -> `-p 127.0.0.1:8080:3000`
|
||||
##### Rate limiting requests
|
||||
```
|
||||
```bash
|
||||
-e RATE_LIMIT=true
|
||||
```
|
||||
> Limits clients to 1000 requests per 5 min
|
||||
@@ -70,6 +70,31 @@ Set options by using the following flags in the `docker run` command:
|
||||
> }
|
||||
> ```
|
||||
|
||||
##### Debug Mode
|
||||
```bash
|
||||
-e DEBUG_MODE="true"
|
||||
```
|
||||
|
||||
> Use this flag to enable debugging information about the connecting peers IP addresses. This is quite useful to check whether the [#HTTP-Server](#http-server)
|
||||
> is configured correctly, so the auto discovery feature works correctly. Otherwise, all clients discover each other mutually, independently of their network status.
|
||||
>
|
||||
> If this flag is set to `"true"` each peer that connects to the PairDrop server will produce a log to STDOUT like this:
|
||||
> ```
|
||||
> ----DEBUGGING-PEER-IP-START----
|
||||
> remoteAddress: ::ffff:172.17.0.1
|
||||
> x-forwarded-for: 19.117.63.126
|
||||
> cf-connecting-ip: undefined
|
||||
> PairDrop uses: 19.117.63.126
|
||||
> IP is private: false
|
||||
> if IP is private, '127.0.0.1' is used instead
|
||||
> ----DEBUGGING-PEER-IP-END----
|
||||
> ```
|
||||
> If the IP PairDrop uses is the public IP of your device everything is correctly setup.
|
||||
>To find out your devices public IP visit https://www.whatismyip.com/.
|
||||
>
|
||||
> To preserve your clients' privacy, **never use this flag in production!**
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
### Docker Image from GHCR
|
||||
@@ -82,7 +107,7 @@ docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 gh
|
||||
>
|
||||
> To specify options replace `npm run start:prod` according to [the documentation below.](#options--flags-1)
|
||||
|
||||
> The Docker Image includes a Healthcheck. To learn more see [Docker Swarm Usage](./docker-swarm-usage.md#docker-swarm-usage)
|
||||
> The Docker Image includes a Healthcheck. To learn more see [Docker Swarm Usage](docker-swarm-usage.md#docker-swarm-usage)
|
||||
|
||||
### Docker Image self-built
|
||||
#### Build the image
|
||||
@@ -103,7 +128,7 @@ docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 -i
|
||||
>
|
||||
> To specify options replace `npm run start:prod` according to [the documentation below.](#options--flags-1)
|
||||
|
||||
> The Docker Image includes a Healthcheck. To learn more see [Docker Swarm Usage](./docker-swarm-usage.md#docker-swarm-usage)
|
||||
> The Docker Image includes a Healthcheck. To learn more see [Docker Swarm Usage](docker-swarm-usage.md#docker-swarm-usage)
|
||||
|
||||
<br>
|
||||
|
||||
@@ -201,6 +226,36 @@ $env:RTC_CONFIG="rtc_config.json"; npm start
|
||||
> }
|
||||
> ```
|
||||
|
||||
#### Debug Mode
|
||||
On Unix based systems
|
||||
```bash
|
||||
DEBUG_MODE="true" npm start
|
||||
```
|
||||
On Windows
|
||||
```bash
|
||||
$env:DEBUG_MODE="true"; npm start
|
||||
```
|
||||
|
||||
> Use this flag to enable debugging information about the connecting peers IP addresses. This is quite useful to check whether the [#HTTP-Server](#http-server)
|
||||
> is configured correctly, so the auto discovery feature works correctly. Otherwise, all clients discover each other mutually, independently of their network status.
|
||||
>
|
||||
> If this flag is set to `"true"` each peer that connects to the PairDrop server will produce a log to STDOUT like this:
|
||||
> ```
|
||||
> ----DEBUGGING-PEER-IP-START----
|
||||
> remoteAddress: ::ffff:172.17.0.1
|
||||
> x-forwarded-for: 19.117.63.126
|
||||
> cf-connecting-ip: undefined
|
||||
> PairDrop uses: 19.117.63.126
|
||||
> IP is private: false
|
||||
> if IP is private, '127.0.0.1' is used instead
|
||||
> ----DEBUGGING-PEER-IP-END----
|
||||
> ```
|
||||
> If the IP PairDrop uses is the public IP of your device everything is correctly setup.
|
||||
>To find out your devices public IP visit https://www.whatismyip.com/.
|
||||
>
|
||||
> To preserve your clients' privacy, **never use this flag in production!**
|
||||
|
||||
|
||||
### Options / Flags
|
||||
#### Local Run
|
||||
```bash
|
||||
@@ -257,6 +312,8 @@ npm run start:prod -- --localhost-only --include-ws-fallback
|
||||
## HTTP-Server
|
||||
When running PairDrop, the `X-Forwarded-For` header has to be set by a proxy. Otherwise, all clients will be mutually visible.
|
||||
|
||||
To check if your setup is configured correctly [use the environment variable `DEBUG_MODE="true"`](#debug-mode).
|
||||
|
||||
### Using nginx
|
||||
#### Allow http and https requests
|
||||
```
|
||||
|
||||
17
index.js
17
index.js
@@ -90,6 +90,12 @@ if (process.argv.includes('--include-ws-fallback')) {
|
||||
app.use(express.static('public'));
|
||||
}
|
||||
|
||||
const debugMode = process.env.DEBUG_MODE === "true";
|
||||
|
||||
if (debugMode) {
|
||||
console.log("DEBUG_MODE is active. To protect privacy, do not use in production.")
|
||||
}
|
||||
|
||||
app.use(function(req, res) {
|
||||
res.redirect('/');
|
||||
});
|
||||
@@ -502,6 +508,17 @@ class Peer {
|
||||
if (this.ip.substring(0,7) === "::ffff:")
|
||||
this.ip = this.ip.substring(7);
|
||||
|
||||
if (debugMode) {
|
||||
console.debug("----DEBUGGING-PEER-IP-START----");
|
||||
console.debug("remoteAddress:", request.connection.remoteAddress);
|
||||
console.debug("x-forwarded-for:", request.headers['x-forwarded-for']);
|
||||
console.debug("cf-connecting-ip:", request.headers['cf-connecting-ip']);
|
||||
console.debug("PairDrop uses:", this.ip);
|
||||
console.debug("IP is private:", this.ipIsPrivate(this.ip));
|
||||
console.debug("if IP is private, '127.0.0.1' is used instead");
|
||||
console.debug("----DEBUGGING-PEER-IP-END----");
|
||||
}
|
||||
|
||||
// IPv4 and IPv6 use different values to refer to localhost
|
||||
// put all peers on the same network as the server into the same room as well
|
||||
if (this.ip === '::1' || this.ipIsPrivate(this.ip)) {
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pairdrop",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pairdrop",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pairdrop",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -87,12 +87,16 @@ class PeersUI {
|
||||
if (newDisplayName === savedDisplayName) return;
|
||||
|
||||
if (newDisplayName) {
|
||||
PersistentStorage.set('editedDisplayName', newDisplayName).then(_ => {
|
||||
PersistentStorage.set('editedDisplayName', newDisplayName).then(async _ => {
|
||||
const persistent = await PersistentStorage.isStoragePersistent();
|
||||
if (!persistent) {
|
||||
throw ErrorEvent("Storage not persistent.")
|
||||
}
|
||||
Events.fire('notify-user', 'Device name is changed permanently.');
|
||||
}).catch(_ => {
|
||||
console.log("This browser does not support IndexedDB. Use localStorage instead.");
|
||||
localStorage.setItem('editedDisplayName', newDisplayName);
|
||||
Events.fire('notify-user', 'Device name is changed only for this session.');
|
||||
Events.fire('notify-user', 'Device name is changed for this session only.\n\nGoogle Chrome:\nSave page as bookmark or enable notifications to enable persistence.');
|
||||
}).finally(_ => {
|
||||
Events.fire('self-display-name-changed', newDisplayName);
|
||||
Events.fire('broadcast-send', {type: 'self-display-name-changed', detail: newDisplayName});
|
||||
@@ -101,7 +105,6 @@ class PeersUI {
|
||||
PersistentStorage.delete('editedDisplayName').catch(_ => {
|
||||
console.log("This browser does not support IndexedDB. Use localStorage instead.")
|
||||
localStorage.removeItem('editedDisplayName');
|
||||
Events.fire('notify-user', 'Random Display name is used again.');
|
||||
}).finally(_ => {
|
||||
Events.fire('notify-user', 'Device name is randomly generated again.');
|
||||
Events.fire('self-display-name-changed', '');
|
||||
@@ -1027,17 +1030,21 @@ class PairDeviceDialog extends Dialog {
|
||||
|
||||
_pairDeviceJoined(peerId, roomSecret) {
|
||||
this.hide();
|
||||
PersistentStorage.addRoomSecret(roomSecret).then(_ => {
|
||||
PersistentStorage.addRoomSecret(roomSecret).then(async addedRoomSecret => {
|
||||
const persistent = await PersistentStorage.isStoragePersistent();
|
||||
if (!persistent) {
|
||||
throw ErrorEvent("Storage not persistent.")
|
||||
}
|
||||
Events.fire('notify-user', 'Devices paired successfully.');
|
||||
const oldRoomSecret = $(peerId).ui.roomSecret;
|
||||
if (oldRoomSecret) PersistentStorage.deleteRoomSecret(oldRoomSecret);
|
||||
$(peerId).ui.roomSecret = roomSecret;
|
||||
this._evaluateNumberRoomSecrets();
|
||||
if (oldRoomSecret) await PersistentStorage.deleteRoomSecret(oldRoomSecret);
|
||||
$(peerId).ui.roomSecret = addedRoomSecret;
|
||||
}).finally(_ => {
|
||||
this._evaluateNumberRoomSecrets();
|
||||
this._cleanUp();
|
||||
})
|
||||
.catch(_ => {
|
||||
Events.fire('notify-user', 'Paired devices are not persistent.');
|
||||
Events.fire('notify-user', 'Paired device is saved for this session only.\n\nGoogle Chrome:\nSave page as bookmark or enable notifications to enable persistence.');
|
||||
PersistentStorage.logBrowserNotCapable();
|
||||
});
|
||||
}
|
||||
@@ -1460,6 +1467,15 @@ class Notifications {
|
||||
return;
|
||||
}
|
||||
Events.fire('notify-user', 'Notifications enabled.');
|
||||
PersistentStorage.isStoragePersistent().then(persistent => {
|
||||
if (!persistent) {
|
||||
PersistentStorage.requestPersistentStorage().then(updatedPersistence => {
|
||||
if (updatedPersistence) {
|
||||
Events.fire('notify-user', 'Successfully enabled persistent storage.')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.$button.setAttribute('hidden', 1);
|
||||
});
|
||||
}
|
||||
@@ -1722,8 +1738,27 @@ class PersistentStorage {
|
||||
console.log("This browser does not support IndexedDB. Paired devices will be gone after the browser is closed.");
|
||||
}
|
||||
|
||||
static async isStoragePersistent() {
|
||||
return await navigator.storage.persisted();
|
||||
}
|
||||
|
||||
static async requestPersistentStorage() {
|
||||
if (!navigator.storage || !navigator.storage.persist) return false;
|
||||
if (await this.isStoragePersistent()) return true;
|
||||
|
||||
const persistent = await navigator.storage.persist()
|
||||
if (persistent) {
|
||||
console.log("Storage will not be cleared except by explicit user action");
|
||||
} else {
|
||||
console.warn("Storage may be cleared by the UA under storage pressure.");
|
||||
}
|
||||
return persistent;
|
||||
}
|
||||
|
||||
static set(key, value) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
await this.requestPersistentStorage();
|
||||
|
||||
const DBOpenRequest = window.indexedDB.open('pairdrop_store');
|
||||
DBOpenRequest.onsuccess = (e) => {
|
||||
const db = e.target.result;
|
||||
@@ -1780,7 +1815,9 @@ class PersistentStorage {
|
||||
}
|
||||
|
||||
static addRoomSecret(roomSecret) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
await this.requestPersistentStorage();
|
||||
|
||||
const DBOpenRequest = window.indexedDB.open('pairdrop_store');
|
||||
DBOpenRequest.onsuccess = (e) => {
|
||||
const db = e.target.result;
|
||||
@@ -1789,7 +1826,7 @@ class PersistentStorage {
|
||||
const objectStoreRequest = objectStore.add({'secret': roomSecret});
|
||||
objectStoreRequest.onsuccess = _ => {
|
||||
console.log(`Request successful. RoomSecret added: ${roomSecret}`);
|
||||
resolve();
|
||||
resolve(roomSecret);
|
||||
}
|
||||
}
|
||||
DBOpenRequest.onerror = (e) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cacheVersion = 'v1.6.2';
|
||||
const cacheVersion = 'v1.6.3';
|
||||
const cacheTitle = `pairdrop-cache-${cacheVersion}`;
|
||||
const urlsToCache = [
|
||||
'index.html',
|
||||
|
||||
@@ -1128,6 +1128,7 @@ x-toast {
|
||||
line-height: 24px;
|
||||
border-radius: 8px;
|
||||
pointer-events: all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
x-toast:not([show]):not(:hover) {
|
||||
|
||||
@@ -87,12 +87,16 @@ class PeersUI {
|
||||
if (newDisplayName === savedDisplayName) return;
|
||||
|
||||
if (newDisplayName) {
|
||||
PersistentStorage.set('editedDisplayName', newDisplayName).then(_ => {
|
||||
PersistentStorage.set('editedDisplayName', newDisplayName).then(async _ => {
|
||||
const persistent = await PersistentStorage.isStoragePersistent();
|
||||
if (!persistent) {
|
||||
throw ErrorEvent("Storage not persistent.")
|
||||
}
|
||||
Events.fire('notify-user', 'Device name is changed permanently.');
|
||||
}).catch(_ => {
|
||||
console.log("This browser does not support IndexedDB. Use localStorage instead.");
|
||||
localStorage.setItem('editedDisplayName', newDisplayName);
|
||||
Events.fire('notify-user', 'Device name is changed only for this session.');
|
||||
Events.fire('notify-user', 'Device name is changed for this session only.\n\nGoogle Chrome:\nSave page as bookmark or enable notifications to enable persistence.');
|
||||
}).finally(_ => {
|
||||
Events.fire('self-display-name-changed', newDisplayName);
|
||||
Events.fire('broadcast-send', {type: 'self-display-name-changed', detail: newDisplayName});
|
||||
@@ -101,7 +105,6 @@ class PeersUI {
|
||||
PersistentStorage.delete('editedDisplayName').catch(_ => {
|
||||
console.log("This browser does not support IndexedDB. Use localStorage instead.")
|
||||
localStorage.removeItem('editedDisplayName');
|
||||
Events.fire('notify-user', 'Random Display name is used again.');
|
||||
}).finally(_ => {
|
||||
Events.fire('notify-user', 'Device name is randomly generated again.');
|
||||
Events.fire('self-display-name-changed', '');
|
||||
@@ -1027,17 +1030,21 @@ class PairDeviceDialog extends Dialog {
|
||||
|
||||
_pairDeviceJoined(peerId, roomSecret) {
|
||||
this.hide();
|
||||
PersistentStorage.addRoomSecret(roomSecret).then(_ => {
|
||||
PersistentStorage.addRoomSecret(roomSecret).then(async addedRoomSecret => {
|
||||
const persistent = await PersistentStorage.isStoragePersistent();
|
||||
if (!persistent) {
|
||||
throw ErrorEvent("Storage not persistent.")
|
||||
}
|
||||
Events.fire('notify-user', 'Devices paired successfully.');
|
||||
const oldRoomSecret = $(peerId).ui.roomSecret;
|
||||
if (oldRoomSecret) PersistentStorage.deleteRoomSecret(oldRoomSecret);
|
||||
$(peerId).ui.roomSecret = roomSecret;
|
||||
this._evaluateNumberRoomSecrets();
|
||||
if (oldRoomSecret) await PersistentStorage.deleteRoomSecret(oldRoomSecret);
|
||||
$(peerId).ui.roomSecret = addedRoomSecret;
|
||||
}).finally(_ => {
|
||||
this._evaluateNumberRoomSecrets();
|
||||
this._cleanUp();
|
||||
})
|
||||
.catch(_ => {
|
||||
Events.fire('notify-user', 'Paired devices are not persistent.');
|
||||
Events.fire('notify-user', 'Paired device is saved for this session only.\n\nGoogle Chrome:\nSave page as bookmark or enable notifications to enable persistence.');
|
||||
PersistentStorage.logBrowserNotCapable();
|
||||
});
|
||||
}
|
||||
@@ -1460,6 +1467,15 @@ class Notifications {
|
||||
return;
|
||||
}
|
||||
Events.fire('notify-user', 'Notifications enabled.');
|
||||
PersistentStorage.isStoragePersistent().then(persistent => {
|
||||
if (!persistent) {
|
||||
PersistentStorage.requestPersistentStorage().then(updatedPersistence => {
|
||||
if (updatedPersistence) {
|
||||
Events.fire('notify-user', 'Successfully enabled persistent storage.')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.$button.setAttribute('hidden', 1);
|
||||
});
|
||||
}
|
||||
@@ -1722,8 +1738,27 @@ class PersistentStorage {
|
||||
console.log("This browser does not support IndexedDB. Paired devices will be gone after the browser is closed.");
|
||||
}
|
||||
|
||||
static async isStoragePersistent() {
|
||||
return await navigator.storage.persisted();
|
||||
}
|
||||
|
||||
static async requestPersistentStorage() {
|
||||
if (!navigator.storage || !navigator.storage.persist) return false;
|
||||
if (await this.isStoragePersistent()) return true;
|
||||
|
||||
const persistent = await navigator.storage.persist()
|
||||
if (persistent) {
|
||||
console.log("Storage will not be cleared except by explicit user action");
|
||||
} else {
|
||||
console.warn("Storage may be cleared by the UA under storage pressure.");
|
||||
}
|
||||
return persistent;
|
||||
}
|
||||
|
||||
static set(key, value) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
await this.requestPersistentStorage();
|
||||
|
||||
const DBOpenRequest = window.indexedDB.open('pairdrop_store');
|
||||
DBOpenRequest.onsuccess = (e) => {
|
||||
const db = e.target.result;
|
||||
@@ -1780,7 +1815,9 @@ class PersistentStorage {
|
||||
}
|
||||
|
||||
static addRoomSecret(roomSecret) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
await this.requestPersistentStorage();
|
||||
|
||||
const DBOpenRequest = window.indexedDB.open('pairdrop_store');
|
||||
DBOpenRequest.onsuccess = (e) => {
|
||||
const db = e.target.result;
|
||||
@@ -1789,7 +1826,7 @@ class PersistentStorage {
|
||||
const objectStoreRequest = objectStore.add({'secret': roomSecret});
|
||||
objectStoreRequest.onsuccess = _ => {
|
||||
console.log(`Request successful. RoomSecret added: ${roomSecret}`);
|
||||
resolve();
|
||||
resolve(roomSecret);
|
||||
}
|
||||
}
|
||||
DBOpenRequest.onerror = (e) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cacheVersion = 'v1.6.2';
|
||||
const cacheVersion = 'v1.6.3';
|
||||
const cacheTitle = `pairdrop-included-ws-fallback-cache-${cacheVersion}`;
|
||||
const urlsToCache = [
|
||||
'index.html',
|
||||
|
||||
@@ -1154,6 +1154,7 @@ x-toast {
|
||||
line-height: 24px;
|
||||
border-radius: 8px;
|
||||
pointer-events: all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
x-toast:not([show]):not(:hover) {
|
||||
|
||||
Reference in New Issue
Block a user