mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-20 15:06:15 -04:00
Revert making peerId ephemeral to prevent duplication of shown peers on reconnect. Implement peerIdHash to prevent rogue users from overtaking peerIds
This commit is contained in:
parent
f34f5bd4b2
commit
cc78b34d2e
4 changed files with 88 additions and 16 deletions
|
@ -80,6 +80,7 @@ Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
|
||||||
* [Progressive Web App](https://wikipedia.org/wiki/Progressive_Web_App)
|
* [Progressive Web App](https://wikipedia.org/wiki/Progressive_Web_App)
|
||||||
* [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
|
* [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
|
||||||
* [zip.js](https://gildas-lormeau.github.io/zip.js/)
|
* [zip.js](https://gildas-lormeau.github.io/zip.js/)
|
||||||
|
* [cyrb53](https://github.com/bryc) super fast hash function
|
||||||
|
|
||||||
Have any questions? Read our [FAQ](/docs/faq.md).
|
Have any questions? Read our [FAQ](/docs/faq.md).
|
||||||
|
|
||||||
|
|
87
index.js
87
index.js
|
@ -3,6 +3,11 @@ const crypto = require('crypto')
|
||||||
const {spawn} = require('child_process')
|
const {spawn} = require('child_process')
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const parser = require('ua-parser-js');
|
||||||
|
const { uniqueNamesGenerator, animals, colors } = require('unique-names-generator');
|
||||||
|
const express = require('express');
|
||||||
|
const RateLimit = require('express-rate-limit');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
// Handle SIGINT
|
// Handle SIGINT
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
|
@ -70,10 +75,6 @@ const rtcConfig = process.env.RTC_CONFIG
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const express = require('express');
|
|
||||||
const RateLimit = require('express-rate-limit');
|
|
||||||
const http = require('http');
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
if (process.argv.includes('--rate-limit')) {
|
if (process.argv.includes('--rate-limit')) {
|
||||||
|
@ -114,9 +115,6 @@ if (process.argv.includes('--localhost-only')) {
|
||||||
server.listen(port);
|
server.listen(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parser = require('ua-parser-js');
|
|
||||||
const { uniqueNamesGenerator, animals, colors } = require('unique-names-generator');
|
|
||||||
|
|
||||||
class PairDropServer {
|
class PairDropServer {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -145,7 +143,8 @@ class PairDropServer {
|
||||||
message: {
|
message: {
|
||||||
displayName: peer.name.displayName,
|
displayName: peer.name.displayName,
|
||||||
deviceName: peer.name.deviceName,
|
deviceName: peer.name.deviceName,
|
||||||
peerId: peer.id
|
peerId: peer.id,
|
||||||
|
peerIdHash: peer.id.hashCode128BitSalted()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -477,7 +476,7 @@ class Peer {
|
||||||
this._setIP(request);
|
this._setIP(request);
|
||||||
|
|
||||||
// set peer id
|
// set peer id
|
||||||
this.id = crypto.randomUUID();
|
this._setPeerId(request)
|
||||||
|
|
||||||
// is WebRTC supported ?
|
// is WebRTC supported ?
|
||||||
this.rtcSupported = request.url.indexOf('webrtc') > -1;
|
this.rtcSupported = request.url.indexOf('webrtc') > -1;
|
||||||
|
@ -549,6 +548,17 @@ class Peer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setPeerId(request) {
|
||||||
|
const searchParams = new URL(request.url, "http://server").searchParams;
|
||||||
|
let peerId = searchParams.get("peer_id");
|
||||||
|
let peerIdHash = searchParams.get("peer_id_hash");
|
||||||
|
if (peerId && Peer.isValidUuid(peerId) && this.isPeerIdHashValid(peerId, peerIdHash)) {
|
||||||
|
this.id = peerId;
|
||||||
|
} else {
|
||||||
|
this.id = crypto.randomUUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
|
return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
|
||||||
}
|
}
|
||||||
|
@ -602,6 +612,10 @@ class Peer {
|
||||||
return /^([0-9]|[a-f]){8}-(([0-9]|[a-f]){4}-){3}([0-9]|[a-f]){12}$/.test(uuid);
|
return /^([0-9]|[a-f]){8}-(([0-9]|[a-f]){4}-){3}([0-9]|[a-f]){12}$/.test(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isPeerIdHashValid(peerId, peerIdHash) {
|
||||||
|
return peerIdHash === peerId.hashCode128BitSalted();
|
||||||
|
}
|
||||||
|
|
||||||
addRoomSecret(roomSecret) {
|
addRoomSecret(roomSecret) {
|
||||||
if (!(roomSecret in this.roomSecrets)) {
|
if (!(roomSecret in this.roomSecrets)) {
|
||||||
this.roomSecrets.push(roomSecret);
|
this.roomSecrets.push(roomSecret);
|
||||||
|
@ -617,14 +631,55 @@ class Peer {
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'hashCode', {
|
Object.defineProperty(String.prototype, 'hashCode', {
|
||||||
value: function() {
|
value: function() {
|
||||||
var hash = 0, i, chr;
|
return cyrb53(this);
|
||||||
for (i = 0; i < this.length; i++) {
|
|
||||||
chr = this.charCodeAt(i);
|
|
||||||
hash = ((hash << 5) - hash) + chr;
|
|
||||||
hash |= 0; // Convert to 32bit integer
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(String.prototype, 'hashCode128BitSalted', {
|
||||||
|
value: function() {
|
||||||
|
return hasher.hashCode128BitSalted(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasher = (() => {
|
||||||
|
let seeds;
|
||||||
|
return {
|
||||||
|
hashCode128BitSalted(str) {
|
||||||
|
if (!seeds) {
|
||||||
|
// seeds are created on first call to salt hash.
|
||||||
|
seeds = [4];
|
||||||
|
for (let i=0; i<4; i++) {
|
||||||
|
const randomBuffer = new Uint32Array(1);
|
||||||
|
crypto.webcrypto.getRandomValues(randomBuffer);
|
||||||
|
seeds[i] = randomBuffer[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let hashCode = "";
|
||||||
|
for (let i=0; i<4; i++) {
|
||||||
|
hashCode += cyrb53(str, seeds[i]);
|
||||||
|
}
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})()
|
||||||
|
|
||||||
|
/*
|
||||||
|
cyrb53 (c) 2018 bryc (github.com/bryc)
|
||||||
|
A fast and simple hash function with decent collision resistance.
|
||||||
|
Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity.
|
||||||
|
Public domain. Attribution appreciated.
|
||||||
|
*/
|
||||||
|
const cyrb53 = function(str, seed = 0) {
|
||||||
|
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||||
|
for (let i = 0, ch; i < str.length; i++) {
|
||||||
|
ch = str.charCodeAt(i);
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
|
||||||
|
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
|
||||||
|
return 4294967296 * (2097151 & h2) + (h1>>>0);
|
||||||
|
};
|
||||||
|
|
||||||
new PairDropServer();
|
new PairDropServer();
|
||||||
|
|
|
@ -118,6 +118,8 @@ class ServerConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDisplayName(msg) {
|
_onDisplayName(msg) {
|
||||||
|
sessionStorage.setItem("peerId", msg.message.peerId);
|
||||||
|
sessionStorage.setItem("peerIdHash", msg.message.peerIdHash);
|
||||||
Events.fire('display-name', msg);
|
Events.fire('display-name', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +128,12 @@ class ServerConnection {
|
||||||
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
||||||
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
||||||
let ws_url = new URL(protocol + '://' + location.host + location.pathname + 'server' + webrtc);
|
let ws_url = new URL(protocol + '://' + location.host + location.pathname + 'server' + webrtc);
|
||||||
|
const peerId = sessionStorage.getItem("peerId");
|
||||||
|
const peerIdHash = sessionStorage.getItem("peerIdHash");
|
||||||
|
if (peerId && peerIdHash) {
|
||||||
|
ws_url.searchParams.append('peer_id', peerId);
|
||||||
|
ws_url.searchParams.append('peer_id_hash', peerIdHash);
|
||||||
|
}
|
||||||
return ws_url.toString();
|
return ws_url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,8 @@ class ServerConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDisplayName(msg) {
|
_onDisplayName(msg) {
|
||||||
|
sessionStorage.setItem("peerId", msg.message.peerId);
|
||||||
|
sessionStorage.setItem("peerIdHash", msg.message.peerIdHash);
|
||||||
Events.fire('display-name', msg);
|
Events.fire('display-name', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +139,12 @@ class ServerConnection {
|
||||||
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
||||||
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
||||||
let ws_url = new URL(protocol + '://' + location.host + location.pathname + 'server' + webrtc);
|
let ws_url = new URL(protocol + '://' + location.host + location.pathname + 'server' + webrtc);
|
||||||
|
const peerId = sessionStorage.getItem("peerId");
|
||||||
|
const peerIdHash = sessionStorage.getItem("peerIdHash");
|
||||||
|
if (peerId && peerIdHash) {
|
||||||
|
ws_url.searchParams.append('peer_id', peerId);
|
||||||
|
ws_url.searchParams.append('peer_id_hash', peerIdHash);
|
||||||
|
}
|
||||||
return ws_url.toString();
|
return ws_url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue