mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-22 07:46:17 -04:00
Merge branch 'master' into translate
This commit is contained in:
commit
c36c8dae59
14 changed files with 324 additions and 186 deletions
11
.github/ISSUE_TEMPLATE/bug-report.md
vendored
11
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Create a report to help us improve. Please check the FAQ first.
|
about: Create a report to help us improve. Please check the FAQ first.
|
||||||
title: 'Bug:/Enhancement:/Feature Request: '
|
title: '[Bug] '
|
||||||
labels: ''
|
labels: 'bug'
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -34,12 +34,17 @@ If applicable, add screenshots to help explain your problem.
|
||||||
- Browser [e.g. stock browser, safari]
|
- Browser [e.g. stock browser, safari]
|
||||||
- Version [e.g. 22]
|
- Version [e.g. 22]
|
||||||
|
|
||||||
**Self-Hosted**
|
**Bug occurs on official PairDrop instance https://pairdrop.net/**
|
||||||
|
No | Yes
|
||||||
|
Version: v1.7.7
|
||||||
|
|
||||||
|
**Bug occurs on self-hosted PairDrop instance**
|
||||||
No | Yes
|
No | Yes
|
||||||
|
|
||||||
**Self-Hosted Setup**
|
**Self-Hosted Setup**
|
||||||
Proxy: Nginx | Apache2
|
Proxy: Nginx | Apache2
|
||||||
Deployment: docker run | docker-compose | npm run start:prod
|
Deployment: docker run | docker-compose | npm run start:prod
|
||||||
|
Version: v1.7.7
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
|
20
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: Enhancement
|
||||||
|
about: Enhancements and feature requests are always welcome. See discussions regarding central topics.
|
||||||
|
title: '[Enhancement] '
|
||||||
|
labels: 'enhancement'
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What problem is solved by the new feature**
|
||||||
|
What's the motivation for this topic
|
||||||
|
|
||||||
|
**Describe the feature**
|
||||||
|
A clear and concise description of what the new feature/enhancement is.
|
||||||
|
|
||||||
|
**Drafts**
|
||||||
|
Screenshots of Draw.io graph or drawn sketch.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context here.
|
|
@ -2,42 +2,46 @@
|
||||||
|
|
||||||
## Healthcheck
|
## Healthcheck
|
||||||
|
|
||||||
The [Docker Image](../Dockerfile) includes a Healthcheck with the following options:
|
The [Docker Image](../Dockerfile) includes a health check with the following options:
|
||||||
|
|
||||||
```
|
```
|
||||||
--interval=30s
|
--interval=30s
|
||||||
```
|
```
|
||||||
> Specifies the time interval at which the health check should be performed. In this case, the health check will be performed every 30 seconds.
|
> Specifies the time interval to run the health check. \
|
||||||
|
> In this case, the health check is performed every 30 seconds.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
```
|
```
|
||||||
--timeout=10s
|
--timeout=10s
|
||||||
```
|
```
|
||||||
> Specifies the amount of time to wait for a response from the health check command. If the response does not arrive within 10 seconds, the health check will be considered a failure.
|
> Specifies the amount of time to wait for a response from the \"HEALTHCHECK\" command. \
|
||||||
|
> If the response does not arrive within 10 seconds, the health check fails.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
```
|
```
|
||||||
--start-period=5s
|
--start-period=5s
|
||||||
```
|
```
|
||||||
> Specifies the amount of time to wait before starting the health check process. In this case, the health check process will begin 5 seconds after the container is started.
|
> Specifies the amount of time to wait before starting the health check process. \
|
||||||
|
> In this case, the health check process will begin 5 seconds after the container is started.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
```
|
```
|
||||||
--retries=3
|
--retries=3
|
||||||
```
|
```
|
||||||
> Specifies the number of times Docker should retry the health check before considering the container to be unhealthy.
|
> Specifies the number of times Docker should retry the health check \
|
||||||
|
> before considering the container to be unhealthy.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
||||||
The CMD instruction is used to define the command that will be run as part of the health check.
|
The CMD instruction is used to define the command that will be run as part of the health check. \
|
||||||
In this case, the command is `wget --quiet --tries=1 --spider http://localhost:3000/ || exit 1`. This command will attempt to connect to `http://localhost:3000/`
|
In this case, the command is `wget --quiet --tries=1 --spider http://localhost:3000/ || exit 1`. \
|
||||||
and if it fails it will exit with a status code of `1`. If this command returns a status code other than `0`, the health check will be considered a failure.
|
This command will attempt to connect to `http://localhost:3000/` \
|
||||||
|
and if it fails it will exit with a status code of `1`. \
|
||||||
|
If this command returns a status code other than `0`, the health check fails.
|
||||||
|
|
||||||
Overall, this HEALTHCHECK instruction is defining a health check process that will run every 30 seconds, wait up to 10 seconds for a response,
|
Overall, this \"HEALTHCHECK\" instruction is defining a health check process \
|
||||||
begin 5 seconds after the container is started, and retry up to 3 times.
|
that runs every 30 seconds, and waits up to 10 seconds for a response, \
|
||||||
The health check will consist of attempting to connect to http://localhost:3000/ and will consider the container to be unhealthy if it is unable to connect.
|
begins 5 seconds after the container is started, and retries up to 3 times. \
|
||||||
|
The health check attempts to connect to http://localhost:3000/ \
|
||||||
|
and will considers the container unhealthy if unable to connect.
|
||||||
|
|
||||||
|
|
124
docs/faq.md
124
docs/faq.md
|
@ -5,20 +5,18 @@
|
||||||
Help! I can't install the PWA!
|
Help! I can't install the PWA!
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
if you are using a Chromium-based browser (Chrome, Edge, Brave, etc.), you can easily install PairDrop PWA on your desktop
|
if you are using a Chromium-based browser (Chrome, Edge, Vivaldi, Brave, etc.), you can easily install PairDrop PWA on your desktop
|
||||||
by clicking the install-button in the top-right corner while on [pairdrop.net](https://pairdrop.net).
|
by clicking the install-button in the top-right corner while on [pairdrop.net](https://pairdrop.net).
|
||||||
|
|
||||||
<img width="400" src="pwa-install.png" alt="Example on how to install a pwa with Edge">
|
<img width="400" src="pwa-install.png" alt="Example on how to install a pwa with Edge">
|
||||||
|
|
||||||
On Firefox, PWAs are installable via [this browser extensions](https://addons.mozilla.org/de/firefox/addon/pwas-for-firefox/)
|
On Firefox, PWAs are installable via [this browser extensions](https://addons.mozilla.org/de/firefox/addon/pwas-for-firefox/)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<b>Self-Hosted Instance?</b>
|
<b>Self-Hosted Instance?</b>
|
||||||
|
|
||||||
To be able to install the PWA from a self-hosted instance, the connection needs to be [established through HTTPS](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Installable_PWAs).
|
To be able to install the PWA from a self-hosted instance, the connection needs to be [established through HTTPS](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Installable_PWAs).
|
||||||
See [this host your own section](https://github.com/schlagmichdoch/PairDrop/blob/master/docs/host-your-own.md#testing-pwa-related-features) for more information.
|
See [this host your own section](https://github.com/schlagmichdoch/PairDrop/blob/master/docs/host-your-own.md#testing-pwa-related-features) for more info.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -28,12 +26,11 @@ See [this host your own section](https://github.com/schlagmichdoch/PairDrop/blob
|
||||||
Shortcuts?
|
Shortcuts?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Shortcuts!
|
Shortcuts
|
||||||
- Send a message with `CTRL + ENTER`
|
- Send a message with `CTRL + ENTER`
|
||||||
- Close all send and pair dialogs by pressing `Escape`.
|
- Close all "Send" and "Pair" dialogs by pressing `Esc`.
|
||||||
- Copy a received message to clipboard with `CTRL/⌘ + C`.
|
- Copy a received message to the clipboard with `CTRL/⌘ + C`.
|
||||||
- Accept file transfer request with `Enter` and decline with `Escape`.
|
- Accept file-transfer requests with `Enter` and decline with `Esc`.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -44,28 +41,24 @@ Shortcuts!
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Apparently, iOS does not allow images shared from a website to be saved to the gallery directly.
|
Apparently, iOS does not allow images shared from a website to be saved to the gallery directly.
|
||||||
It simply does not offer the option for images shared from a website.
|
It simply does not offer that option for images shared from a website.
|
||||||
|
|
||||||
iOS Shortcuts to the win:
|
iOS Shortcuts saves the day:
|
||||||
I created a simple iOS shortcut that takes your photos and saves them to your gallery:
|
I created a simple iOS shortcut that takes your photos and saves them to your gallery:
|
||||||
https://routinehub.co/shortcut/13988/
|
https://routinehub.co/shortcut/13988/
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
Is it possible to send files or text directly from the context or share menu?
|
Is it possible to send files or text directly from the "Context" or "Share" menu?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Yes, it finally is!
|
Yes, it finally is.
|
||||||
* [Send files directly from context menu on Windows](/docs/how-to.md#send-files-directly-from-context-menu-on-windows)
|
* [Send files directly from the "Context" menu on Windows](/docs/how-to.md#send-files-directly-from-context-menu-on-windows)
|
||||||
* [Send directly from share menu on iOS](/docs/how-to.md#send-directly-from-share-menu-on-ios)
|
* [Send directly from the "Share" menu on iOS](/docs/how-to.md#send-directly-from-share-menu-on-ios)
|
||||||
* [Send directly from share menu on Android](/docs/how-to.md#send-directly-from-share-menu-on-android)
|
* [Send directly from the "Share" menu on Android](/docs/how-to.md#send-directly-from-share-menu-on-android)
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -75,71 +68,81 @@ Yes, it finally is!
|
||||||
Is it possible to send files or text directly via CLI?
|
Is it possible to send files or text directly via CLI?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Yes, it is!
|
Yes.
|
||||||
|
|
||||||
* [Send directly from command-line interface](/docs/how-to.md#send-directly-via-command-line-interface)
|
|
||||||
|
|
||||||
|
|
||||||
|
* [Send directly from a command-line interface](/docs/how-to.md#send-directly-via-command-line-interface)
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
Are there any Third-Party Apps?
|
Are there any third-party Apps?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Here's a list of some third-party apps compatible with PairDrop:
|
These third-party apps are compatible with PairDrop:
|
||||||
|
|
||||||
1. [Snapdrop Android App](https://github.com/fm-sys/snapdrop-android)
|
1. [Snapdrop Android App](https://github.com/fm-sys/snapdrop-android)
|
||||||
2. [Snapdrop for Firefox (Addon)](https://github.com/ueen/SnapdropFirefoxAddon)
|
2. [Snapdrop for Firefox (Addon)](https://github.com/ueen/SnapdropFirefoxAddon)
|
||||||
3. Feel free to make one :)
|
3. Feel free to make one :)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
What about the connection? Is it a P2P-connection directly from device to device or is there any third-party-server?
|
What about the connection? Is it a P2P connection directly from device to device or is there any third-party-server?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
It uses a WebRTC peer to peer connection. WebRTC needs a Signaling Server that is only used to establish a connection. The server is not involved in the file transfer.
|
It uses a WebRTC peer-to-peer connection.
|
||||||
|
WebRTC needs a signaling server that is only used to establish a connection.
|
||||||
|
The server is not involved in the file transfer.
|
||||||
|
|
||||||
If devices are on the same network, none of your files are ever sent to any server.
|
If the devices are on the same network,
|
||||||
|
none of your files are ever sent to any server.
|
||||||
|
|
||||||
If your devices are paired and behind a NAT, the PairDrop TURN Server is used to route your files and messages. See the [Technical Documentation](technical-documentation.md#encryption-webrtc-stun-and-turn) to learn more about STUN, TURN and WebRTC.
|
If your devices are paired and behind a NAT,
|
||||||
|
the PairDrop TURN Server is used to route your files and messages.
|
||||||
If you host your own instance and want to support devices that do not support WebRTC, you can [start the PairDrop instance with an activated Websocket fallback](https://github.com/schlagmichdoch/PairDrop/blob/master/docs/host-your-own.md#websocket-fallback-for-vpn).
|
See the [Technical Documentation](technical-documentation.md#encryption-webrtc-stun-and-turn)
|
||||||
|
to learn more about STUN, TURN and WebRTC.
|
||||||
|
|
||||||
|
If you host your own instance
|
||||||
|
and want to support devices that do not support WebRTC,
|
||||||
|
you can [start the PairDrop instance with an activated WebSocket fallback](https://github.com/schlagmichdoch/PairDrop/blob/master/docs/host-your-own.md#websocket-fallback-for-vpn).
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
What about privacy? Will files be saved on third-party-servers?
|
What about privacy? Will files be saved on third-party servers?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Files are sent directly between peers. PairDrop doesn't even use a database. If you are curious, have a look [at the Server](https://github.com/schlagmichdoch/pairdrop/blob/master/index.js).
|
Files are sent directly between peers.
|
||||||
WebRTC encrypts the files on transit.
|
PairDrop doesn't even use a database.
|
||||||
|
If curious, study [the server](https://github.com/schlagmichdoch/pairdrop/blob/master/index.js).
|
||||||
|
WebRTC encrypts the files in transit.
|
||||||
|
|
||||||
If devices are on the same network, none of your files are ever sent to any server.
|
If the devices are on the same network,
|
||||||
|
none of your files are ever sent to any server.
|
||||||
If your devices are paired and behind a NAT, the PairDrop TURN Server is used to route your files and messages. See the [Technical Documentation](technical-documentation.md#encryption-webrtc-stun-and-turn) to learn more about STUN, TURN and WebRTC.
|
|
||||||
|
|
||||||
|
If your devices are paired and behind a NAT,
|
||||||
|
the PairDrop TURN Server is used to route your files and messages.
|
||||||
|
See the [Technical Documentation](technical-documentation.md#encryption-webrtc-stun-and-turn)
|
||||||
|
to learn more about STUN, TURN and WebRTC.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
What about security? Are my files encrypted while being sent between the computers?
|
What about security? Are my files encrypted while sent between the computers?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Yes. Your files are sent using WebRTC, which encrypts them on transit. To ensure the connection is secure and there is no MITM, compare the security number shown under the device name on both devices. The security number is different for every connection.
|
Yes. Your files are sent using WebRTC, encrypting them in transit.
|
||||||
|
To ensure the connection is secure and there is no [MITM](https://wikiless.org/wiki/Man-in-the-middle_attack),
|
||||||
|
compare the security number shown under the device name on both devices.
|
||||||
|
The security number is different for every connection.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -149,18 +152,18 @@ Yes. Your files are sent using WebRTC, which encrypts them on transit. To ensure
|
||||||
Transferring many files with paired devices takes too long
|
Transferring many files with paired devices takes too long
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Naturally, if traffic needs to be routed through the turn server because your devices are behind different NATs, transfer speed decreases.
|
Naturally, if traffic needs to be routed through the TURN server
|
||||||
|
because your devices are behind different NATs, transfer speed decreases.
|
||||||
|
|
||||||
You can open a hotspot on one of your devices to bridge the connection which omits the need of the TURN server.
|
You can open a hotspot on one of your devices to bridge the connection,
|
||||||
|
which omits the need of the TURN server.
|
||||||
|
|
||||||
- [How to open a hotspot on Windows](https://support.microsoft.com/en-us/windows/use-your-windows-pc-as-a-mobile-hotspot-c89b0fad-72d5-41e8-f7ea-406ad9036b85#WindowsVersion=Windows_11)
|
- [How to open a hotspot on Windows](https://support.microsoft.com/en-us/windows/use-your-windows-pc-as-a-mobile-hotspot-c89b0fad-72d5-41e8-f7ea-406ad9036b85#WindowsVersion=Windows_11)
|
||||||
- [How to open a hotspot on Mac](https://support.apple.com/guide/mac-help/share-internet-connection-mac-network-users-mchlp1540/mac)
|
- [How to open a hotspot on macOS](https://support.apple.com/guide/mac-help/share-internet-connection-mac-network-users-mchlp1540/mac)
|
||||||
- [Library to open a hotspot on Linux](https://github.com/lakinduakash/linux-wifi-hotspot)
|
- [Library to open a hotspot on Linux](https://github.com/lakinduakash/linux-wifi-hotspot)
|
||||||
|
|
||||||
You can also use mobile hotspots on phones to do that.
|
You can also use mobile hotspots on phones to do that.
|
||||||
Then, all data should be sent directly between devices and your data plan should not be charged.
|
Then, all data should be sent directly between devices and not use your data plan.
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -170,10 +173,16 @@ Then, all data should be sent directly between devices and your data plan should
|
||||||
Why don't you implement feature xyz?
|
Why don't you implement feature xyz?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Snapdrop and PairDrop are a study in radical simplicity. The user interface is insanely simple. Features are chosen very carefully because complexity grows quadratically since every feature potentially interferes with each other feature. We focus very narrowly on a single use case: instant file transfer.
|
Snapdrop and PairDrop are a study in radical simplicity.
|
||||||
We are not trying to optimize for some edge-cases. We are optimizing the user flow of the average users. Don't be sad if we decline your feature request for the sake of simplicity.
|
The user interface is insanely simple.
|
||||||
|
Features are chosen very carefully because complexity grows quadratically
|
||||||
|
since every feature potentially interferes with each other feature.
|
||||||
|
We focus very narrowly on a single use case: instant file transfer.
|
||||||
|
Not facilitating optimal edge-cases means better flow for average users.
|
||||||
|
Don't be sad. We may decline your feature request for the sake of simplicity.
|
||||||
|
|
||||||
If you want to learn more about simplicity you can read *Insanely Simple: The Obsession that Drives Apple's Success* or *Thinking, Fast and Slow*.
|
Read *Insanely Simple: The Obsession that Drives Apple's Success*,
|
||||||
|
and/or *Thinking, Fast and Slow* to learn more.
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
@ -182,17 +191,15 @@ If you want to learn more about simplicity you can read *Insanely Simple: The Ob
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
<summary style="font-size:1.25em;margin-top: 24px; margin-bottom: 16px; font-weight: var(--base-text-weight-semibold, 600); line-height: 1.25;">
|
||||||
Snapdrop and PairDrop are awesome! How can I support them?
|
Snapdrop and PairDrop are awesome. How can I support them?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
* [Buy me a coffee](https://www.buymeacoffee.com/pairdrop) to pay for the domain and the server, and support open source software
|
* [Buy me a coffee](https://www.buymeacoffee.com/pairdrop) to pay for the domain and the server, and support libre software.
|
||||||
* [File bugs, give feedback, submit suggestions](https://github.com/schlagmichdoch/pairdrop/issues)
|
* [File bugs, give feedback, submit suggestions](https://github.com/schlagmichdoch/pairdrop/issues)
|
||||||
* Share PairDrop on social media.
|
* Share PairDrop on social media.
|
||||||
* Fix bugs and make a pull request.
|
* Fix bugs and make a pull request.
|
||||||
* Do security analysis and suggestions
|
* Do some security analysis and make suggestions.
|
||||||
* To support the original Snapdrop and its creator go to [his GitHub page](https://github.com/RobinLinus/snapdrop)
|
* To support the original Snapdrop and its creator go to [his GitHub page](https://github.com/RobinLinus/snapdrop)
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -202,8 +209,7 @@ If you want to learn more about simplicity you can read *Insanely Simple: The Ob
|
||||||
How does it work?
|
How does it work?
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
[See here for Information about the Technical Implementation](/docs/technical-documentation.md)
|
[See here for info about the technical implementation](/docs/technical-documentation.md)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
|
@ -3,9 +3,14 @@ The easiest way to get PairDrop up and running is by using Docker.
|
||||||
|
|
||||||
> <b>TURN server for Internet Transfer</b>
|
> <b>TURN server for Internet Transfer</b>
|
||||||
>
|
>
|
||||||
> Beware that you have to host your own TURN server in order to enable transfers between different networks.
|
> Beware that you have to host your own TURN server to enable transfers between different networks.
|
||||||
>
|
>
|
||||||
> You can follow [this guide](https://gabrieltanner.org/blog/turn-server/) to either install coturn directly on your system (Step 1) or deploy it via docker-compose (Step 5).
|
> Follow [this guide](https://gabrieltanner.org/blog/turn-server/) to either install coturn directly on your system (Step 1) \
|
||||||
|
> or deploy it via docker-compose (Step 5).
|
||||||
|
|
||||||
|
> <b>PairDrop via HTTPS</b>
|
||||||
|
>
|
||||||
|
> On some browsers PairDrop must be served over TLS in order for some feautures to work properly. These may include copying an incoming message via the 'copy' button, installing PairDrop as PWA, persistent pairing of devices and changing of the display name, and notifications. Naturally, this is also recommended to increase security.
|
||||||
|
|
||||||
## Deployment with Docker
|
## Deployment with Docker
|
||||||
|
|
||||||
|
@ -15,9 +20,11 @@ The easiest way to get PairDrop up and running is by using Docker.
|
||||||
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 lscr.io/linuxserver/pairdrop
|
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 lscr.io/linuxserver/pairdrop
|
||||||
```
|
```
|
||||||
|
|
||||||
> You must use a server proxy to set the X-Forwarded-For to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
> You must use a server proxy to set the X-Forwarded-For \
|
||||||
|
> to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
||||||
>
|
>
|
||||||
> To prevent bypassing the proxy by reaching the docker container directly, `127.0.0.1` is specified in the run command.
|
> To prevent bypassing the proxy by reaching the docker container directly, \
|
||||||
|
> `127.0.0.1` is specified in the run command.
|
||||||
|
|
||||||
#### Options / Flags
|
#### Options / Flags
|
||||||
Set options by using the following flags in the `docker run` command:
|
Set options by using the following flags in the `docker run` command:
|
||||||
|
@ -39,21 +46,30 @@ Set options by using the following flags in the `docker run` command:
|
||||||
```bash
|
```bash
|
||||||
-e IPV6_LOCALIZE=4
|
-e IPV6_LOCALIZE=4
|
||||||
```
|
```
|
||||||
> To enable Peer Discovery among IPv6 peers, you can specify a reduced number of segments of the client IPv6 address to be evaluated as the peer's IP. This can be especially useful when using Cloudflare as a proxy.
|
> To enable Peer Discovery among IPv6 peers, you can specify a reduced number of segments \
|
||||||
|
> of the client IPv6 address to be evaluated as the peer's IP. \
|
||||||
|
> This can be especially useful when using Cloudflare as a proxy.
|
||||||
>
|
>
|
||||||
> The flag must be set to an **integer** between `1` and `7`. The number represents the number of IPv6 [hextets](https://en.wikipedia.org/wiki/IPv6#Address_representation) to match the client IP against. The most common value would be `4`, which will group peers within the same `/64` subnet.
|
> The flag must be set to an **integer** between `1` and `7`. \
|
||||||
|
> The number represents the number of IPv6 [hextets](https://en.wikipedia.org/wiki/IPv6#Address_representation) \
|
||||||
|
> to match the client IP against. The most common value would be `4`, \
|
||||||
|
> which will group peers within the same `/64` subnet.
|
||||||
|
|
||||||
##### Websocket Fallback (for VPN)
|
##### Websocket Fallback (for VPN)
|
||||||
```bash
|
```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.
|
||||||
>
|
>
|
||||||
> This is not used on the official https://pairdrop.net, but you can activate it on your self-hosted instance.
|
> This is not used on the official https://pairdrop.net website, \
|
||||||
> This is especially useful if you connect to your instance via a VPN as most VPN services block WebRTC completely in order to hide your real IP address ([read more](https://privacysavvy.com/security/safe-browsing/disable-webrtc-chrome-firefox-safari-opera-edge/)).
|
> but you can activate it on your self-hosted instance.
|
||||||
|
> This is especially useful if you connect to your instance via a VPN (as most VPN services block WebRTC completely in order to hide your real IP address). ([Read more here](https://privacysavvy.com/security/safe-browsing/disable-webrtc-chrome-firefox-safari-opera-edge/)).
|
||||||
>
|
>
|
||||||
> **Warning:** All traffic sent between devices using this fallback is routed through the server and therefor not peer to peer!
|
> **Warning:** All traffic sent between devices using this fallback \
|
||||||
> Beware that the traffic routed via this fallback is readable by the server. Only ever use this on instances you can trust.
|
> is routed through the server and therefor not peer to peer! \
|
||||||
|
> 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
|
##### Specify STUN/TURN Servers
|
||||||
|
@ -61,7 +77,8 @@ Set options by using the following flags in the `docker run` command:
|
||||||
-e RTC_CONFIG="rtc_config.json"
|
-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.
|
> 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.
|
> You can use `pairdrop/rtc_config_example.json` as a starting point.
|
||||||
>
|
>
|
||||||
> To host your own TURN server you can follow this guide: https://gabrieltanner.org/blog/turn-server/
|
> To host your own TURN server you can follow this guide: https://gabrieltanner.org/blog/turn-server/
|
||||||
|
@ -83,8 +100,10 @@ Set options by using the following flags in the `docker run` command:
|
||||||
-e DEBUG_MODE="true"
|
-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)
|
> Use this flag to enable debugging information about the connecting peers IP addresses. \
|
||||||
> is configured correctly, so the auto discovery feature works correctly. Otherwise, all clients discover each other mutually, independently of their network status.
|
> 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:
|
> If this flag is set to `"true"` each peer that connects to the PairDrop server will produce a log to STDOUT like this:
|
||||||
> ```
|
> ```
|
||||||
|
@ -97,7 +116,7 @@ Set options by using the following flags in the `docker run` command:
|
||||||
> if IP is private, '127.0.0.1' is used instead
|
> if IP is private, '127.0.0.1' is used instead
|
||||||
> ----DEBUGGING-PEER-IP-END----
|
> ----DEBUGGING-PEER-IP-END----
|
||||||
> ```
|
> ```
|
||||||
> If the IP PairDrop uses is the public IP of your device everything is correctly setup.
|
> If the IP PairDrop uses is the public IP of your device, everything is set up correctly. \
|
||||||
>To find out your devices public IP visit https://www.whatismyip.com/.
|
>To find out your devices public IP visit https://www.whatismyip.com/.
|
||||||
>
|
>
|
||||||
> To preserve your clients' privacy, **never use this flag in production!**
|
> To preserve your clients' privacy, **never use this flag in production!**
|
||||||
|
@ -109,13 +128,17 @@ Set options by using the following flags in the `docker run` command:
|
||||||
```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
|
||||||
```
|
```
|
||||||
> You must use a server proxy to set the X-Forwarded-For to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
> You must use a server proxy to set the X-Forwarded-For to prevent \
|
||||||
|
> all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
||||||
>
|
>
|
||||||
> To prevent bypassing the proxy by reaching the docker container directly, `127.0.0.1` is specified in the run command.
|
> To prevent bypassing the proxy by reaching the Docker container directly, \
|
||||||
|
> `127.0.0.1` is specified in the run command.
|
||||||
>
|
>
|
||||||
> To specify options replace `npm run start:prod` according to [the documentation below.](#options--flags-1)
|
> 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. \
|
||||||
|
> Read more about [Docker Swarm Usage](docker-swarm-usage.md#docker-swarm-usage).
|
||||||
|
|
||||||
### Docker Image self-built
|
### Docker Image self-built
|
||||||
#### Build the image
|
#### Build the image
|
||||||
|
@ -130,13 +153,17 @@ docker build --pull . -f Dockerfile -t pairdrop
|
||||||
```bash
|
```bash
|
||||||
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 -it pairdrop npm run start:prod
|
docker run -d --restart=unless-stopped --name=pairdrop -p 127.0.0.1:3000:3000 -it pairdrop npm run start:prod
|
||||||
```
|
```
|
||||||
> You must use a server proxy to set the X-Forwarded-For to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
> You must use a server proxy to set the X-Forwarded-For \
|
||||||
|
> to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
||||||
>
|
>
|
||||||
> To prevent bypassing the proxy by reaching the docker container directly, `127.0.0.1` is specified in the run command.
|
> To prevent bypassing the proxy by reaching the Docker container \
|
||||||
|
> directly, `127.0.0.1` is specified in the run command.
|
||||||
>
|
>
|
||||||
> To specify options replace `npm run start:prod` according to [the documentation below.](#options--flags-1)
|
> 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. \
|
||||||
|
Read more about [Docker Swarm Usage](docker-swarm-usage.md#docker-swarm-usage).
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
@ -162,9 +189,11 @@ services:
|
||||||
|
|
||||||
Run the compose file with `docker compose up -d`.
|
Run the compose file with `docker compose up -d`.
|
||||||
|
|
||||||
> You must use a server proxy to set the X-Forwarded-For to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
> You must use a server proxy to set the X-Forwarded-For \
|
||||||
|
> to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
||||||
>
|
>
|
||||||
> To prevent bypassing the proxy by reaching the docker container directly, `127.0.0.1` is specified in the run command.
|
> To prevent bypassing the proxy by reaching the Docker container \
|
||||||
|
> directly, `127.0.0.1` is specified in the run command.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
@ -190,7 +219,7 @@ or
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
> Remember to check your IP Address using your OS command to see where you can access the server.
|
> Remember to check your IP address using your OS command to see where you can access the server.
|
||||||
|
|
||||||
> By default, the node server listens on port 3000.
|
> By default, the node server listens on port 3000.
|
||||||
|
|
||||||
|
@ -212,7 +241,8 @@ $env:PORT=3010; npm start
|
||||||
```bash
|
```bash
|
||||||
IPV6_LOCALIZE=4
|
IPV6_LOCALIZE=4
|
||||||
```
|
```
|
||||||
> Truncate a portion of the client IPv6 address to make peers more discoverable. See [Options/Flags](#options--flags) above.
|
> Truncate a portion of the client IPv6 address to make peers more discoverable. \
|
||||||
|
> See [Options/Flags](#options--flags) above.
|
||||||
|
|
||||||
#### Specify STUN/TURN Server
|
#### Specify STUN/TURN Server
|
||||||
On Unix based systems
|
On Unix based systems
|
||||||
|
@ -223,10 +253,12 @@ On Windows
|
||||||
```bash
|
```bash
|
||||||
$env:RTC_CONFIG="rtc_config.json"; npm start
|
$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.
|
> 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.
|
> You can use `pairdrop/rtc_config_example.json` as a starting point.
|
||||||
>
|
>
|
||||||
> To host your own TURN server you can follow this guide: https://gabrieltanner.org/blog/turn-server/
|
> To host your own TURN server you can follow this guide: \
|
||||||
|
> https://gabrieltanner.org/blog/turn-server/
|
||||||
>
|
>
|
||||||
> Default configuration:
|
> Default configuration:
|
||||||
> ```json
|
> ```json
|
||||||
|
@ -250,10 +282,13 @@ On Windows
|
||||||
$env:DEBUG_MODE="true"; npm start
|
$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)
|
> Use this flag to enable debugging info about the connecting peers IP addresses. \
|
||||||
> is configured correctly, so the auto discovery feature works correctly. Otherwise, all clients discover each other mutually, independently of their network status.
|
> 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:
|
> 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----
|
> ----DEBUGGING-PEER-IP-START----
|
||||||
> remoteAddress: ::ffff:172.17.0.1
|
> remoteAddress: ::ffff:172.17.0.1
|
||||||
|
@ -264,10 +299,10 @@ $env:DEBUG_MODE="true"; npm start
|
||||||
> if IP is private, '127.0.0.1' is used instead
|
> if IP is private, '127.0.0.1' is used instead
|
||||||
> ----DEBUGGING-PEER-IP-END----
|
> ----DEBUGGING-PEER-IP-END----
|
||||||
> ```
|
> ```
|
||||||
> If the IP PairDrop uses is the public IP of your device everything is correctly setup.
|
> If the IP PairDrop uses is the public IP of your device everything is set up correctly. \
|
||||||
>To find out your devices public IP visit https://www.whatismyip.com/.
|
>Find your devices public IP by visiting https://www.whatismyip.com/.
|
||||||
>
|
>
|
||||||
> To preserve your clients' privacy, **never use this flag in production!**
|
> Preserve your clients' privacy. **Never use this flag in production!**
|
||||||
|
|
||||||
|
|
||||||
### Options / Flags
|
### Options / Flags
|
||||||
|
@ -277,9 +312,11 @@ npm start -- --localhost-only
|
||||||
```
|
```
|
||||||
> Only allow connections from localhost.
|
> Only allow connections from localhost.
|
||||||
>
|
>
|
||||||
> You must use a server proxy to set the X-Forwarded-For to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
> You must use a server proxy to set the X-Forwarded-For \
|
||||||
|
> to prevent all clients from discovering each other (See [#HTTP-Server](#http-server)).
|
||||||
>
|
>
|
||||||
> Use this when deploying PairDrop with node to prevent bypassing the proxy by reaching the docker container directly.
|
> Use this when deploying PairDrop with node to prevent \
|
||||||
|
> bypassing the proxy by reaching the Docker container directly.
|
||||||
|
|
||||||
#### Automatic restart on error
|
#### Automatic restart on error
|
||||||
```bash
|
```bash
|
||||||
|
@ -301,13 +338,19 @@ npm start -- --rate-limit
|
||||||
```bash
|
```bash
|
||||||
npm start -- --include-ws-fallback
|
npm start -- --include-ws-fallback
|
||||||
```
|
```
|
||||||
> 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.
|
||||||
>
|
>
|
||||||
> This is not used on the official https://pairdrop.net, but you can activate it on your self-hosted instance.
|
> This is not used on the official https://pairdrop.net, \
|
||||||
> This is especially useful if you connect to your instance via a VPN as most VPN services block WebRTC completely in order to hide your real IP address ([read more](https://privacysavvy.com/security/safe-browsing/disable-webrtc-chrome-firefox-safari-opera-edge/)).
|
but you can activate it on your self-hosted instance. \
|
||||||
|
> This is especially useful if you connect to your instance \
|
||||||
|
> via a VPN as most VPN services block WebRTC completely in order to hide your real IP address.
|
||||||
|
> ([Read more](https://privacysavvy.com/security/safe-browsing/disable-webrtc-chrome-firefox-safari-opera-edge/)).
|
||||||
>
|
>
|
||||||
> **Warning:** All traffic sent between devices using this fallback is routed through the server and therefor not peer to peer!
|
> **Warning:** All traffic sent between devices using this fallback \
|
||||||
> Beware that the traffic routed via this fallback is readable by the server. Only ever use this on instances you can trust.
|
> is routed through the server and therefor not peer to peer! \
|
||||||
|
> 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.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
@ -321,10 +364,12 @@ npm run start:prod
|
||||||
```bash
|
```bash
|
||||||
npm run start:prod -- --localhost-only --include-ws-fallback
|
npm run start:prod -- --localhost-only --include-ws-fallback
|
||||||
```
|
```
|
||||||
> To prevent connections to the node server from bypassing the proxy server you should always use "--localhost-only" on production.
|
> To prevent connections to the node server from bypassing \
|
||||||
|
> the proxy server you should always use "--localhost-only" on production.
|
||||||
|
|
||||||
## HTTP-Server
|
## HTTP-Server
|
||||||
When running PairDrop, the `X-Forwarded-For` header has to be set by a proxy. Otherwise, all clients will be mutually visible.
|
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).
|
To check if your setup is configured correctly [use the environment variable `DEBUG_MODE="true"`](#debug-mode).
|
||||||
|
|
||||||
|
@ -405,10 +450,10 @@ a2enmod proxy_wstunnel
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
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
|
```apacheconf
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ProxyPass / http://127.0.0.1:3000/
|
ProxyPass / http://127.0.0.1:3000/
|
||||||
|
@ -425,7 +470,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||||
RewriteRule ^/?(.*) "wws://127.0.0.1:3000/$1" [P,L]
|
RewriteRule ^/?(.*) "wws://127.0.0.1:3000/$1" [P,L]
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
#### Automatic http to https redirect:
|
#### Automatic HTTP to HTTPS redirect:
|
||||||
```apacheconf
|
```apacheconf
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
Redirect permanent / https://127.0.0.1:3000/
|
Redirect permanent / https://127.0.0.1:3000/
|
||||||
|
@ -438,7 +483,7 @@ Create a new configuration file under `/etc/apache2/sites-available` (on debian)
|
||||||
RewriteRule ^/?(.*) "wws://127.0.0.1:3000/$1" [P,L]
|
RewriteRule ^/?(.*) "wws://127.0.0.1:3000/$1" [P,L]
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
Activate the new virtual host and reload apache:
|
Activate the new virtual host and reload Apache:
|
||||||
```bash
|
```bash
|
||||||
a2ensite pairdrop
|
a2ensite pairdrop
|
||||||
```
|
```
|
||||||
|
@ -462,28 +507,38 @@ Then, clone the repository and run docker-compose:
|
||||||
|
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
Now point your browser to `http://localhost:8080`.
|
Now point your web browser to `http://localhost:8080`.
|
||||||
|
|
||||||
- To restart the containers run `docker-compose restart`.
|
- To restart the containers, run `docker-compose restart`.
|
||||||
- To stop the containers run `docker-compose stop`.
|
- To stop the containers, run `docker-compose stop`.
|
||||||
- To debug the NodeJS server run `docker logs pairdrop_node_1`.
|
- To debug the NodeJS server, run `docker logs pairdrop_node_1`.
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Testing PWA related features
|
## Testing PWA related features
|
||||||
PWAs require that the app is served under a correctly set up and trusted TLS endpoint.
|
PWAs requires the app to be served under a correctly set up and trusted TLS endpoint.
|
||||||
|
|
||||||
The nginx container creates a CA certificate and a website certificate for you. To correctly set the common name of the certificate, you need to change the FQDN environment variable in `docker/fqdn.env` to the fully qualified domain name of your workstation.
|
The NGINX container creates a CA certificate and a website certificate for you. \
|
||||||
|
To correctly set the common name of the certificate, \
|
||||||
|
you need to change the FQDN environment variable in `docker/fqdn.env` \
|
||||||
|
to the fully qualified domain name of your workstation.
|
||||||
|
|
||||||
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. \
|
||||||
- On Windows, make sure to install it to the `Trusted Root Certification Authorities` store.
|
For your convenience, you can download the crt file from `http://<Your FQDN>:8080/ca.crt`. \
|
||||||
- On macOS, double-click the installed CA certificate in `Keychain Access`, expand `Trust`, and select `Always Trust` for SSL.
|
Install that certificate to the trust store of your operating system. \
|
||||||
- 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.
|
- On Windows, make sure to install it to the `Trusted Root Certification Authorities` store. \
|
||||||
- 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).
|
- 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).
|
||||||
|
|
||||||
Please note that the certificates (CA and webserver cert) expire after a day.
|
Please note that the certificates (CA and webserver cert) expire after a day.
|
||||||
Also, whenever you restart the nginx docker, container new certificates are created.
|
Also, whenever you restart the NGINX Docker, container new certificates are created.
|
||||||
|
|
||||||
The site is served on `https://<Your FQDN>:8443`.
|
The site is served on `https://<Your FQDN>:8443`.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ The [File Handling API](https://learn.microsoft.com/en-us/microsoft-edge/progres
|
||||||
|
|
||||||
This is still experimental and must be enabled via a flag **before** the PWA is installed to Windows.
|
This is still experimental and must be enabled via a flag **before** the PWA is installed to Windows.
|
||||||
1. [Enabled feature in Edge](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/handle-files#enable-the-file-handling-api)
|
1. [Enabled feature in Edge](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/handle-files#enable-the-file-handling-api)
|
||||||
2. Install PairDrop by visiting https://pairdrop.net/ with the Edge browser and install it as described [here](faq.md#help--i-cant-install-the-pwa-).
|
2. Install PairDrop by visiting https://pairdrop.net/ with the Edge web browser and install it as described [here](faq.md#help--i-cant-install-the-pwa-).
|
||||||
3. You are done! You can now send most files one at a time via PairDrop:
|
3. You are done! You can now send most files one at a time via PairDrop:
|
||||||
|
|
||||||
_context menu > Open with > PairDrop_
|
_context menu > Open with > PairDrop_
|
||||||
|
@ -13,7 +13,8 @@ This is still experimental and must be enabled via a flag **before** the PWA is
|
||||||
[//]: # (Todo: add screenshots)
|
[//]: # (Todo: add screenshots)
|
||||||
|
|
||||||
### Sending multiple files to PairDrop
|
### Sending multiple files to PairDrop
|
||||||
Outstandingly, it is also possible to send multiple files to PairDrop via the context menu by adding PairDrop to the `Send to` menu:
|
Outstandingly, it is also possible to send multiple files to PairDrop \
|
||||||
|
via the context menu by adding PairDrop to the `Send to` menu:
|
||||||
1. [Register PairDrop as file handler](#registering-to-open-files-with-pairdrop)
|
1. [Register PairDrop as file handler](#registering-to-open-files-with-pairdrop)
|
||||||
2. Hit Windows Key+R, type: `shell:programs` and hit Enter.
|
2. Hit Windows Key+R, type: `shell:programs` and hit Enter.
|
||||||
3. Copy the PairDrop shortcut from the directory
|
3. Copy the PairDrop shortcut from the directory
|
||||||
|
@ -26,7 +27,8 @@ Outstandingly, it is also possible to send multiple files to PairDrop via the co
|
||||||
[//]: # (Todo: add screenshots)
|
[//]: # (Todo: add screenshots)
|
||||||
|
|
||||||
## Send directly from share menu on iOS
|
## Send directly from share menu on iOS
|
||||||
I created an iOS shortcut to send images, files, folder, URLs or text directly from the share-menu
|
I created an iOS shortcut to send images, files, folder, URLs \
|
||||||
|
or text directly from the share-menu
|
||||||
https://routinehub.co/shortcut/13990/
|
https://routinehub.co/shortcut/13990/
|
||||||
|
|
||||||
[//]: # (Todo: add doku with screenshots)
|
[//]: # (Todo: add doku with screenshots)
|
||||||
|
@ -63,7 +65,7 @@ On Windows Command Prompt you need to use bash: `bash pairdrop -h`
|
||||||
Download the bash file: [pairdrop-cli/pairdrop](/pairdrop-cli/pairdrop).
|
Download the bash file: [pairdrop-cli/pairdrop](/pairdrop-cli/pairdrop).
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
1. Put file in a preferred folder e.g. `/usr/local/bin`
|
1. Put the file in a preferred folder e.g. `/usr/local/bin`
|
||||||
2. Make sure the bash file is executable. Otherwise, use `chmod +x pairdrop`
|
2. Make sure the bash file is executable. Otherwise, use `chmod +x pairdrop`
|
||||||
3. Add absolute path of the folder to PATH variable to make `pairdrop` available globally by executing
|
3. Add absolute path of the folder to PATH variable to make `pairdrop` available globally by executing
|
||||||
`export PATH=$PATH:/opt/pairdrop-cli`
|
`export PATH=$PATH:/opt/pairdrop-cli`
|
||||||
|
@ -74,7 +76,7 @@ Download the bash file: [pairdrop-cli/pairdrop](/pairdrop-cli/pairdrop).
|
||||||
#### Windows
|
#### Windows
|
||||||
1. Put file in a preferred folder e.g. `C:\Users\Public\pairdrop-cli`
|
1. Put file in a preferred folder e.g. `C:\Users\Public\pairdrop-cli`
|
||||||
2. Search for and open `Edit environment variables for your account`
|
2. Search for and open `Edit environment variables for your account`
|
||||||
3. Click `Environment Variables...`
|
3. Click `Environment Variables…`
|
||||||
4. Under *System Variables* select `Path` and click *Edit...*
|
4. Under *System Variables* select `Path` and click *Edit...*
|
||||||
5. Click *New*, insert the preferred folder (`C:\Users\Public\pairdrop-cli`), click *OK* until all windows are closed
|
5. Click *New*, insert the preferred folder (`C:\Users\Public\pairdrop-cli`), click *OK* until all windows are closed
|
||||||
6. Reopen Command prompt window
|
6. Reopen Command prompt window
|
||||||
|
|
|
@ -3,48 +3,80 @@
|
||||||
|
|
||||||
Encryption is mandatory for WebRTC connections and completely done by the browser itself.
|
Encryption is mandatory for WebRTC connections and completely done by the browser itself.
|
||||||
|
|
||||||
When the peers are first connecting, a channel is created by exchanging their signaling information.
|
When the peers are first connecting, \
|
||||||
This signaling information includes some sort of public key and is specific to the clients ip address.
|
a channel is created by exchanging their signaling info. \
|
||||||
That is what the STUN Server is used for: it simply returns your public IP address as you only know your local ip address
|
This signaling information includes some sort of public key \
|
||||||
|
and is specific to the clients IP address. \
|
||||||
|
That is what the STUN Server is used for: \
|
||||||
|
it simply returns your public IP address \
|
||||||
|
as you only know your local ip address \
|
||||||
if behind a NAT (router).
|
if behind a NAT (router).
|
||||||
|
|
||||||
The transfer of the signaling information is done by the PairDrop / Snapdrop server using secure websockets.
|
The transfer of the signaling info is done by the \
|
||||||
After that the channel itself is completely peer-2-peer and all information can only be decrypted by the receiver.
|
PairDrop / Snapdrop server using secure websockets. \
|
||||||
When the two peers are on the same network or when they are not behind any NAT system (which they are always for classic
|
After that the channel itself is completely peer-to-peer \
|
||||||
Snapdrop and for not paired users on PairDrop) the files are send directly peer to peer.
|
and all info can only be decrypted by the receiver. \
|
||||||
|
When the two peers are on the same network \
|
||||||
|
or when they are not behind any NAT system \
|
||||||
|
(which they are always for classic \
|
||||||
|
Snapdrop and for not paired users on PairDrop) \
|
||||||
|
the files are send directly peer-to-peer.
|
||||||
|
|
||||||
When a user is behind a NAT (behind a router) the contents are channeled through a TURN server.
|
When a user is behind a NAT (behind a router) \
|
||||||
But again, the contents send via the channel can only be decrypted by the receiver. So a rogue TURN server could only
|
the contents are channeled through a TURN server. \
|
||||||
see that there is a connection, but not what is sent. Obviously, connections which are channeled through a TURN server
|
But again, the contents send via the channel \
|
||||||
are not as fast as peer to peer.
|
can only be decrypted by the receiver. \
|
||||||
|
So a rogue TURN server could only \
|
||||||
|
see that there is a connection, but not what is sent. \
|
||||||
|
Obviously, connections which are channeled through a TURN server \
|
||||||
|
are not as fast as peer-to-peer.
|
||||||
|
|
||||||
The selection whether a TURN server is needed or not is also done automatically by the browser.
|
The selection whether a TURN server is needed \
|
||||||
It simply iterated through the configured RTC iceServers and checks what works. Only if the STUN server is not sufficient,
|
or not is also done automatically by the web browser. \
|
||||||
|
It simply iterated through the configured \
|
||||||
|
RTC iceServers and checks what works. \
|
||||||
|
Only if the STUN server is not sufficient, \
|
||||||
the TURN server is used.
|
the TURN server is used.
|
||||||
|
|
||||||

|

|
||||||
_Diagram created by wowza.com_
|
_Diagram created by wowza.com_
|
||||||
|
|
||||||
Good thing: if your device has an IPv6 address it is uniquely reachable by that address. As I understand it, when both devices are using IPv6 addresses there is no need for a TURN server in any scenario.
|
Good thing: if your device has an IPv6 address \
|
||||||
|
it is uniquely reachable by that address. \
|
||||||
|
As I understand it, when both devices are using \
|
||||||
|
IPv6 addresses there is no need for a TURN server in any scenario.
|
||||||
|
|
||||||
To learn more take a look at https://www.wowza.com/blog/webrtc-encryption-and-security which gives a good insight into stun, turn and webrtc
|
Learn more by reading https://www.wowza.com/blog/webrtc-encryption-and-security \
|
||||||
|
which gives a good insight into STUN, TURN and WebRTC.
|
||||||
|
|
||||||
|
|
||||||
## Device Pairing
|
## Device Pairing
|
||||||
|
|
||||||
The pairing functionality uses the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
|
The pairing functionality uses the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
|
||||||
|
|
||||||
It works by creating long secrets that are served by the server to the initiating and requesting pair peer,
|
It works by creating long secrets that are served \
|
||||||
when the inserted key is correct. These long secrets are then saved to an indexedDB database in the browser.
|
by the server to the initiating and requesting pair peer, \
|
||||||
IndexedDB is somewhat the successor of localStorage as saved data is shared between all tabs.
|
when the inserted key is correct. \
|
||||||
It goes one step further by making the data persistent and available offline if implemented to a PWA.
|
These long secrets are then saved to an \
|
||||||
|
indexedDB database in the web browser. \
|
||||||
|
IndexedDB is somewhat the successor of localStorage \
|
||||||
|
as saved data is shared between all tabs. \
|
||||||
|
It goes one step further by making the data persistent \
|
||||||
|
and available offline if implemented to a PWA.
|
||||||
|
|
||||||
All secrets a client has saved to its database are send to the PairDrop server. Peers with a common secret are discoverable
|
All secrets a client has saved to its database \
|
||||||
to each other analog to peers with the same ip-address are discoverable to each other.
|
are sent to the PairDrop server. \
|
||||||
|
Peers with a common secret are discoverable \
|
||||||
|
to each other analog to peers with the same \
|
||||||
|
IP address are discoverable by each other.
|
||||||
|
|
||||||
What I really like about this approach, and the reason why I implemented it, is that devices on the same network are always
|
What I really like about this approach (and the reason I implemented it) \
|
||||||
visible regardless whether any devices are paired or not. The main user flow is never obstructed. Paired devices are simply
|
is that devices on the same network are always \
|
||||||
shown additionally. This makes it in my idea better than the idea of using a room system as [discussed here](https://github.com/RobinLinus/snapdrop/pull/214).
|
visible regardless whether any devices are paired or not. \
|
||||||
|
The main user flow is never obstructed. \
|
||||||
|
Paired devices are simply shown additionally. \
|
||||||
|
This makes it in my idea better than the idea of \
|
||||||
|
using a room system as [discussed here](https://github.com/RobinLinus/snapdrop/pull/214).
|
||||||
|
|
||||||
|
|
||||||
[< Back](/README.md)
|
[< Back](/README.md)
|
||||||
|
|
20
package-lock.json
generated
20
package-lock.json
generated
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "pairdrop",
|
"name": "pairdrop",
|
||||||
"version": "1.7.6",
|
"version": "1.7.7",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pairdrop",
|
"name": "pairdrop",
|
||||||
"version": "1.7.6",
|
"version": "1.7.7",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-rate-limit": "^6.7.0",
|
"express-rate-limit": "^6.9.0",
|
||||||
"ua-parser-js": "^1.0.35",
|
"ua-parser-js": "^1.0.35",
|
||||||
"unique-names-generator": "^4.3.0",
|
"unique-names-generator": "^4.3.0",
|
||||||
"ws": "^8.13.0"
|
"ws": "^8.13.0"
|
||||||
|
@ -204,11 +204,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express-rate-limit": {
|
"node_modules/express-rate-limit": {
|
||||||
"version": "6.7.0",
|
"version": "6.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.9.0.tgz",
|
||||||
"integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
|
"integrity": "sha512-AnISR3V8qy4gpKM62/TzYdoFO9NV84fBx0POXzTryHU/qGUJBWuVGd+JhbvtVmKBv37t8/afmqdnv16xWoQxag==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.9.0"
|
"node": ">= 14.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"express": "^4 || ^5"
|
"express": "^4 || ^5"
|
||||||
|
@ -801,9 +801,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"express-rate-limit": {
|
"express-rate-limit": {
|
||||||
"version": "6.7.0",
|
"version": "6.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.9.0.tgz",
|
||||||
"integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
|
"integrity": "sha512-AnISR3V8qy4gpKM62/TzYdoFO9NV84fBx0POXzTryHU/qGUJBWuVGd+JhbvtVmKBv37t8/afmqdnv16xWoQxag==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"finalhandler": {
|
"finalhandler": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "pairdrop",
|
"name": "pairdrop",
|
||||||
"version": "1.7.6",
|
"version": "1.7.7",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-rate-limit": "^6.7.0",
|
"express-rate-limit": "^6.9.0",
|
||||||
"ua-parser-js": "^1.0.35",
|
"ua-parser-js": "^1.0.35",
|
||||||
"unique-names-generator": "^4.3.0",
|
"unique-names-generator": "^4.3.0",
|
||||||
"ws": "^8.13.0"
|
"ws": "^8.13.0"
|
||||||
|
|
|
@ -38,7 +38,10 @@ openPairDrop()
|
||||||
else
|
else
|
||||||
xdg-open "$url"
|
xdg-open "$url"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
exit
|
exit
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setOs()
|
setOs()
|
||||||
|
@ -98,13 +101,19 @@ sendFiles()
|
||||||
[[ -a "$zipPath" ]] && echo "Cannot overwrite $zipPath. Please remove first." && exit
|
[[ -a "$zipPath" ]] && echo "Cannot overwrite $zipPath. Please remove first." && exit
|
||||||
|
|
||||||
if [[ -d $path ]]; then
|
if [[ -d $path ]]; then
|
||||||
zipPathTemp="temp_${zipPath}"
|
zipPathTemp="${path}_pairdrop_temp.zip"
|
||||||
[[ -a "$zipPathTemp" ]] && echo "Cannot overwrite $zipPathTemp. Please remove first." && exit
|
[[ -a "$zipPathTemp" ]] && echo "Cannot overwrite $zipPathTemp. Please remove first." && exit
|
||||||
echo "Processing directory..."
|
echo "Processing directory..."
|
||||||
|
|
||||||
# Create zip files temporarily to send directory
|
# Create zip files temporarily to send directory
|
||||||
|
if [[ $OS == "Windows" ]];then
|
||||||
|
powershell.exe -Command "Compress-Archive -Path ${path} -DestinationPath ${zipPath}"
|
||||||
|
echo "Compress-Archive -Path ${zipPath} -DestinationPath ${zipPathTemp}"
|
||||||
|
powershell.exe -Command "Compress-Archive -Path ${zipPath} -DestinationPath ${zipPathTemp}"
|
||||||
|
else
|
||||||
zip -q -b /tmp/ -r "$zipPath" "$path"
|
zip -q -b /tmp/ -r "$zipPath" "$path"
|
||||||
zip -q -b /tmp/ "$zipPathTemp" "$zipPath"
|
zip -q -b /tmp/ "$zipPathTemp" "$zipPath"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $OS == "Mac" ]];then
|
if [[ $OS == "Mac" ]];then
|
||||||
hash=$(base64 -i "$zipPathTemp")
|
hash=$(base64 -i "$zipPathTemp")
|
||||||
|
@ -118,8 +127,12 @@ sendFiles()
|
||||||
echo "Processing file..."
|
echo "Processing file..."
|
||||||
|
|
||||||
# Create zip file temporarily to send file
|
# Create zip file temporarily to send file
|
||||||
zip -q -b /tmp/ "$zipPath" "$path"
|
|
||||||
|
|
||||||
|
if [[ $OS == "Windows" ]];then
|
||||||
|
powershell.exe -Command "Compress-Archive -Path ${path} -DestinationPath ${zipPath} -CompressionLevel Optimal"
|
||||||
|
else
|
||||||
|
zip -q -b /tmp/ "$zipPath" "$path"
|
||||||
|
fi
|
||||||
if [[ $OS == "Mac" ]];then
|
if [[ $OS == "Mac" ]];then
|
||||||
hash=$(base64 -i "$zipPath")
|
hash=$(base64 -i "$zipPath")
|
||||||
else
|
else
|
||||||
|
@ -142,6 +155,7 @@ sendFiles()
|
||||||
hash=
|
hash=
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
openPairDrop
|
openPairDrop
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
<div class="title-wrapper">
|
<div class="title-wrapper">
|
||||||
<h1>PairDrop</h1>
|
<h1>PairDrop</h1>
|
||||||
<div class="font-subheading">v1.7.6</div>
|
<div class="font-subheading">v1.7.7</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text">The easiest way to transfer files across devices</div>
|
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text">The easiest way to transfer files across devices</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const cacheVersion = 'v1.7.6';
|
const cacheVersion = 'v1.7.7';
|
||||||
const cacheTitle = `pairdrop-cache-${cacheVersion}`;
|
const cacheTitle = `pairdrop-cache-${cacheVersion}`;
|
||||||
const urlsToCache = [
|
const urlsToCache = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|
|
@ -304,7 +304,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
<div class="title-wrapper">
|
<div class="title-wrapper">
|
||||||
<h1>PairDrop</h1>
|
<h1>PairDrop</h1>
|
||||||
<div class="font-subheading">v1.7.6</div>
|
<div class="font-subheading">v1.7.7</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text">The easiest way to transfer files across devices</div>
|
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text">The easiest way to transfer files across devices</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const cacheVersion = 'v1.7.6';
|
const cacheVersion = 'v1.7.7';
|
||||||
const cacheTitle = `pairdrop-included-ws-fallback-cache-${cacheVersion}`;
|
const cacheTitle = `pairdrop-included-ws-fallback-cache-${cacheVersion}`;
|
||||||
const urlsToCache = [
|
const urlsToCache = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue