eslintify all test files

This commit is contained in:
Scott Nonnenberg
2018-11-02 11:02:53 -07:00
parent 884bc9333d
commit dbf0be2db5
44 changed files with 1469 additions and 1484 deletions

View File

@@ -0,0 +1,25 @@
{
"env": {
"browser": true,
"node": false,
"mocha": true,
},
"parserOptions": {
"sourceType": "script"
},
"rules": {
"strict": "off",
"more/no-then": "off",
},
"globals": {
"assert": true,
"assertEqualArrayBuffers": true,
"dcodeIO": true,
"getString": true,
"hexToArrayBuffer": true,
"MockServer": true,
"MockSocket": true,
"PROTO_ROOT": true,
"stringToArrayBuffer": true,
}
}

View File

@@ -1,57 +1,59 @@
/* global mocha, chai, assert */
mocha.setup('bdd');
window.assert = chai.assert;
window.PROTO_ROOT = '../../protos';
(function() {
const OriginalReporter = mocha._reporter;
const OriginalReporter = mocha._reporter;
const SauceReporter = function(runner) {
const failedTests = [];
const SauceReporter = runner => {
const failedTests = [];
runner.on('end', () => {
window.mochaResults = runner.stats;
window.mochaResults.reports = failedTests;
runner.on('end', () => {
window.mochaResults = runner.stats;
window.mochaResults.reports = failedTests;
});
runner.on('fail', (test, err) => {
const flattenTitles = item => {
const titles = [];
while (item.parent.title) {
titles.push(item.parent.title);
// eslint-disable-next-line no-param-reassign
item = item.parent;
}
return titles.reverse();
};
failedTests.push({
name: test.title,
result: false,
message: err.message,
stack: err.stack,
titles: flattenTitles(test),
});
});
runner.on('fail', (test, err) => {
const flattenTitles = function(test) {
const titles = [];
while (test.parent.title) {
titles.push(test.parent.title);
test = test.parent;
}
return titles.reverse();
};
failedTests.push({
name: test.title,
result: false,
message: err.message,
stack: err.stack,
titles: flattenTitles(test),
});
});
// eslint-disable-next-line no-new
new OriginalReporter(runner);
};
new OriginalReporter(runner);
};
SauceReporter.prototype = OriginalReporter.prototype;
SauceReporter.prototype = OriginalReporter.prototype;
mocha.reporter(SauceReporter);
})();
mocha.reporter(SauceReporter);
/*
* global helpers for tests
*/
function assertEqualArrayBuffers(ab1, ab2) {
window.assertEqualArrayBuffers = (ab1, ab2) => {
assert.deepEqual(new Uint8Array(ab1), new Uint8Array(ab2));
}
};
function hexToArrayBuffer(str) {
window.hexToArrayBuffer = str => {
const ret = new ArrayBuffer(str.length / 2);
const array = new Uint8Array(ret);
for (let i = 0; i < str.length / 2; i++)
for (let i = 0; i < str.length / 2; i += 1)
array[i] = parseInt(str.substr(i * 2, 2), 16);
return ret;
}
};
window.MockSocket.prototype.addEventListener = function() {};
window.MockSocket.prototype.addEventListener = () => null;

View File

@@ -46,7 +46,7 @@ describe('AccountManager', () => {
return accountManager.cleanSignedPreKeys();
});
it('eliminates confirmed keys over a week old, if more than three', () => {
it('eliminates confirmed keys over a week old, if more than three', async () => {
const now = Date.now();
signedPreKeys = [
{
@@ -77,20 +77,19 @@ describe('AccountManager', () => {
];
let count = 0;
window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) {
window.textsecure.storage.protocol.removeSignedPreKey = keyId => {
if (keyId !== 1 && keyId !== 4) {
throw new Error(`Wrong keys were eliminated! ${keyId}`);
}
count++;
count += 1;
};
return accountManager.cleanSignedPreKeys().then(() => {
assert.strictEqual(count, 2);
});
await accountManager.cleanSignedPreKeys();
assert.strictEqual(count, 2);
});
it('keeps at least three unconfirmed keys if no confirmed', () => {
it('keeps at least three unconfirmed keys if no confirmed', async () => {
const now = Date.now();
signedPreKeys = [
{
@@ -112,20 +111,19 @@ describe('AccountManager', () => {
];
let count = 0;
window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) {
window.textsecure.storage.protocol.removeSignedPreKey = keyId => {
if (keyId !== 2) {
throw new Error(`Wrong keys were eliminated! ${keyId}`);
}
count++;
count += 1;
};
return accountManager.cleanSignedPreKeys().then(() => {
assert.strictEqual(count, 1);
});
await accountManager.cleanSignedPreKeys();
assert.strictEqual(count, 1);
});
it('if some confirmed keys, keeps unconfirmed to addd up to three total', () => {
it('if some confirmed keys, keeps unconfirmed to addd up to three total', async () => {
const now = Date.now();
signedPreKeys = [
{
@@ -149,17 +147,16 @@ describe('AccountManager', () => {
];
let count = 0;
window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) {
window.textsecure.storage.protocol.removeSignedPreKey = keyId => {
if (keyId !== 3) {
throw new Error(`Wrong keys were eliminated! ${keyId}`);
}
count++;
count += 1;
};
return accountManager.cleanSignedPreKeys().then(() => {
assert.strictEqual(count, 1);
});
await accountManager.cleanSignedPreKeys();
assert.strictEqual(count, 1);
});
});
});

View File

@@ -1,9 +1,11 @@
/* global ContactBuffer, GroupBuffer, textsecure */
describe('ContactBuffer', () => {
function getTestBuffer() {
const buffer = new dcodeIO.ByteBuffer();
const avatarBuffer = new dcodeIO.ByteBuffer();
const avatarLen = 255;
for (var i = 0; i < avatarLen; ++i) {
for (let i = 0; i < avatarLen; i += 1) {
avatarBuffer.writeUint8(i);
}
avatarBuffer.limit = avatarBuffer.offset;
@@ -15,7 +17,7 @@ describe('ContactBuffer', () => {
});
const contactInfoBuffer = contactInfo.encode().toArrayBuffer();
for (var i = 0; i < 3; ++i) {
for (let i = 0; i < 3; i += 1) {
buffer.writeVarint32(contactInfoBuffer.byteLength);
buffer.append(contactInfoBuffer);
buffer.append(avatarBuffer.clone());
@@ -32,14 +34,14 @@ describe('ContactBuffer', () => {
let contact = contactBuffer.next();
let count = 0;
while (contact !== undefined) {
count++;
count += 1;
assert.strictEqual(contact.name, 'Zero Cool');
assert.strictEqual(contact.number, '+10000000000');
assert.strictEqual(contact.avatar.contentType, 'image/jpeg');
assert.strictEqual(contact.avatar.length, 255);
assert.strictEqual(contact.avatar.data.byteLength, 255);
const avatarBytes = new Uint8Array(contact.avatar.data);
for (let j = 0; j < 255; ++j) {
for (let j = 0; j < 255; j += 1) {
assert.strictEqual(avatarBytes[j], j);
}
contact = contactBuffer.next();
@@ -53,7 +55,7 @@ describe('GroupBuffer', () => {
const buffer = new dcodeIO.ByteBuffer();
const avatarBuffer = new dcodeIO.ByteBuffer();
const avatarLen = 255;
for (var i = 0; i < avatarLen; ++i) {
for (let i = 0; i < avatarLen; i += 1) {
avatarBuffer.writeUint8(i);
}
avatarBuffer.limit = avatarBuffer.offset;
@@ -66,7 +68,7 @@ describe('GroupBuffer', () => {
});
const groupInfoBuffer = groupInfo.encode().toArrayBuffer();
for (var i = 0; i < 3; ++i) {
for (let i = 0; i < 3; i += 1) {
buffer.writeVarint32(groupInfoBuffer.byteLength);
buffer.append(groupInfoBuffer);
buffer.append(avatarBuffer.clone());
@@ -83,7 +85,7 @@ describe('GroupBuffer', () => {
let group = groupBuffer.next();
let count = 0;
while (group !== undefined) {
count++;
count += 1;
assert.strictEqual(group.name, 'Hackers');
assertEqualArrayBuffers(
group.id.toArrayBuffer(),
@@ -94,7 +96,7 @@ describe('GroupBuffer', () => {
assert.strictEqual(group.avatar.length, 255);
assert.strictEqual(group.avatar.data.byteLength, 255);
const avatarBytes = new Uint8Array(group.avatar.data);
for (let j = 0; j < 255; ++j) {
for (let j = 0; j < 255; j += 1) {
assert.strictEqual(avatarBytes[j], j);
}
group = groupBuffer.next();

View File

@@ -1,3 +1,5 @@
/* global libsignal, textsecure */
describe('encrypting and decrypting profile data', () => {
const NAME_PADDED_LENGTH = 26;
describe('encrypting and decrypting profile names', () => {
@@ -61,12 +63,12 @@ describe('encrypting and decrypting profile data', () => {
'This is an avatar'
).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
const bad_key = libsignal.crypto.getRandomBytes(32);
const badKey = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
return textsecure.crypto
.decryptProfile(encrypted, bad_key)
.decryptProfile(encrypted, badKey)
.catch(error => {
assert.strictEqual(error.name, 'ProfileDecryptError');
});

View File

@@ -22,7 +22,7 @@ const fakeAPI = {
// sendMessages: fakeCall,
setSignedPreKey: fakeCall,
getKeysForNumber(number, deviceId) {
getKeysForNumber(number) {
const res = getKeysForNumberMap[number];
if (res !== undefined) {
delete getKeysForNumberMap[number];
@@ -32,14 +32,14 @@ const fakeAPI = {
},
sendMessages(destination, messageArray) {
for (i in messageArray) {
for (let i = 0, max = messageArray.length; i < max; i += 1) {
const msg = messageArray[i];
if (
(msg.type != 1 && msg.type != 3) ||
(msg.type !== 1 && msg.type !== 3) ||
msg.destinationDeviceId === undefined ||
msg.destinationRegistrationId === undefined ||
msg.body === undefined ||
msg.timestamp == undefined ||
msg.timestamp === undefined ||
msg.relay !== undefined ||
msg.destination !== undefined
)

View File

@@ -1,4 +1,6 @@
describe('Key generation', function() {
/* global libsignal, textsecure */
describe('Key generation', function thisNeeded() {
const count = 10;
this.timeout(count * 2000);
@@ -60,7 +62,7 @@ describe('Key generation', function() {
result = res;
});
});
for (let i = 1; i <= count; i++) {
for (let i = 1; i <= count; i += 1) {
itStoresPreKey(i);
}
itStoresSignedPreKey(1);
@@ -68,12 +70,12 @@ describe('Key generation', function() {
it(`result contains ${count} preKeys`, () => {
assert.isArray(result.preKeys);
assert.lengthOf(result.preKeys, count);
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
assert.isObject(result.preKeys[i]);
}
});
it('result contains the correct keyIds', () => {
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
assert.strictEqual(result.preKeys[i].keyId, i + 1);
}
});
@@ -93,7 +95,7 @@ describe('Key generation', function() {
result = res;
});
});
for (let i = 1; i <= 2 * count; i++) {
for (let i = 1; i <= 2 * count; i += 1) {
itStoresPreKey(i);
}
itStoresSignedPreKey(1);
@@ -101,12 +103,12 @@ describe('Key generation', function() {
it(`result contains ${count} preKeys`, () => {
assert.isArray(result.preKeys);
assert.lengthOf(result.preKeys, count);
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
assert.isObject(result.preKeys[i]);
}
});
it('result contains the correct keyIds', () => {
for (let i = 1; i <= count; i++) {
for (let i = 1; i <= count; i += 1) {
assert.strictEqual(result.preKeys[i - 1].keyId, i + count);
}
});
@@ -126,7 +128,7 @@ describe('Key generation', function() {
result = res;
});
});
for (let i = 1; i <= 3 * count; i++) {
for (let i = 1; i <= 3 * count; i += 1) {
itStoresPreKey(i);
}
itStoresSignedPreKey(2);
@@ -134,12 +136,12 @@ describe('Key generation', function() {
it(`result contains ${count} preKeys`, () => {
assert.isArray(result.preKeys);
assert.lengthOf(result.preKeys, count);
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
assert.isObject(result.preKeys[i]);
}
});
it('result contains the correct keyIds', () => {
for (let i = 1; i <= count; i++) {
for (let i = 1; i <= count; i += 1) {
assert.strictEqual(result.preKeys[i - 1].keyId, i + 2 * count);
}
});

View File

@@ -12,7 +12,6 @@ describe('Helpers', () => {
describe('stringToArrayBuffer', () => {
it('returns ArrayBuffer when passed string', () => {
const StaticArrayBufferProto = new ArrayBuffer().__proto__;
const anArrayBuffer = new ArrayBuffer(1);
const typedArray = new Uint8Array(anArrayBuffer);
typedArray[0] = 'a'.charCodeAt(0);

View File

@@ -36,10 +36,10 @@ SignalProtocolStore.prototype = {
isTrustedIdentity(identifier, identityKey) {
if (identifier === null || identifier === undefined) {
throw new error('tried to check identity key for undefined/null key');
throw new Error('tried to check identity key for undefined/null key');
}
if (!(identityKey instanceof ArrayBuffer)) {
throw new error('Expected identityKey to be an ArrayBuffer');
throw new Error('Expected identityKey to be an ArrayBuffer');
}
const trusted = this.get(`identityKey${identifier}`);
if (trusted === undefined) {
@@ -96,9 +96,11 @@ SignalProtocolStore.prototype = {
loadSignedPreKeys() {
return new Promise(resolve => {
const res = [];
for (const i in this.store) {
if (i.startsWith('25519KeysignedKey')) {
res.push(this.store[i]);
const keys = Object.keys(this.store);
for (let i = 0, max = keys.length; i < max; i += 1) {
const key = keys[i];
if (key.startsWith('25519KeysignedKey')) {
res.push(this.store[key]);
}
}
resolve(res);
@@ -127,7 +129,9 @@ SignalProtocolStore.prototype = {
},
removeAllSessions(identifier) {
return new Promise(resolve => {
for (key in this.store) {
const keys = Object.keys(this.store);
for (let i = 0, max = keys.length; i < max; i += 1) {
const key = keys[i];
if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) {
delete this.store[key];
}
@@ -138,9 +142,11 @@ SignalProtocolStore.prototype = {
getDeviceIds(identifier) {
return new Promise(resolve => {
const deviceIds = [];
for (key in this.store) {
const keys = Object.keys(this.store);
for (let i = 0, max = keys.length; i < max; i += 1) {
const key = keys[i];
if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) {
deviceIds.push(parseInt(key.split('.')[1]));
deviceIds.push(parseInt(key.split('.')[1], 10));
}
}
resolve(deviceIds);

View File

@@ -1,9 +1,12 @@
/* global libsignal, textsecure, SignalProtocolStore */
describe('MessageReceiver', () => {
textsecure.storage.impl = new SignalProtocolStore();
const WebSocket = window.WebSocket;
const { WebSocket } = window;
const number = '+19999999999';
const deviceId = 1;
const signalingKey = libsignal.crypto.getRandomBytes(32 + 20);
before(() => {
window.WebSocket = MockSocket;
textsecure.storage.user.setNumberAndDeviceId(number, deviceId, 'name');
@@ -15,7 +18,6 @@ describe('MessageReceiver', () => {
});
describe('connecting', () => {
const blob = null;
const attrs = {
type: textsecure.protobuf.Envelope.Type.CIPHERTEXT,
source: number,
@@ -29,14 +31,12 @@ describe('MessageReceiver', () => {
before(done => {
const signal = new textsecure.protobuf.Envelope(attrs).toArrayBuffer();
const data = new textsecure.protobuf.DataMessage({ body: 'hello' });
const signaling_key = signalingKey;
const aes_key = signaling_key.slice(0, 32);
const mac_key = signaling_key.slice(32, 32 + 20);
const aesKey = signalingKey.slice(0, 32);
const macKey = signalingKey.slice(32, 32 + 20);
window.crypto.subtle
.importKey('raw', aes_key, { name: 'AES-CBC' }, false, ['encrypt'])
.importKey('raw', aesKey, { name: 'AES-CBC' }, false, ['encrypt'])
.then(key => {
const iv = libsignal.crypto.getRandomBytes(16);
window.crypto.subtle
@@ -45,14 +45,14 @@ describe('MessageReceiver', () => {
window.crypto.subtle
.importKey(
'raw',
mac_key,
macKey,
{ name: 'HMAC', hash: { name: 'SHA-256' } },
false,
['sign']
)
.then(key => {
.then(innerKey => {
window.crypto.subtle
.sign({ name: 'HMAC', hash: 'SHA-256' }, key, signal)
.sign({ name: 'HMAC', hash: 'SHA-256' }, innerKey, signal)
.then(mac => {
const version = new Uint8Array([1]);
const message = dcodeIO.ByteBuffer.concat([
@@ -82,14 +82,19 @@ describe('MessageReceiver', () => {
window.addEventListener('textsecure:message', ev => {
const signal = ev.proto;
for (const key in attrs) {
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]);
}
assert.strictEqual(signal.message.body, 'hello');
server.close();
mockServer.close();
done();
});
const messageReceiver = new textsecure.MessageReceiver(
window.messageReceiver = new textsecure.MessageReceiver(
'username',
'password',
'signalingKey'

View File

@@ -1,32 +1,34 @@
/* global textsecure */
describe('Protocol', () => {
describe('Unencrypted PushMessageProto "decrypt"', () => {
// exclusive
it('works', done => {
localStorage.clear();
const text_message = new textsecure.protobuf.DataMessage();
text_message.body = 'Hi Mom';
const server_message = {
const textMessage = new textsecure.protobuf.DataMessage();
textMessage.body = 'Hi Mom';
const serverMessage = {
type: 4, // unencrypted
source: '+19999999999',
timestamp: 42,
message: text_message.encode(),
message: textMessage.encode(),
};
return textsecure.protocol_wrapper
.handleEncryptedMessage(
server_message.source,
server_message.source_device,
server_message.type,
server_message.message
serverMessage.source,
serverMessage.source_device,
serverMessage.type,
serverMessage.message
)
.then(message => {
assert.equal(message.body, text_message.body);
assert.equal(message.body, textMessage.body);
assert.equal(
message.attachments.length,
text_message.attachments.length
textMessage.attachments.length
);
assert.equal(text_message.attachments.length, 0);
assert.equal(textMessage.attachments.length, 0);
})
.then(done)
.catch(done);

View File

@@ -1,19 +1,20 @@
describe('Protocol Wrapper', function() {
/* global libsignal, textsecure */
describe('Protocol Wrapper', function thisNeeded() {
const store = textsecure.storage.protocol;
const identifier = '+5558675309';
const another_identifier = '+5555590210';
let prekeys, identityKey, testKey;
this.timeout(5000);
before(done => {
localStorage.clear();
libsignal.KeyHelper.generateIdentityKeyPair()
.then(identityKey =>
textsecure.storage.protocol.saveIdentity(identifier, identityKey)
)
.then(key => textsecure.storage.protocol.saveIdentity(identifier, key))
.then(() => {
done();
});
});
describe('processPreKey', () => {
it('rejects if the identity key changes', () => {
const address = new libsignal.SignalProtocolAddress(identifier, 1);

View File

@@ -1,10 +1,11 @@
/* global libsignal, textsecure */
describe('SignalProtocolStore', () => {
before(() => {
localStorage.clear();
});
const store = textsecure.storage.protocol;
const identifier = '+5558675309';
const another_identifier = '+5555590210';
const identityKey = {
pubKey: libsignal.crypto.getRandomBytes(33),
privKey: libsignal.crypto.getRandomBytes(32),
@@ -13,176 +14,121 @@ describe('SignalProtocolStore', () => {
pubKey: libsignal.crypto.getRandomBytes(33),
privKey: libsignal.crypto.getRandomBytes(32),
};
it('retrieves my registration id', done => {
it('retrieves my registration id', async () => {
store.put('registrationId', 1337);
store
.getLocalRegistrationId()
.then(reg => {
assert.strictEqual(reg, 1337);
})
.then(done, done);
const reg = await store.getLocalRegistrationId();
assert.strictEqual(reg, 1337);
});
it('retrieves my identity key', done => {
it('retrieves my identity key', async () => {
store.put('identityKey', identityKey);
store
.getIdentityKeyPair()
.then(key => {
assertEqualArrayBuffers(key.pubKey, identityKey.pubKey);
assertEqualArrayBuffers(key.privKey, identityKey.privKey);
const key = await store.getIdentityKeyPair();
assertEqualArrayBuffers(key.pubKey, identityKey.pubKey);
assertEqualArrayBuffers(key.privKey, identityKey.privKey);
});
it('stores identity keys', async () => {
await store.saveIdentity(identifier, testKey.pubKey);
const key = await store.loadIdentityKey(identifier);
assertEqualArrayBuffers(key, testKey.pubKey);
});
it('returns whether a key is trusted', async () => {
const newIdentity = libsignal.crypto.getRandomBytes(33);
await store.saveIdentity(identifier, testKey.pubKey);
const trusted = await store.isTrustedIdentity(identifier, newIdentity);
if (trusted) {
throw new Error('Allowed to overwrite identity key');
}
});
it('returns whether a key is untrusted', async () => {
await store.saveIdentity(identifier, testKey.pubKey);
const trusted = await store.isTrustedIdentity(identifier, testKey.pubKey);
if (!trusted) {
throw new Error('Allowed to overwrite identity key');
}
});
it('stores prekeys', async () => {
await store.storePreKey(1, testKey);
const key = await store.loadPreKey(1);
assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
assertEqualArrayBuffers(key.privKey, testKey.privKey);
});
it('deletes prekeys', async () => {
await store.storePreKey(2, testKey);
await store.removePreKey(2, testKey);
const key = await store.loadPreKey(2);
assert.isUndefined(key);
});
it('stores signed prekeys', async () => {
await store.storeSignedPreKey(3, testKey);
const key = await store.loadSignedPreKey(3);
assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
assertEqualArrayBuffers(key.privKey, testKey.privKey);
});
it('deletes signed prekeys', async () => {
await store.storeSignedPreKey(4, testKey);
await store.removeSignedPreKey(4, testKey);
const key = await store.loadSignedPreKey(4);
assert.isUndefined(key);
});
it('stores sessions', async () => {
const testRecord = 'an opaque string';
const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));
await Promise.all(
devices.map(async encodedNumber => {
await store.storeSession(encodedNumber, testRecord + encodedNumber);
})
.then(done, done);
);
const records = await Promise.all(
devices.map(store.loadSession.bind(store))
);
for (let i = 0, max = records.length; i < max; i += 1) {
assert.strictEqual(records[i], testRecord + devices[i]);
}
});
it('stores identity keys', done => {
store
.saveIdentity(identifier, testKey.pubKey)
.then(() =>
store.loadIdentityKey(identifier).then(key => {
assertEqualArrayBuffers(key, testKey.pubKey);
})
)
.then(done, done);
});
it('returns whether a key is trusted', done => {
const newIdentity = libsignal.crypto.getRandomBytes(33);
store.saveIdentity(identifier, testKey.pubKey).then(() => {
store
.isTrustedIdentity(identifier, newIdentity)
.then(trusted => {
if (trusted) {
done(new Error('Allowed to overwrite identity key'));
} else {
done();
}
})
.catch(done);
});
});
it('returns whether a key is untrusted', done => {
const newIdentity = libsignal.crypto.getRandomBytes(33);
store.saveIdentity(identifier, testKey.pubKey).then(() => {
store
.isTrustedIdentity(identifier, testKey.pubKey)
.then(trusted => {
if (trusted) {
done();
} else {
done(new Error('Allowed to overwrite identity key'));
}
})
.catch(done);
});
});
it('stores prekeys', done => {
store
.storePreKey(1, testKey)
.then(() =>
store.loadPreKey(1).then(key => {
assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
assertEqualArrayBuffers(key.privKey, testKey.privKey);
})
)
.then(done, done);
});
it('deletes prekeys', done => {
before(done => {
store.storePreKey(2, testKey).then(done);
});
store
.removePreKey(2, testKey)
.then(() =>
store.loadPreKey(2).then(key => {
assert.isUndefined(key);
})
)
.then(done, done);
});
it('stores signed prekeys', done => {
store
.storeSignedPreKey(3, testKey)
.then(() =>
store.loadSignedPreKey(3).then(key => {
assertEqualArrayBuffers(key.pubKey, testKey.pubKey);
assertEqualArrayBuffers(key.privKey, testKey.privKey);
})
)
.then(done, done);
});
it('deletes signed prekeys', done => {
before(done => {
store.storeSignedPreKey(4, testKey).then(done);
});
store
.removeSignedPreKey(4, testKey)
.then(() =>
store.loadSignedPreKey(4).then(key => {
assert.isUndefined(key);
})
)
.then(done, done);
});
it('stores sessions', done => {
it('removes all sessions for a number', async () => {
const testRecord = 'an opaque string';
const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));
let promise = Promise.resolve();
devices.forEach(encodedNumber => {
promise = promise.then(() =>
store.storeSession(encodedNumber, testRecord + encodedNumber)
);
});
promise
.then(() =>
Promise.all(devices.map(store.loadSession.bind(store))).then(
records => {
for (const i in records) {
assert.strictEqual(records[i], testRecord + devices[i]);
}
}
)
)
.then(done, done);
await Promise.all(
devices.map(async encodedNumber => {
await store.storeSession(encodedNumber, testRecord + encodedNumber);
})
);
await store.removeAllSessions(identifier);
const records = await Promise.all(
devices.map(store.loadSession.bind(store))
);
for (let i = 0, max = records.length; i < max; i += 1) {
assert.isUndefined(records[i]);
}
});
it('removes all sessions for a number', done => {
it('returns deviceIds for a number', async () => {
const testRecord = 'an opaque string';
const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));
let promise = Promise.resolve();
devices.forEach(encodedNumber => {
promise = promise.then(() =>
store.storeSession(encodedNumber, testRecord + encodedNumber)
);
});
promise
.then(() =>
store.removeAllSessions(identifier).then(record =>
Promise.all(devices.map(store.loadSession.bind(store))).then(
records => {
for (const i in records) {
assert.isUndefined(records[i]);
}
}
)
)
)
.then(done, done);
await Promise.all(
devices.map(async encodedNumber => {
await store.storeSession(encodedNumber, testRecord + encodedNumber);
})
);
const deviceIds = await store.getDeviceIds(identifier);
assert.sameMembers(deviceIds, [1, 2, 3]);
});
it('returns deviceIds for a number', done => {
const testRecord = 'an opaque string';
const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.'));
let promise = Promise.resolve();
devices.forEach(encodedNumber => {
promise = promise.then(() =>
store.storeSession(encodedNumber, testRecord + encodedNumber)
);
});
promise
.then(() =>
store.getDeviceIds(identifier).then(deviceIds => {
assert.sameMembers(deviceIds, [1, 2, 3]);
})
)
.then(done, done);
it('returns empty array for a number with no device ids', async () => {
const deviceIds = await store.getDeviceIds('foo');
assert.sameMembers(deviceIds, []);
});
it('returns empty array for a number with no device ids', () =>
store.getDeviceIds('foo').then(deviceIds => {
assert.sameMembers(deviceIds, []);
}));
});

View File

@@ -1,8 +1,8 @@
/* global textsecure */
describe('createTaskWithTimeout', () => {
it('resolves when promise resolves', () => {
const task = function() {
return Promise.resolve('hi!');
};
const task = () => Promise.resolve('hi!');
const taskWithTimeout = textsecure.createTaskWithTimeout(task);
return taskWithTimeout().then(result => {
@@ -11,26 +11,22 @@ describe('createTaskWithTimeout', () => {
});
it('flows error from promise back', () => {
const error = new Error('original');
const task = function() {
return Promise.reject(error);
};
const task = () => Promise.reject(error);
const taskWithTimeout = textsecure.createTaskWithTimeout(task);
return taskWithTimeout().catch(flowedError => {
assert.strictEqual(error, flowedError);
});
});
it('rejects if promise takes too long (this one logs error to console)', function() {
const error = new Error('original');
it('rejects if promise takes too long (this one logs error to console)', () => {
let complete = false;
const task = function() {
return new Promise(resolve => {
const task = () =>
new Promise(resolve => {
setTimeout(() => {
complete = true;
resolve();
}, 3000);
});
};
const taskWithTimeout = textsecure.createTaskWithTimeout(task, this.name, {
timeout: 10,
});
@@ -45,29 +41,27 @@ describe('createTaskWithTimeout', () => {
);
});
it('resolves if task returns something falsey', () => {
const task = function() {};
const task = () => {};
const taskWithTimeout = textsecure.createTaskWithTimeout(task);
return taskWithTimeout();
});
it('resolves if task returns a non-promise', () => {
const task = function() {
return 'hi!';
};
const task = () => 'hi!';
const taskWithTimeout = textsecure.createTaskWithTimeout(task);
return taskWithTimeout().then(result => {
assert.strictEqual(result, 'hi!');
});
});
it('rejects if task throws (and does not log about taking too long)', function() {
it('rejects if task throws (and does not log about taking too long)', () => {
const error = new Error('Task is throwing!');
const task = function() {
const task = () => {
throw error;
};
const taskWithTimeout = textsecure.createTaskWithTimeout(task, this.name, {
timeout: 10,
});
return taskWithTimeout().then(
result => {
() => {
throw new Error('Overall task should reject!');
},
flowedError => {

View File

@@ -1,208 +1,214 @@
(function() {
describe('WebSocket-Resource', () => {
describe('requests and responses', () => {
it('receives requests and sends responses', done => {
// mock socket
const request_id = '1';
const socket = {
send(data) {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.RESPONSE
);
assert.strictEqual(message.response.message, 'OK');
assert.strictEqual(message.response.status, 200);
assert.strictEqual(message.response.id.toString(), request_id);
done();
},
addEventListener() {},
};
/* global textsecure, WebSocketResource */
// actual test
const resource = new WebSocketResource(socket, {
handleRequest(request) {
assert.strictEqual(request.verb, 'PUT');
assert.strictEqual(request.path, '/some/path');
assertEqualArrayBuffers(
request.body.toArrayBuffer(),
new Uint8Array([1, 2, 3]).buffer
);
request.respond(200, 'OK');
},
});
describe('WebSocket-Resource', () => {
describe('requests and responses', () => {
it('receives requests and sends responses', done => {
// mock socket
const requestId = '1';
const socket = {
send(data) {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.RESPONSE
);
assert.strictEqual(message.response.message, 'OK');
assert.strictEqual(message.response.status, 200);
assert.strictEqual(message.response.id.toString(), requestId);
done();
},
addEventListener() {},
};
// mock socket request
socket.onmessage({
data: new Blob([
new textsecure.protobuf.WebSocketMessage({
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST,
request: {
id: request_id,
verb: 'PUT',
path: '/some/path',
body: new Uint8Array([1, 2, 3]).buffer,
},
})
.encode()
.toArrayBuffer(),
]),
});
// actual test
this.resource = new WebSocketResource(socket, {
handleRequest(request) {
assert.strictEqual(request.verb, 'PUT');
assert.strictEqual(request.path, '/some/path');
assertEqualArrayBuffers(
request.body.toArrayBuffer(),
new Uint8Array([1, 2, 3]).buffer
);
request.respond(200, 'OK');
},
});
it('sends requests and receives responses', done => {
// mock socket and request handler
let request_id;
const socket = {
send(data) {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'PUT');
assert.strictEqual(message.request.path, '/some/path');
assertEqualArrayBuffers(
message.request.body.toArrayBuffer(),
new Uint8Array([1, 2, 3]).buffer
);
request_id = message.request.id;
},
addEventListener() {},
};
// actual test
const resource = new WebSocketResource(socket);
resource.sendRequest({
verb: 'PUT',
path: '/some/path',
body: new Uint8Array([1, 2, 3]).buffer,
error: done,
success(message, status, request) {
assert.strictEqual(message, 'OK');
assert.strictEqual(status, 200);
done();
},
});
// mock socket response
socket.onmessage({
data: new Blob([
new textsecure.protobuf.WebSocketMessage({
type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE,
response: { id: request_id, message: 'OK', status: 200 },
})
.encode()
.toArrayBuffer(),
]),
});
// mock socket request
socket.onmessage({
data: new Blob([
new textsecure.protobuf.WebSocketMessage({
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST,
request: {
id: requestId,
verb: 'PUT',
path: '/some/path',
body: new Uint8Array([1, 2, 3]).buffer,
},
})
.encode()
.toArrayBuffer(),
]),
});
});
describe('close', () => {
before(() => {
window.WebSocket = MockSocket;
});
after(() => {
window.WebSocket = WebSocket;
});
it('closes the connection', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('close', done);
});
const resource = new WebSocketResource(
new WebSocket('ws://localhost:8081')
);
resource.close();
});
});
it('sends requests and receives responses', done => {
// mock socket and request handler
let requestId;
const socket = {
send(data) {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'PUT');
assert.strictEqual(message.request.path, '/some/path');
assertEqualArrayBuffers(
message.request.body.toArrayBuffer(),
new Uint8Array([1, 2, 3]).buffer
);
requestId = message.request.id;
},
addEventListener() {},
};
describe.skip('with a keepalive config', function() {
before(() => {
window.WebSocket = MockSocket;
});
after(() => {
window.WebSocket = WebSocket;
});
this.timeout(60000);
it('sends keepalives once a minute', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/v1/keepalive');
server.close();
done();
});
});
new WebSocketResource(new WebSocket('ws://localhost:8081'), {
keepalive: { path: '/v1/keepalive' },
});
// actual test
const resource = new WebSocketResource(socket);
resource.sendRequest({
verb: 'PUT',
path: '/some/path',
body: new Uint8Array([1, 2, 3]).buffer,
error: done,
success(message, status) {
assert.strictEqual(message, 'OK');
assert.strictEqual(status, 200);
done();
},
});
it('uses / as a default path', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/');
server.close();
done();
});
});
new WebSocketResource(new WebSocket('ws://localhost:8081'), {
keepalive: true,
});
});
it('optionally disconnects if no response', function(done) {
this.timeout(65000);
const mockServer = new MockServer('ws://localhost:8081');
const socket = new WebSocket('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('close', done);
});
new WebSocketResource(socket, { keepalive: true });
});
it('allows resetting the keepalive timer', function(done) {
this.timeout(65000);
const mockServer = new MockServer('ws://localhost:8081');
const socket = new WebSocket('ws://localhost:8081');
const startTime = Date.now();
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/');
assert(
Date.now() > startTime + 60000,
'keepalive time should be longer than a minute'
);
server.close();
done();
});
});
const resource = new WebSocketResource(socket, { keepalive: true });
setTimeout(() => {
resource.resetKeepAliveTimer();
}, 5000);
// mock socket response
socket.onmessage({
data: new Blob([
new textsecure.protobuf.WebSocketMessage({
type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE,
response: { id: requestId, message: 'OK', status: 200 },
})
.encode()
.toArrayBuffer(),
]),
});
});
});
})();
describe('close', () => {
before(() => {
window.WebSocket = MockSocket;
});
after(() => {
window.WebSocket = WebSocket;
});
it('closes the connection', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('close', done);
});
const resource = new WebSocketResource(
new WebSocket('ws://localhost:8081')
);
resource.close();
});
});
describe.skip('with a keepalive config', function thisNeeded() {
before(() => {
window.WebSocket = MockSocket;
});
after(() => {
window.WebSocket = WebSocket;
});
this.timeout(60000);
it('sends keepalives once a minute', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/v1/keepalive');
server.close();
done();
});
});
this.resource = new WebSocketResource(
new WebSocket('ws://loc1alhost:8081'),
{
keepalive: { path: '/v1/keepalive' },
}
);
});
it('uses / as a default path', done => {
const mockServer = new MockServer('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/');
server.close();
done();
});
});
this.resource = new WebSocketResource(
new WebSocket('ws://localhost:8081'),
{
keepalive: true,
}
);
});
it('optionally disconnects if no response', function thisNeeded1(done) {
this.timeout(65000);
const mockServer = new MockServer('ws://localhost:8081');
const socket = new WebSocket('ws://localhost:8081');
mockServer.on('connection', server => {
server.on('close', done);
});
this.resource = new WebSocketResource(socket, { keepalive: true });
});
it('allows resetting the keepalive timer', function thisNeeded2(done) {
this.timeout(65000);
const mockServer = new MockServer('ws://localhost:8081');
const socket = new WebSocket('ws://localhost:8081');
const startTime = Date.now();
mockServer.on('connection', server => {
server.on('message', data => {
const message = textsecure.protobuf.WebSocketMessage.decode(data);
assert.strictEqual(
message.type,
textsecure.protobuf.WebSocketMessage.Type.REQUEST
);
assert.strictEqual(message.request.verb, 'GET');
assert.strictEqual(message.request.path, '/');
assert(
Date.now() > startTime + 60000,
'keepalive time should be longer than a minute'
);
server.close();
done();
});
});
const resource = new WebSocketResource(socket, { keepalive: true });
setTimeout(() => {
resource.resetKeepAliveTimer();
}, 5000);
});
});
});

View File

@@ -1,3 +1,5 @@
/* global TextSecureWebSocket */
describe('TextSecureWebSocket', () => {
const RealWebSocket = window.WebSocket;
before(() => {
@@ -13,19 +15,19 @@ describe('TextSecureWebSocket', () => {
server.close();
done();
});
var socket = new TextSecureWebSocket('ws://localhost:8080');
const socket = new TextSecureWebSocket('ws://localhost:8080');
});
it('sends and receives', done => {
const mockServer = new MockServer('ws://localhost:8080');
mockServer.on('connection', server => {
server.on('message', data => {
server.on('message', () => {
server.send('ack');
server.close();
});
});
const socket = new TextSecureWebSocket('ws://localhost:8080');
socket.onmessage = function(response) {
socket.onmessage = response => {
assert.strictEqual(response.data, 'ack');
socket.close();
done();
@@ -40,20 +42,20 @@ describe('TextSecureWebSocket', () => {
server.close();
socket.close();
});
var socket = new TextSecureWebSocket('ws://localhost:8082');
socket.onclose = function() {
const socket = new TextSecureWebSocket('ws://localhost:8082');
socket.onclose = () => {
assert.strictEqual(socket.getStatus(), WebSocket.CLOSING);
done();
};
});
it('reconnects', function(done) {
it('reconnects', function thisNeeded(done) {
this.timeout(60000);
const mockServer = new MockServer('ws://localhost:8082');
const socket = new TextSecureWebSocket('ws://localhost:8082');
socket.onclose = function() {
const mockServer = new MockServer('ws://localhost:8082');
mockServer.on('connection', server => {
socket.onclose = () => {
const secondServer = new MockServer('ws://localhost:8082');
secondServer.on('connection', server => {
socket.close();
server.close();
done();