Fully move to protobufjs

This commit is contained in:
Fedor Indutny 2021-07-13 11:54:53 -07:00 committed by GitHub
parent 20ea409d9e
commit 570fb182d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 1133 additions and 12401 deletions

View file

@ -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();
});
};

View file

@ -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 = [];
}
}
);
});
})();

View file

@ -17,10 +17,8 @@ module.exports = {
globals: {
assert: true,
assertEqualArrayBuffers: true,
dcodeIO: true,
getString: true,
hexToArrayBuffer: true,
PROTO_ROOT: true,
stringToArrayBuffer: true,
},
};

View file

@ -5,7 +5,6 @@
mocha.setup('bdd');
window.assert = chai.assert;
window.PROTO_ROOT = '../../protos';
const OriginalReporter = mocha._reporter;

View file

@ -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');
});
});
});
});
});

View file

@ -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>