Compare commits

..

13 Commits

Author SHA1 Message Date
schlagmichdoch 43824d0de2 increase version to v1.7.7 2023-08-10 17:09:51 +02:00
schlagmichdoch 2efb531765 Merge pull request #138
Bump express-rate-limit from 6.8.0 to 6.9.0
2023-08-10 17:06:22 +02:00
schlagmichdoch d9686a6706 Merge pull request #137 from Zhongbing-Chen/master
revise the command line tool
2023-08-10 16:31:48 +02:00
dependabot[bot] 395c3e00a4 Bump express-rate-limit from 6.8.0 to 6.9.0
Bumps [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit) from 6.8.0 to 6.9.0.
- [Release notes](https://github.com/express-rate-limit/express-rate-limit/releases)
- [Changelog](https://github.com/express-rate-limit/express-rate-limit/blob/main/changelog.md)
- [Commits](https://github.com/express-rate-limit/express-rate-limit/compare/v6.8.0...v6.9.0)

---
updated-dependencies:
- dependency-name: express-rate-limit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 04:24:11 +00:00
zhongbing 8869c3c27e revise the command line tool 2023-08-06 00:47:01 +08:00
schlagmichdoch b07b8316ff Merge pull request #129 from schlagmichdoch/dependabot/npm_and_yarn/express-rate-limit-6.8.0
Bump express-rate-limit from 6.7.0 to 6.8.0
2023-07-25 18:58:11 +02:00
dependabot[bot] 445a295404 Bump express-rate-limit from 6.7.0 to 6.8.0
Bumps [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit) from 6.7.0 to 6.8.0.
- [Release notes](https://github.com/express-rate-limit/express-rate-limit/releases)
- [Changelog](https://github.com/express-rate-limit/express-rate-limit/blob/main/changelog.md)
- [Commits](https://github.com/express-rate-limit/express-rate-limit/compare/v6.7.0...v6.8.0)

---
updated-dependencies:
- dependency-name: express-rate-limit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-24 04:58:27 +00:00
schlagmichdoch 29b91cb17a increase version to v1.7.6 2023-06-01 01:51:51 +02:00
schlagmichdoch 26bf4d6dc3 ensure that otherPeers never receive peer-left after peer-joined on reconnect by leaving room before rejoining it 2023-06-01 01:49:07 +02:00
schlagmichdoch f195c686e7 increase version to v1.7.5 2023-06-01 01:32:06 +02:00
schlagmichdoch 3505f161c6 strip 'NO-BREAK SPACE' (U+00A0) of received text as some browsers seem to add them when pasting text 2023-06-01 01:29:00 +02:00
schlagmichdoch 3e2368c0c9 stabilize connection on reconnect by terminating websocket only on timeout and not always when peer leaves its ip room 2023-06-01 01:26:53 +02:00
schlagmichdoch d36cd3524c Fix clearBrowserHistory: url should not always be replaced by "/" as PairDrop might not always be hosted at domain root 2023-05-30 02:34:50 +02:00
12 changed files with 117 additions and 84 deletions
+7 -6
View File
@@ -219,10 +219,15 @@ class PairDropServer {
} }
_onDisconnect(sender) { _onDisconnect(sender) {
this._disconnect(sender);
}
_disconnect(sender) {
this._leaveRoom(sender, 'ip', '', true); this._leaveRoom(sender, 'ip', '', true);
this._leaveAllSecretRooms(sender, true); this._leaveAllSecretRooms(sender, true);
this._removeRoomKey(sender.roomKey); this._removeRoomKey(sender.roomKey);
sender.roomKey = null; sender.roomKey = null;
sender.socket.terminate();
} }
_onRoomSecrets(sender, message) { _onRoomSecrets(sender, message) {
@@ -358,6 +363,7 @@ class PairDropServer {
const room = roomType === 'ip' ? peer.ip : roomSecret; const room = roomType === 'ip' ? peer.ip : roomSecret;
if (this._rooms[room] && this._rooms[room][peer.id]) { if (this._rooms[room] && this._rooms[room][peer.id]) {
// ensures that otherPeers never receive `peer-left` after `peer-joined` on reconnect.
this._leaveRoom(peer, roomType, roomSecret); this._leaveRoom(peer, roomType, roomSecret);
} }
@@ -385,10 +391,6 @@ class PairDropServer {
// delete the peer // delete the peer
delete this._rooms[room][peer.id]; delete this._rooms[room][peer.id];
if (roomType === 'ip') {
peer.socket.terminate();
}
//if room is empty, delete the room //if room is empty, delete the room
if (!Object.keys(this._rooms[room]).length) { if (!Object.keys(this._rooms[room]).length) {
delete this._rooms[room]; delete this._rooms[room];
@@ -468,8 +470,7 @@ class PairDropServer {
peer.lastBeat = Date.now(); peer.lastBeat = Date.now();
} }
if (Date.now() - peer.lastBeat > 2 * timeout) { if (Date.now() - peer.lastBeat > 2 * timeout) {
this._leaveRoom(peer); this._disconnect(peer);
this._leaveAllSecretRooms(peer);
return; return;
} }
+10 -10
View File
@@ -1,16 +1,16 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.7.4", "version": "1.7.7",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pairdrop", "name": "pairdrop",
"version": "1.7.4", "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": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.7.4", "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"
+16 -2
View File
@@ -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
} }
+1 -1
View File
@@ -278,7 +278,7 @@
</svg> </svg>
<div class="title-wrapper"> <div class="title-wrapper">
<h1>PairDrop</h1> <h1>PairDrop</h1>
<div class="font-subheading">v1.7.4</div> <div class="font-subheading">v1.7.7</div>
</div> </div>
<div class="font-subheading">The easiest way to transfer files across devices</div> <div class="font-subheading">The easiest way to transfer files across devices</div>
<div class="row"> <div class="row">
+12 -7
View File
@@ -1024,7 +1024,8 @@ class PairDeviceDialog extends Dialog {
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('room_key')) { if (urlParams.has('room_key')) {
this._pairDeviceJoin(urlParams.get('room_key')); this._pairDeviceJoin(urlParams.get('room_key'));
window.history.replaceState({}, "title**", '/'); //remove room_key from url const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url); //remove room_key from url
} }
} }
@@ -1295,7 +1296,8 @@ class SendTextDialog extends Dialog {
} }
async _onKeyDown(e) { async _onKeyDown(e) {
if (this.isShown()) { if (!this.isShown()) return;
if (e.code === "Escape") { if (e.code === "Escape") {
this.hide(); this.hide();
} else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) { } else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) {
@@ -1303,7 +1305,6 @@ class SendTextDialog extends Dialog {
this._send(); this._send();
} }
} }
}
_textInputEmpty() { _textInputEmpty() {
return !this.$text.innerText || this.$text.innerText === "\n"; return !this.$text.innerText || this.$text.innerText === "\n";
@@ -1419,7 +1420,8 @@ class ReceiveTextDialog extends Dialog {
} }
async _onCopy() { async _onCopy() {
await navigator.clipboard.writeText(this.$text.innerText); const sanitizedText = this.$text.innerText.replace(/\u00A0/gm, ' ');
await navigator.clipboard.writeText(sanitizedText);
Events.fire('notify-user', 'Copied to clipboard'); Events.fire('notify-user', 'Copied to clipboard');
this.hide(); this.hide();
} }
@@ -1575,7 +1577,8 @@ class Base64ZipDialog extends Dialog {
} }
clearBrowserHistory() { clearBrowserHistory() {
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
hide() { hide() {
@@ -1791,7 +1794,8 @@ class WebShareTargetUI {
} }
} }
} }
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
} }
} }
@@ -1815,7 +1819,8 @@ class WebFileHandlersUI {
Events.fire('activate-paste-mode', {files: files, text: ""}) Events.fire('activate-paste-mode', {files: files, text: ""})
launchParams = null; launchParams = null;
}); });
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
} }
} }
+4
View File
@@ -402,3 +402,7 @@ const cyrb53 = function(str, seed = 0) {
function onlyUnique (value, index, array) { function onlyUnique (value, index, array) {
return array.indexOf(value) === index; return array.indexOf(value) === index;
} }
function getUrlWithoutArguments() {
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
}
+12 -12
View File
@@ -1,4 +1,4 @@
const cacheVersion = 'v1.7.4'; const cacheVersion = 'v1.7.7';
const cacheTitle = `pairdrop-cache-${cacheVersion}`; const cacheTitle = `pairdrop-cache-${cacheVersion}`;
const urlsToCache = [ const urlsToCache = [
'index.html', 'index.html',
@@ -72,8 +72,7 @@ self.addEventListener('fetch', function(event) {
if (event.request.method === "POST") { if (event.request.method === "POST") {
// Requests related to Web Share Target. // Requests related to Web Share Target.
event.respondWith((async () => { event.respondWith((async () => {
let share_url = await evaluateRequestData(event.request); const share_url = await evaluateRequestData(event.request);
share_url = event.request.url + share_url;
return Response.redirect(encodeURI(share_url), 302); return Response.redirect(encodeURI(share_url), 302);
})()); })());
} else { } else {
@@ -101,15 +100,16 @@ self.addEventListener('activate', evt =>
) )
); );
const evaluateRequestData = async function (request) { const evaluateRequestData = function (request) {
return new Promise(async (resolve) => {
const formData = await request.formData(); const formData = await request.formData();
const title = formData.get("title"); const title = formData.get("title");
const text = formData.get("text"); const text = formData.get("text");
const url = formData.get("url"); const url = formData.get("url");
const files = formData.getAll("allfiles"); const files = formData.getAll("allfiles");
const pairDropUrl = request.url;
return new Promise(async (resolve) => {
if (files && files.length > 0) { if (files && files.length > 0) {
let fileObjects = []; let fileObjects = [];
for (let i=0; i<files.length; i++) { for (let i=0; i<files.length; i++) {
@@ -128,21 +128,21 @@ const evaluateRequestData = async function (request) {
const objectStoreRequest = objectStore.add(fileObjects[i]); const objectStoreRequest = objectStore.add(fileObjects[i]);
objectStoreRequest.onsuccess = _ => { objectStoreRequest.onsuccess = _ => {
if (i === fileObjects.length - 1) resolve('?share-target=files'); if (i === fileObjects.length - 1) resolve(pairDropUrl + '?share-target=files');
} }
} }
} }
DBOpenRequest.onerror = _ => { DBOpenRequest.onerror = _ => {
resolve(''); resolve(pairDropUrl);
} }
} else { } else {
let share_url = '?share-target=text'; let urlArgument = '?share-target=text';
if (title) share_url += `&title=${title}`; if (title) urlArgument += `&title=${title}`;
if (text) share_url += `&text=${text}`; if (text) urlArgument += `&text=${text}`;
if (url) share_url += `&url=${url}`; if (url) urlArgument += `&url=${url}`;
resolve(share_url); resolve(pairDropUrl + urlArgument);
} }
}); });
} }
+1 -1
View File
@@ -281,7 +281,7 @@
</svg> </svg>
<div class="title-wrapper"> <div class="title-wrapper">
<h1>PairDrop</h1> <h1>PairDrop</h1>
<div class="font-subheading">v1.7.4</div> <div class="font-subheading">v1.7.7</div>
</div> </div>
<div class="font-subheading">The easiest way to transfer files across devices</div> <div class="font-subheading">The easiest way to transfer files across devices</div>
<div class="row"> <div class="row">
+12 -7
View File
@@ -1025,7 +1025,8 @@ class PairDeviceDialog extends Dialog {
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('room_key')) { if (urlParams.has('room_key')) {
this._pairDeviceJoin(urlParams.get('room_key')); this._pairDeviceJoin(urlParams.get('room_key'));
window.history.replaceState({}, "title**", '/'); //remove room_key from url const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url); //remove room_key from url
} }
} }
@@ -1296,7 +1297,8 @@ class SendTextDialog extends Dialog {
} }
async _onKeyDown(e) { async _onKeyDown(e) {
if (this.isShown()) { if (!this.isShown()) return;
if (e.code === "Escape") { if (e.code === "Escape") {
this.hide(); this.hide();
} else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) { } else if (e.code === "Enter" && (e.ctrlKey || e.metaKey)) {
@@ -1304,7 +1306,6 @@ class SendTextDialog extends Dialog {
this._send(); this._send();
} }
} }
}
_textInputEmpty() { _textInputEmpty() {
return !this.$text.innerText || this.$text.innerText === "\n"; return !this.$text.innerText || this.$text.innerText === "\n";
@@ -1420,7 +1421,8 @@ class ReceiveTextDialog extends Dialog {
} }
async _onCopy() { async _onCopy() {
await navigator.clipboard.writeText(this.$text.innerText); const sanitizedText = this.$text.innerText.replace(/\u00A0/gm, ' ');
await navigator.clipboard.writeText(sanitizedText);
Events.fire('notify-user', 'Copied to clipboard'); Events.fire('notify-user', 'Copied to clipboard');
this.hide(); this.hide();
} }
@@ -1576,7 +1578,8 @@ class Base64ZipDialog extends Dialog {
} }
clearBrowserHistory() { clearBrowserHistory() {
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
hide() { hide() {
@@ -1792,7 +1795,8 @@ class WebShareTargetUI {
} }
} }
} }
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
} }
} }
@@ -1816,7 +1820,8 @@ class WebFileHandlersUI {
Events.fire('activate-paste-mode', {files: files, text: ""}) Events.fire('activate-paste-mode', {files: files, text: ""})
launchParams = null; launchParams = null;
}); });
window.history.replaceState({}, "Rewrite URL", '/'); const url = getUrlWithoutArguments();
window.history.replaceState({}, "Rewrite URL", url);
} }
} }
} }
@@ -403,6 +403,10 @@ function onlyUnique (value, index, array) {
return array.indexOf(value) === index; return array.indexOf(value) === index;
} }
function getUrlWithoutArguments() {
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
}
function arrayBufferToBase64(buffer) { function arrayBufferToBase64(buffer) {
var binary = ''; var binary = '';
var bytes = new Uint8Array(buffer); var bytes = new Uint8Array(buffer);
+12 -12
View File
@@ -1,4 +1,4 @@
const cacheVersion = 'v1.7.4'; 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',
@@ -72,8 +72,7 @@ self.addEventListener('fetch', function(event) {
if (event.request.method === "POST") { if (event.request.method === "POST") {
// Requests related to Web Share Target. // Requests related to Web Share Target.
event.respondWith((async () => { event.respondWith((async () => {
let share_url = await evaluateRequestData(event.request); const share_url = await evaluateRequestData(event.request);
share_url = event.request.url + share_url;
return Response.redirect(encodeURI(share_url), 302); return Response.redirect(encodeURI(share_url), 302);
})()); })());
} else { } else {
@@ -101,15 +100,16 @@ self.addEventListener('activate', evt =>
) )
); );
const evaluateRequestData = async function (request) { const evaluateRequestData = function (request) {
return new Promise(async (resolve) => {
const formData = await request.formData(); const formData = await request.formData();
const title = formData.get("title"); const title = formData.get("title");
const text = formData.get("text"); const text = formData.get("text");
const url = formData.get("url"); const url = formData.get("url");
const files = formData.getAll("allfiles"); const files = formData.getAll("allfiles");
const pairDropUrl = request.url;
return new Promise(async (resolve) => {
if (files && files.length > 0) { if (files && files.length > 0) {
let fileObjects = []; let fileObjects = [];
for (let i=0; i<files.length; i++) { for (let i=0; i<files.length; i++) {
@@ -128,21 +128,21 @@ const evaluateRequestData = async function (request) {
const objectStoreRequest = objectStore.add(fileObjects[i]); const objectStoreRequest = objectStore.add(fileObjects[i]);
objectStoreRequest.onsuccess = _ => { objectStoreRequest.onsuccess = _ => {
if (i === fileObjects.length - 1) resolve('?share-target=files'); if (i === fileObjects.length - 1) resolve(pairDropUrl + '?share-target=files');
} }
} }
} }
DBOpenRequest.onerror = _ => { DBOpenRequest.onerror = _ => {
resolve(''); resolve(pairDropUrl);
} }
} else { } else {
let share_url = '?share-target=text'; let urlArgument = '?share-target=text';
if (title) share_url += `&title=${title}`; if (title) urlArgument += `&title=${title}`;
if (text) share_url += `&text=${text}`; if (text) urlArgument += `&text=${text}`;
if (url) share_url += `&url=${url}`; if (url) urlArgument += `&url=${url}`;
resolve(share_url); resolve(pairDropUrl + urlArgument);
} }
}); });
} }