diff --git a/index.js b/index.js index bde7f98..a6133e7 100644 --- a/index.js +++ b/index.js @@ -171,6 +171,9 @@ class PairDropServer { case 'pair-device-cancel': this._onPairDeviceCancel(sender); break; + case 'regenerate-room-secret': + this._onRegenerateRoomSecret(sender, message); + break case 'resend-peers': this._notifyPeers(sender); break; @@ -205,7 +208,7 @@ class PairDropServer { _onRoomSecrets(sender, message) { const roomSecrets = message.roomSecrets.filter(roomSecret => { - return /^[\x00-\x7F]{64}$/.test(roomSecret); + return /^[\x00-\x7F]{64,256}$/.test(roomSecret); }) this._joinSecretRooms(sender, roomSecrets); } @@ -233,7 +236,7 @@ class PairDropServer { } _onPairDeviceInitiate(sender) { - let roomSecret = randomizer.getRandomString(64); + let roomSecret = randomizer.getRandomString(256); let roomKey = this._createRoomKey(sender, roomSecret); if (sender.roomKey) this._removeRoomKey(sender.roomKey); sender.roomKey = roomKey; @@ -246,16 +249,19 @@ class PairDropServer { } _onPairDeviceJoin(sender, message) { + // rate limit implementation: max 10 attempts every 10s if (sender.roomKeyRate >= 10) { this._send(sender, { type: 'pair-device-join-key-rate-limit' }); return; } sender.roomKeyRate += 1; setTimeout(_ => sender.roomKeyRate -= 1, 10000); + if (!this._roomSecrets[message.roomKey] || sender.id === this._roomSecrets[message.roomKey].creator.id) { this._send(sender, { type: 'pair-device-join-key-invalid' }); return; } + const roomSecret = this._roomSecrets[message.roomKey].roomSecret; const creator = this._roomSecrets[message.roomKey].creator; this._removeRoomKey(message.roomKey); @@ -275,14 +281,31 @@ class PairDropServer { _onPairDeviceCancel(sender) { if (sender.roomKey) { + this._removeRoomKey(sender.roomKey); this._send(sender, { type: 'pair-device-canceled', roomKey: sender.roomKey, }); - this._removeRoomKey(sender.roomKey); } } + _onRegenerateRoomSecret(sender, message) { + const oldRoomSecret = message.roomSecret; + const newRoomSecret = randomizer.getRandomString(256); + + // notify all other peers + for (const peerId in this._rooms[oldRoomSecret]) { + const peer = this._rooms[oldRoomSecret][peerId]; + this._send(peer, { + type: 'room-secret-regenerated', + oldRoomSecret: oldRoomSecret, + newRoomSecret: newRoomSecret, + }); + peer.removeRoomSecret(oldRoomSecret); + } + delete this._rooms[oldRoomSecret]; + } + _createRoomKey(creator, roomSecret) { let roomKey; do { diff --git a/public/scripts/network.js b/public/scripts/network.js index 0523be7..a66b3c8 100644 --- a/public/scripts/network.js +++ b/public/scripts/network.js @@ -12,6 +12,7 @@ class ServerConnection { if (navigator.connection) navigator.connection.addEventListener('change', _ => this._reconnect()); Events.on('room-secrets', e => this._sendRoomSecrets(e.detail)); Events.on('room-secrets-deleted', e => this.send({ type: 'room-secrets-deleted', roomSecrets: e.detail})); + Events.on('regenerate-room-secret', e => this.send({ type: 'regenerate-room-secret', roomSecret: e.detail})); Events.on('resend-peers', _ => this.send({ type: 'resend-peers'})); Events.on('pair-device-initiate', _ => this._onPairDeviceInitiate()); Events.on('pair-device-join', e => this._onPairDeviceJoin(e.detail)); @@ -105,6 +106,9 @@ class ServerConnection { case 'secret-room-deleted': Events.fire('secret-room-deleted', msg.roomSecret); break; + case 'room-secret-regenerated': + Events.fire('room-secret-regenerated', msg); + break; default: console.error('WS receive: unknown message type', msg); } @@ -808,6 +812,7 @@ class PeersManager { Events.on('peer-connected', e => this._onPeerConnected(e.detail.peerId)); Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); + Events.on('room-secret-regenerated', e => this._onRoomSecretRegenerated(e.detail)); Events.on('display-name', e => this._onDisplayName(e.detail.message.displayName)); Events.on('self-display-name-changed', e => this._notifyPeersDisplayNameChanged(e.detail)); Events.on('notify-peer-display-name-changed', e => this._notifyPeerDisplayNameChanged(e.detail)); @@ -913,6 +918,13 @@ class PeersManager { } } + _onRoomSecretRegenerated(message) { + PersistentStorage.updateRoomSecret(message.oldRoomSecret, message.newRoomSecret).then(_ => { + console.log("successfully regenerated room secret"); + Events.fire("room-secrets", [message.newRoomSecret]); + }) + } + _notifyPeersDisplayNameChanged(newDisplayName) { this._displayName = newDisplayName ? newDisplayName : this._originalDisplayName; for (const peerId in this.peers) { diff --git a/public_included_ws_fallback/scripts/network.js b/public_included_ws_fallback/scripts/network.js index f1efe33..e07e85c 100644 --- a/public_included_ws_fallback/scripts/network.js +++ b/public_included_ws_fallback/scripts/network.js @@ -104,6 +104,9 @@ class ServerConnection { case 'secret-room-deleted': Events.fire('secret-room-deleted', msg.roomSecret); break; + case 'room-secret-regenerated': + Events.fire('room-secret-regenerated', msg); + break; case 'request': case 'header': case 'partition': @@ -860,6 +863,7 @@ class PeersManager { Events.on('peer-connected', e => this._onPeerConnected(e.detail.peerId)); Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); + Events.on('room-secret-regenerated', e => this._onRoomSecretRegenerated(e.detail)); Events.on('display-name', e => this._onDisplayName(e.detail.message.displayName)); Events.on('self-display-name-changed', e => this._notifyPeersDisplayNameChanged(e.detail)); Events.on('notify-peer-display-name-changed', e => this._notifyPeerDisplayNameChanged(e.detail)); @@ -992,6 +996,13 @@ class PeersManager { } } + _onRoomSecretRegenerated(message) { + PersistentStorage.updateRoomSecret(message.oldRoomSecret, message.newRoomSecret).then(_ => { + console.log("successfully regenerated room secret"); + Events.fire("room-secrets", [message.newRoomSecret]); + }) + } + _notifyPeersDisplayNameChanged(newDisplayName) { this._displayName = newDisplayName ? newDisplayName : this._originalDisplayName; for (const peerId in this.peers) {