Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fe18722
commit 98e7e65
Showing
26 changed files
with
798 additions
and
220 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,144 @@ | ||
// Copyright 2015-2020 Signal Messenger, LLC | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
/* global libsignal, textsecure, SignalProtocolStore */ | ||
/* global libsignal, textsecure */ | ||
|
||
describe('MessageReceiver', () => { | ||
textsecure.storage.impl = new SignalProtocolStore(); | ||
const { WebSocket } = window; | ||
const number = '+19999999999'; | ||
const uuid = 'AAAAAAAA-BBBB-4CCC-9DDD-EEEEEEEEEEEE'; | ||
const deviceId = 1; | ||
const signalingKey = libsignal.crypto.getRandomBytes(32 + 20); | ||
|
||
before(() => { | ||
localStorage.clear(); | ||
window.WebSocket = MockSocket; | ||
textsecure.storage.user.setNumberAndDeviceId(number, deviceId, 'name'); | ||
textsecure.storage.user.setUuidAndDeviceId(uuid, deviceId); | ||
textsecure.storage.put('password', 'password'); | ||
textsecure.storage.put('signaling_key', signalingKey); | ||
}); | ||
after(() => { | ||
localStorage.clear(); | ||
window.WebSocket = WebSocket; | ||
}); | ||
|
||
describe('connecting', () => { | ||
const attrs = { | ||
type: textsecure.protobuf.Envelope.Type.CIPHERTEXT, | ||
source: number, | ||
sourceUuid: uuid, | ||
sourceDevice: deviceId, | ||
timestamp: Date.now(), | ||
}; | ||
const websocketmessage = new textsecure.protobuf.WebSocketMessage({ | ||
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, | ||
request: { verb: 'PUT', path: '/messages' }, | ||
}); | ||
let attrs; | ||
let websocketmessage; | ||
|
||
before(() => { | ||
attrs = { | ||
type: textsecure.protobuf.Envelope.Type.CIPHERTEXT, | ||
source: number, | ||
sourceUuid: uuid, | ||
sourceDevice: deviceId, | ||
timestamp: Date.now(), | ||
content: libsignal.crypto.getRandomBytes(200), | ||
}; | ||
const body = new textsecure.protobuf.Envelope(attrs).toArrayBuffer(); | ||
|
||
before(done => { | ||
const signal = new textsecure.protobuf.Envelope(attrs).toArrayBuffer(); | ||
|
||
const aesKey = signalingKey.slice(0, 32); | ||
const macKey = signalingKey.slice(32, 32 + 20); | ||
|
||
window.crypto.subtle | ||
.importKey('raw', aesKey, { name: 'AES-CBC' }, false, ['encrypt']) | ||
.then(key => { | ||
const iv = libsignal.crypto.getRandomBytes(16); | ||
window.crypto.subtle | ||
.encrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, key, signal) | ||
.then(ciphertext => { | ||
window.crypto.subtle | ||
.importKey( | ||
'raw', | ||
macKey, | ||
{ name: 'HMAC', hash: { name: 'SHA-256' } }, | ||
false, | ||
['sign'] | ||
) | ||
.then(innerKey => { | ||
window.crypto.subtle | ||
.sign({ name: 'HMAC', hash: 'SHA-256' }, innerKey, signal) | ||
.then(mac => { | ||
const version = new Uint8Array([1]); | ||
const message = dcodeIO.ByteBuffer.concat([ | ||
version, | ||
iv, | ||
ciphertext, | ||
mac, | ||
]); | ||
websocketmessage.request.body = message.toArrayBuffer(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
websocketmessage = new textsecure.protobuf.WebSocketMessage({ | ||
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, | ||
request: { verb: 'PUT', path: '/api/v1/message', body }, | ||
}); | ||
}); | ||
|
||
it('connects', done => { | ||
const mockServer = new MockServer( | ||
`ws://localhost:8080/v1/websocket/?login=${encodeURIComponent( | ||
uuid | ||
)}.1&password=password` | ||
); | ||
it('generates light-session-reset event when it cannot decrypt', done => { | ||
const mockServer = new MockServer('ws://localhost:8081/'); | ||
|
||
mockServer.on('connection', server => { | ||
server.send(new Blob([websocketmessage.toArrayBuffer()])); | ||
setTimeout(() => { | ||
server.send(new Blob([websocketmessage.toArrayBuffer()])); | ||
}, 1); | ||
}); | ||
|
||
window.addEventListener('textsecure:message', ev => { | ||
const signal = ev.proto; | ||
const keys = Object.keys(attrs); | ||
|
||
for (let i = 0, max = keys.length; i < max; i += 1) { | ||
const key = keys[i]; | ||
assert.strictEqual(attrs[key], signal[key]); | ||
const messageReceiver = new textsecure.MessageReceiver( | ||
'oldUsername', | ||
'username', | ||
'password', | ||
'signalingKey', | ||
{ | ||
serverTrustRoot: 'AAAAAAAA', | ||
} | ||
assert.strictEqual(signal.message.body, 'hello'); | ||
mockServer.close(); | ||
); | ||
|
||
done(); | ||
}); | ||
messageReceiver.addEventListener('light-session-reset', done()); | ||
}); | ||
}); | ||
|
||
window.messageReceiver = new textsecure.MessageReceiver( | ||
describe('methods', () => { | ||
let messageReceiver; | ||
let mockServer; | ||
|
||
beforeEach(() => { | ||
// Necessary to populate the server property inside of MockSocket. Without it, we | ||
// crash when doing any number of things to a MockSocket instance. | ||
mockServer = new MockServer('ws://localhost:8081'); | ||
|
||
messageReceiver = new textsecure.MessageReceiver( | ||
'oldUsername', | ||
'username', | ||
'password', | ||
'signalingKey' | ||
// 'ws://localhost:8080', | ||
// window, | ||
'signalingKey', | ||
{ | ||
serverTrustRoot: 'AAAAAAAA', | ||
} | ||
); | ||
}); | ||
afterEach(() => { | ||
mockServer.close(); | ||
}); | ||
|
||
describe('#isOverHourIntoPast', () => { | ||
it('returns false for now', () => { | ||
assert.isFalse(messageReceiver.isOverHourIntoPast(Date.now())); | ||
}); | ||
it('returns false for 5 minutes ago', () => { | ||
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000; | ||
assert.isFalse(messageReceiver.isOverHourIntoPast(fiveMinutesAgo)); | ||
}); | ||
it('returns true for 65 minutes ago', () => { | ||
const sixtyFiveMinutesAgo = Date.now() - 65 * 60 * 1000; | ||
assert.isTrue(messageReceiver.isOverHourIntoPast(sixtyFiveMinutesAgo)); | ||
}); | ||
}); | ||
|
||
describe('#cleanupSessionResets', () => { | ||
it('leaves empty object alone', () => { | ||
window.storage.put('sessionResets', {}); | ||
messageReceiver.cleanupSessionResets(); | ||
const actual = window.storage.get('sessionResets'); | ||
|
||
const expected = {}; | ||
assert.deepEqual(actual, expected); | ||
}); | ||
it('filters out any timestamp older than one hour', () => { | ||
const startValue = { | ||
one: Date.now() - 1, | ||
two: Date.now(), | ||
three: Date.now() - 65 * 60 * 1000, | ||
}; | ||
window.storage.put('sessionResets', startValue); | ||
messageReceiver.cleanupSessionResets(); | ||
const actual = window.storage.get('sessionResets'); | ||
|
||
const expected = window._.pick(startValue, ['one', 'two']); | ||
assert.deepEqual(actual, expected); | ||
}); | ||
it('filters out falsey items', () => { | ||
const startValue = { | ||
one: 0, | ||
two: false, | ||
three: Date.now(), | ||
}; | ||
window.storage.put('sessionResets', startValue); | ||
messageReceiver.cleanupSessionResets(); | ||
const actual = window.storage.get('sessionResets'); | ||
|
||
const expected = window._.pick(startValue, ['three']); | ||
assert.deepEqual(actual, expected); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.