Fully move to protobufjs
This commit is contained in:
parent
20ea409d9e
commit
570fb182d4
46 changed files with 1133 additions and 12401 deletions
|
@ -1,63 +0,0 @@
|
|||
// Copyright 2015-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global window, postMessage, textsecure, close */
|
||||
|
||||
/* eslint-disable more/no-then, no-global-assign, no-restricted-globals, no-unused-vars */
|
||||
|
||||
/*
|
||||
* Load this script in a Web Worker to generate new prekeys without
|
||||
* tying up the main thread.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
|
||||
*
|
||||
* Because workers don't have access to the window or localStorage, we
|
||||
* create our own version that proxies back to the caller for actual
|
||||
* storage.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
var myWorker = new Worker('/js/key_worker.js');
|
||||
myWorker.onmessage = function(e) {
|
||||
switch(e.data.method) {
|
||||
case 'set':
|
||||
localStorage.setItem(e.data.key, e.data.value);
|
||||
break;
|
||||
case 'remove':
|
||||
localStorage.removeItem(e.data.key);
|
||||
break;
|
||||
case 'done':
|
||||
console.error(e.data.keys);
|
||||
}
|
||||
};
|
||||
*/
|
||||
let store = {};
|
||||
window.textsecure.storage.impl = {
|
||||
/** ***************************
|
||||
*** Override Storage Routines ***
|
||||
**************************** */
|
||||
put(key, value) {
|
||||
if (value === undefined) throw new Error('Tried to store undefined');
|
||||
store[key] = value;
|
||||
postMessage({ method: 'set', key, value });
|
||||
},
|
||||
|
||||
get(key, defaultValue) {
|
||||
if (key in store) {
|
||||
return store[key];
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
|
||||
remove(key) {
|
||||
delete store[key];
|
||||
postMessage({ method: 'remove', key });
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line no-undef
|
||||
onmessage = e => {
|
||||
store = e.data;
|
||||
textsecure.protocol_wrapper.generateKeys().then(keys => {
|
||||
postMessage({ method: 'done', keys });
|
||||
close();
|
||||
});
|
||||
};
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2015-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global window, dcodeIO, textsecure */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
const FILES_TO_LOAD = [
|
||||
'SignalService.proto',
|
||||
'SignalStorage.proto',
|
||||
'SubProtocol.proto',
|
||||
'DeviceMessages.proto',
|
||||
'Stickers.proto',
|
||||
|
||||
// Just for encrypting device names
|
||||
'DeviceName.proto',
|
||||
|
||||
// Metadata-specific protos
|
||||
'UnidentifiedDelivery.proto',
|
||||
|
||||
// Groups
|
||||
'Groups.proto',
|
||||
];
|
||||
|
||||
let remainingFilesToLoad = FILES_TO_LOAD.length;
|
||||
const hasFinishedLoading = () => remainingFilesToLoad <= 0;
|
||||
let onLoadCallbacks = [];
|
||||
|
||||
window.textsecure = window.textsecure || {};
|
||||
window.textsecure.protobuf = {
|
||||
onLoad: callback => {
|
||||
if (hasFinishedLoading()) {
|
||||
setTimeout(callback, 0);
|
||||
} else {
|
||||
onLoadCallbacks.push(callback);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
FILES_TO_LOAD.forEach(filename => {
|
||||
dcodeIO.ProtoBuf.loadProtoFile(
|
||||
{ root: window.PROTO_ROOT, file: filename },
|
||||
(error, result) => {
|
||||
if (error) {
|
||||
const text = `Error loading protos from ${filename} (root: ${
|
||||
window.PROTO_ROOT
|
||||
}) ${error && error.stack ? error.stack : error}`;
|
||||
window.log.error(text);
|
||||
throw error;
|
||||
}
|
||||
const protos = result.build('signalservice');
|
||||
if (!protos) {
|
||||
const text = `Error loading protos from ${filename} - no exported types! (root: ${window.PROTO_ROOT})`;
|
||||
window.log.error(text);
|
||||
throw new Error(text);
|
||||
}
|
||||
// eslint-disable-next-line no-restricted-syntax, guard-for-in
|
||||
for (const protoName in protos) {
|
||||
textsecure.protobuf[protoName] = protos[protoName];
|
||||
}
|
||||
|
||||
remainingFilesToLoad -= 1;
|
||||
if (hasFinishedLoading()) {
|
||||
onLoadCallbacks.forEach(callback => callback());
|
||||
onLoadCallbacks = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
})();
|
|
@ -17,10 +17,8 @@ module.exports = {
|
|||
globals: {
|
||||
assert: true,
|
||||
assertEqualArrayBuffers: true,
|
||||
dcodeIO: true,
|
||||
getString: true,
|
||||
hexToArrayBuffer: true,
|
||||
PROTO_ROOT: true,
|
||||
stringToArrayBuffer: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
mocha.setup('bdd');
|
||||
window.assert = chai.assert;
|
||||
window.PROTO_ROOT = '../../protos';
|
||||
|
||||
const OriginalReporter = mocha._reporter;
|
||||
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
// Copyright 2015-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global textsecure */
|
||||
|
||||
describe('encrypting and decrypting profile data', () => {
|
||||
const NAME_PADDED_LENGTH = 53;
|
||||
describe('encrypting and decrypting profile names', () => {
|
||||
it('pads, encrypts, decrypts, and unpads a short string', () => {
|
||||
const name = 'Alice';
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto
|
||||
.encryptProfileName(buffer, key)
|
||||
.then(encrypted => {
|
||||
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfileName(encrypted, key)
|
||||
.then(({ given, family }) => {
|
||||
assert.strictEqual(family, null);
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
|
||||
name
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('handles a given name of the max, 53 characters', () => {
|
||||
const name = '01234567890123456789012345678901234567890123456789123';
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto
|
||||
.encryptProfileName(buffer, key)
|
||||
.then(encrypted => {
|
||||
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfileName(encrypted, key)
|
||||
.then(({ given, family }) => {
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
|
||||
name
|
||||
);
|
||||
assert.strictEqual(family, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('handles family/given name of the max, 53 characters', () => {
|
||||
const name = '01234567890123456789\u000001234567890123456789012345678912';
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto
|
||||
.encryptProfileName(buffer, key)
|
||||
.then(encrypted => {
|
||||
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfileName(encrypted, key)
|
||||
.then(({ given, family }) => {
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
|
||||
'01234567890123456789'
|
||||
);
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
|
||||
'01234567890123456789012345678912'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('handles a string with family/given name', () => {
|
||||
const name = 'Alice\0Jones';
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto
|
||||
.encryptProfileName(buffer, key)
|
||||
.then(encrypted => {
|
||||
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfileName(encrypted, key)
|
||||
.then(({ given, family }) => {
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
|
||||
'Alice'
|
||||
);
|
||||
assert.strictEqual(
|
||||
dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
|
||||
'Jones'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('works for empty string', async () => {
|
||||
const name = dcodeIO.ByteBuffer.wrap('').toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
const encrypted = await textsecure.crypto.encryptProfileName(name, key);
|
||||
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
|
||||
|
||||
const { given, family } = await textsecure.crypto.decryptProfileName(
|
||||
encrypted,
|
||||
key
|
||||
);
|
||||
assert.strictEqual(family, null);
|
||||
assert.strictEqual(given.byteLength, 0);
|
||||
assert.strictEqual(dcodeIO.ByteBuffer.wrap(given).toString('utf8'), '');
|
||||
});
|
||||
});
|
||||
describe('encrypting and decrypting profile avatars', () => {
|
||||
it('encrypts and decrypts', () => {
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(
|
||||
'This is an avatar'
|
||||
).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
|
||||
assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfile(encrypted, key)
|
||||
.then(decrypted => {
|
||||
assertEqualArrayBuffers(buffer, decrypted);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('throws when decrypting with the wrong key', () => {
|
||||
const buffer = dcodeIO.ByteBuffer.wrap(
|
||||
'This is an avatar'
|
||||
).toArrayBuffer();
|
||||
const key = window.Signal.Crypto.getRandomBytes(32);
|
||||
const badKey = window.Signal.Crypto.getRandomBytes(32);
|
||||
|
||||
return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
|
||||
assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
|
||||
return textsecure.crypto
|
||||
.decryptProfile(encrypted, badKey)
|
||||
.catch(error => {
|
||||
assert.strictEqual(error.name, 'ProfileDecryptError');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -20,7 +20,6 @@
|
|||
></script>
|
||||
|
||||
<script type="text/javascript" src="../components.js"></script>
|
||||
<script type="text/javascript" src="../protobufs.js" data-cover></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../protocol_wrapper.js"
|
||||
|
@ -38,7 +37,6 @@
|
|||
></script>
|
||||
|
||||
<script type="text/javascript" src="helpers_test.js"></script>
|
||||
<script type="text/javascript" src="crypto_test.js"></script>
|
||||
<script type="text/javascript" src="generate_keys_test.js"></script>
|
||||
<script type="text/javascript" src="task_with_timeout_test.js"></script>
|
||||
<script type="text/javascript" src="account_manager_test.js"></script>
|
||||
|
@ -50,10 +48,8 @@
|
|||
|
||||
<!-- Uncomment to start tests without code coverage enabled -->
|
||||
<script type="text/javascript">
|
||||
window.textsecure.protobuf.onLoad(() => {
|
||||
mocha.run();
|
||||
window.Signal.conversationControllerStart();
|
||||
});
|
||||
mocha.run();
|
||||
window.Signal.conversationControllerStart();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue