commit
f77da7c218
@ -0,0 +1,18 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": false,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
},
|
||||
"rules": {
|
||||
"strict": "off",
|
||||
"more/no-then": "off"
|
||||
},
|
||||
"globals": {
|
||||
"assert": true,
|
||||
"clearDatabase": true
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/* global window, mocha, chai, assert, Whisper */
|
||||
|
||||
mocha.setup('bdd');
|
||||
window.assert = chai.assert;
|
||||
window.PROTO_ROOT = '../../protos';
|
||||
|
||||
const OriginalReporter = mocha._reporter;
|
||||
|
||||
const SauceReporter = function Constructor(runner) {
|
||||
const 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),
|
||||
});
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new OriginalReporter(runner);
|
||||
};
|
||||
|
||||
SauceReporter.prototype = OriginalReporter.prototype;
|
||||
|
||||
mocha.reporter(SauceReporter);
|
||||
|
||||
// Override the database id.
|
||||
window.Whisper = window.Whisper || {};
|
||||
window.Whisper.Database = window.Whisper.Database || {};
|
||||
Whisper.Database.id = 'test';
|
||||
|
||||
/*
|
||||
* global helpers for tests
|
||||
*/
|
||||
window.clearDatabase = async () => {
|
||||
await window.Signal.Data.removeAll();
|
||||
};
|
@ -0,0 +1,39 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>libloki test runner</title>
|
||||
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="mocha">
|
||||
</div>
|
||||
<div id="tests">
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/test/in_memory_signal_protocol_store.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../../libtextsecure/components.js"></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/helpers.js" data-cover></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/storage.js" data-cover></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/libsignal-protocol.js"></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/protocol_wrapper.js" data-cover></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/protobufs.js" data-cover></script>
|
||||
<script type="text/javascript" src="../../libtextsecure/stringview.js" data-cover></script>
|
||||
|
||||
<script type="text/javascript" src="../libloki-protocol.js" data-cover></script>
|
||||
|
||||
<script type="text/javascript" src="libloki-protocol_test.js"></script>
|
||||
|
||||
<!-- Comment out to turn off code coverage. Useful for getting real callstacks. -->
|
||||
<!-- NOTE: blanket doesn't support modern syntax and will choke until we find a replacement. :0( -->
|
||||
<!-- <script type="text/javascript" src="blanket_mocha.js"></script> -->
|
||||
|
||||
<!-- Uncomment to start tests without code coverage enabled -->
|
||||
<script type="text/javascript">
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,102 @@
|
||||
/* global libsignal, libloki, textsecure, StringView */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('FallBackSessionCipher', () => {
|
||||
let fallbackCipher;
|
||||
let identityKey;
|
||||
let address;
|
||||
const store = textsecure.storage.protocol;
|
||||
|
||||
before(async () => {
|
||||
clearDatabase();
|
||||
identityKey = await libsignal.KeyHelper.generateIdentityKeyPair();
|
||||
store.put('identityKey', identityKey);
|
||||
const key = libsignal.crypto.getRandomBytes(32);
|
||||
const pubKeyString = StringView.arrayBufferToHex(key);
|
||||
address = new libsignal.SignalProtocolAddress(
|
||||
pubKeyString,
|
||||
1
|
||||
);
|
||||
fallbackCipher = new libloki.FallBackSessionCipher(address);
|
||||
});
|
||||
|
||||
it('should encrypt fallback cipher messages as friend requests', async () => {
|
||||
const buffer = new ArrayBuffer(10);
|
||||
const { type } = await fallbackCipher.encrypt(buffer);
|
||||
assert.strictEqual(type, textsecure.protobuf.Envelope.Type.FRIEND_REQUEST);
|
||||
});
|
||||
|
||||
it('should encrypt and then decrypt a message with the same result', async () => {
|
||||
const arr = new Uint8Array([1,2,3,4,5]);
|
||||
const { body } = await fallbackCipher.encrypt(arr.buffer);
|
||||
const result = await fallbackCipher.decrypt(body);
|
||||
assert.deepEqual(result, arr.buffer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('LibLoki Protocol', () => {
|
||||
let testKey;
|
||||
const store = textsecure.storage.protocol;
|
||||
|
||||
beforeEach(async () => {
|
||||
clearDatabase();
|
||||
testKey = {
|
||||
pubKey: libsignal.crypto.getRandomBytes(33),
|
||||
privKey: libsignal.crypto.getRandomBytes(32),
|
||||
};
|
||||
await store.storeSignedPreKey(1, testKey);
|
||||
});
|
||||
|
||||
it('should generate a new prekey bundle for a new contact', async () => {
|
||||
const pubKey = libsignal.crypto.getRandomBytes(32);
|
||||
const pubKeyString = StringView.arrayBufferToHex(pubKey);
|
||||
const preKeyIdBefore = textsecure.storage.get('maxPreKeyId', 1);
|
||||
const newBundle = await libloki.getPreKeyBundleForContact(pubKeyString);
|
||||
const preKeyIdAfter = textsecure.storage.get('maxPreKeyId', 1);
|
||||
assert.strictEqual(preKeyIdAfter, preKeyIdBefore + 1);
|
||||
|
||||
const testKeyArray = new Uint8Array(testKey.pubKey);
|
||||
assert.isDefined(newBundle);
|
||||
assert.isDefined(newBundle.identityKey);
|
||||
assert.isDefined(newBundle.deviceId);
|
||||
assert.isDefined(newBundle.preKeyId);
|
||||
assert.isDefined(newBundle.signedKeyId);
|
||||
assert.isDefined(newBundle.preKey);
|
||||
assert.isDefined(newBundle.signedKey);
|
||||
assert.isDefined(newBundle.signature);
|
||||
assert.strictEqual(testKeyArray.byteLength, newBundle.signedKey.byteLength);
|
||||
for (let i = 0 ; i !== testKeyArray.byteLength; i += 1)
|
||||
assert.strictEqual(testKeyArray[i], newBundle.signedKey[i]);
|
||||
});
|
||||
|
||||
it('should return the same prekey bundle after creating a contact', async () => {
|
||||
const pubKey = libsignal.crypto.getRandomBytes(32);
|
||||
const pubKeyString = StringView.arrayBufferToHex(pubKey);
|
||||
const bundle1 = await libloki.getPreKeyBundleForContact(pubKeyString);
|
||||
const bundle2 = await libloki.getPreKeyBundleForContact(pubKeyString);
|
||||
assert.isDefined(bundle1);
|
||||
assert.isDefined(bundle2);
|
||||
assert.deepEqual(bundle1, bundle2);
|
||||
});
|
||||
|
||||
it('should save the signed keys and prekeys from a bundle', async () => {
|
||||
const pubKey = libsignal.crypto.getRandomBytes(32);
|
||||
const pubKeyString = StringView.arrayBufferToHex(pubKey);
|
||||
const preKeyIdBefore = textsecure.storage.get('maxPreKeyId', 1);
|
||||
const newBundle = await libloki.getPreKeyBundleForContact(pubKeyString);
|
||||
const preKeyIdAfter = textsecure.storage.get('maxPreKeyId', 1);
|
||||
assert.strictEqual(preKeyIdAfter, preKeyIdBefore + 1);
|
||||
|
||||
const testKeyArray = new Uint8Array(testKey.pubKey);
|
||||
assert.isDefined(newBundle);
|
||||
assert.isDefined(newBundle.identityKey);
|
||||
assert.isDefined(newBundle.deviceId);
|
||||
assert.isDefined(newBundle.preKeyId);
|
||||
assert.isDefined(newBundle.signedKeyId);
|
||||
assert.isDefined(newBundle.preKey);
|
||||
assert.isDefined(newBundle.signedKey);
|
||||
assert.isDefined(newBundle.signature);
|
||||
assert.deepEqual(testKeyArray, newBundle.signedKey);
|
||||
});
|
||||
});
|
@ -0,0 +1,97 @@
|
||||
/* global require */
|
||||
const { assert } = require('chai');
|
||||
const { BigInteger } = require('jsbn');
|
||||
|
||||
const {
|
||||
calcTarget,
|
||||
incrementNonce,
|
||||
bufferToBase64,
|
||||
bigIntToUint8Array,
|
||||
greaterThan,
|
||||
} = require('../../libloki/proof-of-work');
|
||||
|
||||
describe('Proof of Work Worker', () => {
|
||||
it('should increment a Uint8Array nonce correctly', () => {
|
||||
const arr1Before = new Uint8Array([0,0,0,0,0,0,0,0]);
|
||||
const arr1After = incrementNonce(arr1Before);
|
||||
assert.strictEqual(arr1After[0], 0);
|
||||
assert.strictEqual(arr1After[1], 0);
|
||||
assert.strictEqual(arr1After[2], 0);
|
||||
assert.strictEqual(arr1After[3], 0);
|
||||
assert.strictEqual(arr1After[4], 0);
|
||||
assert.strictEqual(arr1After[5], 0);
|
||||
assert.strictEqual(arr1After[6], 0);
|
||||
assert.strictEqual(arr1After[7], 1);
|
||||
});
|
||||
|
||||
it('should increment a Uint8Array nonce correctly', () => {
|
||||
let arr = new Uint8Array([0,0,0,0,0,0,0,0]);
|
||||
assert.deepEqual(incrementNonce(arr), new Uint8Array([0,0,0,0,0,0,0,1]));
|
||||
arr = new Uint8Array([0,0,0,0,0,0,0,0]);
|
||||
for(let i = 0; i <= 255; i += 1) {
|
||||
arr = incrementNonce(arr);
|
||||
}
|
||||
assert.deepEqual(arr, new Uint8Array([0,0,0,0,0,0,1,0]));
|
||||
arr = new Uint8Array([255,255,255,255,255,255,255,255]);
|
||||
assert.deepEqual(incrementNonce(arr), new Uint8Array([0,0,0,0,0,0,0,0]));
|
||||
});
|
||||
|
||||
it('should calculate a correct difficulty target', () => {
|
||||
// These values will need to be updated if we adjust the difficulty settings
|
||||
let payloadLen = 625;
|
||||
const ttl = 86400;
|
||||
let expectedTarget = new Uint8Array([0,4,119,164,35,224,222,64]);
|
||||
|
||||
let actualTarget = calcTarget(ttl, payloadLen);
|
||||
assert.deepEqual(actualTarget, expectedTarget);
|
||||
payloadLen = 6597;
|
||||
expectedTarget = new Uint8Array([0,0,109,145,174,146,124,3]);
|
||||
actualTarget = calcTarget(ttl, payloadLen);
|
||||
assert.deepEqual(actualTarget, expectedTarget);
|
||||
});
|
||||
|
||||
it('should correclty compare two Uint8Arrays', () => {
|
||||
let arr1 = new Uint8Array([0,0,0,0,0,0,0,0,0,1]);
|
||||
let arr2 = new Uint8Array([0,0,0,0,0,0,0,0,0,1]);
|
||||
assert.isFalse(greaterThan(arr1, arr2))
|
||||
arr1 = new Uint8Array([0,0,0,0,0,0,0,0,0,2]);
|
||||
arr2 = new Uint8Array([0,0,0,0,0,0,0,0,0,1]);
|
||||
assert.isTrue(greaterThan(arr1, arr2))
|
||||
arr1 = new Uint8Array([255,255,255,255,255,255,255,255,255,255]);
|
||||
arr2 = new Uint8Array([255,255,255,255,255,255,255,255,255,254]);
|
||||
assert.isTrue(greaterThan(arr1, arr2))
|
||||
arr1 = new Uint8Array([254,255,255,255,255,255,255,255,255,255]);
|
||||
arr2 = new Uint8Array([255,255,255,255,255,255,255,255,255,255]);
|
||||
assert.isFalse(greaterThan(arr1, arr2));
|
||||
arr1 = new Uint8Array([0]);
|
||||
arr2 = new Uint8Array([0,0]);
|
||||
assert.isFalse(greaterThan(arr1, arr2))
|
||||
});
|
||||
|
||||
it('should correclty convert a Uint8Array to a base64 string', () => {
|
||||
let arr = new Uint8Array([1,2,3]);
|
||||
let expected = 'AQID';
|
||||
assert.strictEqual(bufferToBase64(arr), expected);
|
||||
arr = new Uint8Array([123,25,3,121,45,87,24,111]);
|
||||
expected = 'exkDeS1XGG8=';
|
||||
assert.strictEqual(bufferToBase64(arr), expected);
|
||||
arr = new Uint8Array([]);
|
||||
expected = '';
|
||||
assert.strictEqual(bufferToBase64(arr), expected);
|
||||
});
|
||||
|
||||
it('should correclty convert a BigInteger to a Uint8Array', () => {
|
||||
let bigInt = new BigInteger(Number.MAX_SAFE_INTEGER.toString());
|
||||
let expected = new Uint8Array([0, 31, 255, 255, 255, 255, 255, 255]);
|
||||
assert.deepEqual(bigIntToUint8Array(bigInt), expected);
|
||||
bigInt = new BigInteger('0');
|
||||
expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
assert.deepEqual(bigIntToUint8Array(bigInt), expected);
|
||||
bigInt = new BigInteger('255');
|
||||
expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]);
|
||||
assert.deepEqual(bigIntToUint8Array(bigInt), expected);
|
||||
bigInt = new BigInteger('256');
|
||||
expected = new Uint8Array([0, 0, 0, 0, 0, 0, 1, 0]);
|
||||
assert.deepEqual(bigIntToUint8Array(bigInt), expected);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue