parent
817cf5ed03
commit
a7d78c0e9b
38 changed files with 2996 additions and 789 deletions
|
@ -1,104 +1,119 @@
|
|||
'use strict';
|
||||
|
||||
describe('Crypto', function() {
|
||||
it('roundtrip symmetric encryption succeeds', async function() {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
describe('Crypto', () => {
|
||||
describe('accessKey/profileKey', () => {
|
||||
it('verification roundtrips', async () => {
|
||||
const profileKey = await Signal.Crypto.getRandomBytes(32);
|
||||
const accessKey = await Signal.Crypto.deriveAccessKey(profileKey);
|
||||
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted);
|
||||
const verifier = await Signal.Crypto.getAccessKeyVerifier(accessKey);
|
||||
|
||||
var equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted);
|
||||
if (!equal) {
|
||||
throw new Error('The output and input did not match!');
|
||||
}
|
||||
const correct = await Signal.Crypto.verifyAccessKey(accessKey, verifier);
|
||||
|
||||
assert.strictEqual(correct, true);
|
||||
});
|
||||
});
|
||||
|
||||
it('roundtrip fails if nonce is modified', async function() {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
describe('symmetric encryption', () => {
|
||||
it('roundtrips', async () => {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[2] = 9;
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted);
|
||||
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
var equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted);
|
||||
if (!equal) {
|
||||
throw new Error('The output and input did not match!');
|
||||
}
|
||||
});
|
||||
|
||||
throw new Error('Expected error to be thrown');
|
||||
});
|
||||
it('roundtrip fails if nonce is modified', async () => {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
|
||||
it('fails if mac is modified', async function() {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[2] = 9;
|
||||
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[uintArray.length - 3] = 9;
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected error to be thrown');
|
||||
});
|
||||
|
||||
throw new Error('Expected error to be thrown');
|
||||
});
|
||||
it('roundtrip fails if mac is modified', async () => {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
|
||||
it('fails if encrypted contents are modified', async function() {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[uintArray.length - 3] = 9;
|
||||
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[35] = 9;
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected error to be thrown');
|
||||
});
|
||||
|
||||
throw new Error('Expected error to be thrown');
|
||||
it('roundtrip fails if encrypted contents are modified', async () => {
|
||||
var message = 'this is my message';
|
||||
var plaintext = new dcodeIO.ByteBuffer.wrap(
|
||||
message,
|
||||
'binary'
|
||||
).toArrayBuffer();
|
||||
var key = textsecure.crypto.getRandomBytes(32);
|
||||
|
||||
var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext);
|
||||
var uintArray = new Uint8Array(encrypted);
|
||||
uintArray[35] = 9;
|
||||
|
||||
try {
|
||||
var decrypted = await Signal.Crypto.decryptSymmetric(
|
||||
key,
|
||||
uintArray.buffer
|
||||
);
|
||||
} catch (error) {
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
'decryptSymmetric: Failed to decrypt; MAC verification failed'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected error to be thrown');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -383,6 +383,8 @@
|
|||
<script type='text/javascript' src='../js/views/banner_view.js' data-cover></script>
|
||||
<script type='text/javascript' src='../js/views/clear_data_view.js'></script>
|
||||
|
||||
<script type="text/javascript" src="metadata/SecretSessionCipher_test.js"></script>
|
||||
|
||||
<script type="text/javascript" src="views/whisper_view_test.js"></script>
|
||||
<script type="text/javascript" src="views/group_update_view_test.js"></script>
|
||||
<script type="text/javascript" src="views/attachment_view_test.js"></script>
|
||||
|
|
405
test/metadata/SecretSessionCipher_test.js
Normal file
405
test/metadata/SecretSessionCipher_test.js
Normal file
|
@ -0,0 +1,405 @@
|
|||
/* global libsignal, textsecure */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
SecretSessionCipher,
|
||||
createCertificateValidator,
|
||||
_createSenderCertificateFromBuffer,
|
||||
_createServerCertificateFromBuffer,
|
||||
} = window.Signal.Metadata;
|
||||
const {
|
||||
bytesFromString,
|
||||
stringFromBytes,
|
||||
arrayBufferToBase64,
|
||||
} = window.Signal.Crypto;
|
||||
|
||||
function InMemorySignalProtocolStore() {
|
||||
this.store = {};
|
||||
}
|
||||
|
||||
function toString(thing) {
|
||||
if (typeof thing === 'string') {
|
||||
return thing;
|
||||
}
|
||||
return arrayBufferToBase64(thing);
|
||||
}
|
||||
|
||||
InMemorySignalProtocolStore.prototype = {
|
||||
Direction: {
|
||||
SENDING: 1,
|
||||
RECEIVING: 2,
|
||||
},
|
||||
|
||||
getIdentityKeyPair() {
|
||||
return Promise.resolve(this.get('identityKey'));
|
||||
},
|
||||
getLocalRegistrationId() {
|
||||
return Promise.resolve(this.get('registrationId'));
|
||||
},
|
||||
put(key, value) {
|
||||
if (
|
||||
key === undefined ||
|
||||
value === undefined ||
|
||||
key === null ||
|
||||
value === null
|
||||
)
|
||||
throw new Error('Tried to store undefined/null');
|
||||
this.store[key] = value;
|
||||
},
|
||||
get(key, defaultValue) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error('Tried to get value for undefined/null key');
|
||||
if (key in this.store) {
|
||||
return this.store[key];
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
},
|
||||
remove(key) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error('Tried to remove value for undefined/null key');
|
||||
delete this.store[key];
|
||||
},
|
||||
|
||||
isTrustedIdentity(identifier, identityKey) {
|
||||
if (identifier === null || identifier === undefined) {
|
||||
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');
|
||||
}
|
||||
const trusted = this.get(`identityKey${identifier}`);
|
||||
if (trusted === undefined) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return Promise.resolve(toString(identityKey) === toString(trusted));
|
||||
},
|
||||
loadIdentityKey(identifier) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error('Tried to get identity key for undefined/null key');
|
||||
return Promise.resolve(this.get(`identityKey${identifier}`));
|
||||
},
|
||||
saveIdentity(identifier, identityKey) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error('Tried to put identity key for undefined/null key');
|
||||
|
||||
const address = libsignal.SignalProtocolAddress.fromString(identifier);
|
||||
|
||||
const existing = this.get(`identityKey${address.getName()}`);
|
||||
this.put(`identityKey${address.getName()}`, identityKey);
|
||||
|
||||
if (existing && toString(identityKey) !== toString(existing)) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
return Promise.resolve(false);
|
||||
},
|
||||
|
||||
/* Returns a prekeypair object or undefined */
|
||||
loadPreKey(keyId) {
|
||||
let res = this.get(`25519KeypreKey${keyId}`);
|
||||
if (res !== undefined) {
|
||||
res = { pubKey: res.pubKey, privKey: res.privKey };
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
},
|
||||
storePreKey(keyId, keyPair) {
|
||||
return Promise.resolve(this.put(`25519KeypreKey${keyId}`, keyPair));
|
||||
},
|
||||
removePreKey(keyId) {
|
||||
return Promise.resolve(this.remove(`25519KeypreKey${keyId}`));
|
||||
},
|
||||
|
||||
/* Returns a signed keypair object or undefined */
|
||||
loadSignedPreKey(keyId) {
|
||||
let res = this.get(`25519KeysignedKey${keyId}`);
|
||||
if (res !== undefined) {
|
||||
res = { pubKey: res.pubKey, privKey: res.privKey };
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
},
|
||||
storeSignedPreKey(keyId, keyPair) {
|
||||
return Promise.resolve(this.put(`25519KeysignedKey${keyId}`, keyPair));
|
||||
},
|
||||
removeSignedPreKey(keyId) {
|
||||
return Promise.resolve(this.remove(`25519KeysignedKey${keyId}`));
|
||||
},
|
||||
|
||||
loadSession(identifier) {
|
||||
return Promise.resolve(this.get(`session${identifier}`));
|
||||
},
|
||||
storeSession(identifier, record) {
|
||||
return Promise.resolve(this.put(`session${identifier}`, record));
|
||||
},
|
||||
removeSession(identifier) {
|
||||
return Promise.resolve(this.remove(`session${identifier}`));
|
||||
},
|
||||
removeAllSessions(identifier) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const id in this.store) {
|
||||
if (id.startsWith(`session${identifier}`)) {
|
||||
delete this.store[id];
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
describe('SecretSessionCipher', () => {
|
||||
it('successfully roundtrips', async () => {
|
||||
const aliceStore = new InMemorySignalProtocolStore();
|
||||
const bobStore = new InMemorySignalProtocolStore();
|
||||
|
||||
await _initializeSessions(aliceStore, bobStore);
|
||||
|
||||
const aliceIdentityKey = await aliceStore.getIdentityKeyPair();
|
||||
|
||||
const trustRoot = await libsignal.Curve.async.generateKeyPair();
|
||||
const senderCertificate = await _createSenderCertificateFor(
|
||||
trustRoot,
|
||||
'+14151111111',
|
||||
1,
|
||||
aliceIdentityKey.pubKey,
|
||||
31337
|
||||
);
|
||||
const aliceCipher = new SecretSessionCipher(aliceStore);
|
||||
|
||||
const ciphertext = await aliceCipher.encrypt(
|
||||
new libsignal.SignalProtocolAddress('+14152222222', 1),
|
||||
senderCertificate,
|
||||
bytesFromString('smert za smert')
|
||||
);
|
||||
|
||||
const bobCipher = new SecretSessionCipher(bobStore);
|
||||
|
||||
const decryptResult = await bobCipher.decrypt(
|
||||
createCertificateValidator(trustRoot.pubKey),
|
||||
ciphertext,
|
||||
31335
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
stringFromBytes(decryptResult.content),
|
||||
'smert za smert'
|
||||
);
|
||||
assert.strictEqual(decryptResult.sender.toString(), '+14151111111.1');
|
||||
});
|
||||
|
||||
it('fails when untrusted', async () => {
|
||||
const aliceStore = new InMemorySignalProtocolStore();
|
||||
const bobStore = new InMemorySignalProtocolStore();
|
||||
|
||||
await _initializeSessions(aliceStore, bobStore);
|
||||
|
||||
const aliceIdentityKey = await aliceStore.getIdentityKeyPair();
|
||||
|
||||
const trustRoot = await libsignal.Curve.async.generateKeyPair();
|
||||
const falseTrustRoot = await libsignal.Curve.async.generateKeyPair();
|
||||
const senderCertificate = await _createSenderCertificateFor(
|
||||
falseTrustRoot,
|
||||
'+14151111111',
|
||||
1,
|
||||
aliceIdentityKey.pubKey,
|
||||
31337
|
||||
);
|
||||
const aliceCipher = new SecretSessionCipher(aliceStore);
|
||||
|
||||
const ciphertext = await aliceCipher.encrypt(
|
||||
new libsignal.SignalProtocolAddress('+14152222222', 1),
|
||||
senderCertificate,
|
||||
bytesFromString('и вот я')
|
||||
);
|
||||
|
||||
const bobCipher = new SecretSessionCipher(bobStore);
|
||||
|
||||
try {
|
||||
await bobCipher.decrypt(
|
||||
createCertificateValidator(trustRoot.pubKey),
|
||||
ciphertext,
|
||||
31335
|
||||
);
|
||||
throw new Error('It did not fail!');
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, 'Invalid signature');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails when expired', async () => {
|
||||
const aliceStore = new InMemorySignalProtocolStore();
|
||||
const bobStore = new InMemorySignalProtocolStore();
|
||||
|
||||
await _initializeSessions(aliceStore, bobStore);
|
||||
|
||||
const aliceIdentityKey = await aliceStore.getIdentityKeyPair();
|
||||
|
||||
const trustRoot = await libsignal.Curve.async.generateKeyPair();
|
||||
const senderCertificate = await _createSenderCertificateFor(
|
||||
trustRoot,
|
||||
'+14151111111',
|
||||
1,
|
||||
aliceIdentityKey.pubKey,
|
||||
31337
|
||||
);
|
||||
const aliceCipher = new SecretSessionCipher(aliceStore);
|
||||
|
||||
const ciphertext = await aliceCipher.encrypt(
|
||||
new libsignal.SignalProtocolAddress('+14152222222', 1),
|
||||
senderCertificate,
|
||||
bytesFromString('и вот я')
|
||||
);
|
||||
|
||||
const bobCipher = new SecretSessionCipher(bobStore);
|
||||
|
||||
try {
|
||||
await bobCipher.decrypt(
|
||||
createCertificateValidator(trustRoot.pubKey),
|
||||
ciphertext,
|
||||
31338
|
||||
);
|
||||
throw new Error('It did not fail!');
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, 'Certificate is expired');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails when wrong identity', async () => {
|
||||
const aliceStore = new InMemorySignalProtocolStore();
|
||||
const bobStore = new InMemorySignalProtocolStore();
|
||||
|
||||
await _initializeSessions(aliceStore, bobStore);
|
||||
|
||||
const trustRoot = await libsignal.Curve.async.generateKeyPair();
|
||||
const randomKeyPair = await libsignal.Curve.async.generateKeyPair();
|
||||
const senderCertificate = await _createSenderCertificateFor(
|
||||
trustRoot,
|
||||
'+14151111111',
|
||||
1,
|
||||
randomKeyPair.pubKey,
|
||||
31337
|
||||
);
|
||||
const aliceCipher = new SecretSessionCipher(aliceStore);
|
||||
|
||||
const ciphertext = await aliceCipher.encrypt(
|
||||
new libsignal.SignalProtocolAddress('+14152222222', 1),
|
||||
senderCertificate,
|
||||
bytesFromString('smert za smert')
|
||||
);
|
||||
|
||||
const bobCipher = new SecretSessionCipher(bobStore);
|
||||
|
||||
try {
|
||||
await bobCipher.decrypt(
|
||||
createCertificateValidator(trustRoot.puKey),
|
||||
ciphertext,
|
||||
31335
|
||||
);
|
||||
throw new Error('It did not fail!');
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, 'Invalid public key');
|
||||
}
|
||||
});
|
||||
|
||||
// private SenderCertificate _createCertificateFor(
|
||||
// ECKeyPair trustRoot
|
||||
// String sender
|
||||
// int deviceId
|
||||
// ECPublicKey identityKey
|
||||
// long expires
|
||||
// )
|
||||
async function _createSenderCertificateFor(
|
||||
trustRoot,
|
||||
sender,
|
||||
deviceId,
|
||||
identityKey,
|
||||
expires
|
||||
) {
|
||||
const serverKey = await libsignal.Curve.async.generateKeyPair();
|
||||
|
||||
const serverCertificateCertificateProto = new textsecure.protobuf.ServerCertificate.Certificate();
|
||||
serverCertificateCertificateProto.id = 1;
|
||||
serverCertificateCertificateProto.key = serverKey.pubKey;
|
||||
const serverCertificateCertificateBytes = serverCertificateCertificateProto
|
||||
.encode()
|
||||
.toArrayBuffer();
|
||||
|
||||
const serverCertificateSignature = await libsignal.Curve.async.calculateSignature(
|
||||
trustRoot.privKey,
|
||||
serverCertificateCertificateBytes
|
||||
);
|
||||
|
||||
const serverCertificateProto = new textsecure.protobuf.ServerCertificate();
|
||||
serverCertificateProto.certificate = serverCertificateCertificateBytes;
|
||||
serverCertificateProto.signature = serverCertificateSignature;
|
||||
const serverCertificate = _createServerCertificateFromBuffer(
|
||||
serverCertificateProto.encode().toArrayBuffer()
|
||||
);
|
||||
|
||||
const senderCertificateCertificateProto = new textsecure.protobuf.SenderCertificate.Certificate();
|
||||
senderCertificateCertificateProto.sender = sender;
|
||||
senderCertificateCertificateProto.senderDevice = deviceId;
|
||||
senderCertificateCertificateProto.identityKey = identityKey;
|
||||
senderCertificateCertificateProto.expires = expires;
|
||||
senderCertificateCertificateProto.signer = textsecure.protobuf.ServerCertificate.decode(
|
||||
serverCertificate.serialized
|
||||
);
|
||||
const senderCertificateBytes = senderCertificateCertificateProto
|
||||
.encode()
|
||||
.toArrayBuffer();
|
||||
|
||||
const senderCertificateSignature = await libsignal.Curve.async.calculateSignature(
|
||||
serverKey.privKey,
|
||||
senderCertificateBytes
|
||||
);
|
||||
|
||||
const senderCertificateProto = new textsecure.protobuf.SenderCertificate();
|
||||
senderCertificateProto.certificate = senderCertificateBytes;
|
||||
senderCertificateProto.signature = senderCertificateSignature;
|
||||
return _createSenderCertificateFromBuffer(
|
||||
senderCertificateProto.encode().toArrayBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
// private void _initializeSessions(
|
||||
// SignalProtocolStore aliceStore, SignalProtocolStore bobStore)
|
||||
async function _initializeSessions(aliceStore, bobStore) {
|
||||
const aliceAddress = new libsignal.SignalProtocolAddress('+14152222222', 1);
|
||||
await aliceStore.put(
|
||||
'identityKey',
|
||||
await libsignal.Curve.generateKeyPair()
|
||||
);
|
||||
await bobStore.put('identityKey', await libsignal.Curve.generateKeyPair());
|
||||
|
||||
await aliceStore.put('registrationId', 57);
|
||||
await bobStore.put('registrationId', 58);
|
||||
|
||||
const bobPreKey = await libsignal.Curve.async.generateKeyPair();
|
||||
const bobIdentityKey = await bobStore.getIdentityKeyPair();
|
||||
const bobSignedPreKey = await libsignal.KeyHelper.generateSignedPreKey(
|
||||
bobIdentityKey,
|
||||
2
|
||||
);
|
||||
|
||||
const bobBundle = {
|
||||
identityKey: bobIdentityKey.pubKey,
|
||||
registrationId: 1,
|
||||
preKey: {
|
||||
keyId: 1,
|
||||
publicKey: bobPreKey.pubKey,
|
||||
},
|
||||
signedPreKey: {
|
||||
keyId: 2,
|
||||
publicKey: bobSignedPreKey.keyPair.pubKey,
|
||||
signature: bobSignedPreKey.signature,
|
||||
},
|
||||
};
|
||||
const aliceSessionBuilder = new libsignal.SessionBuilder(
|
||||
aliceStore,
|
||||
aliceAddress
|
||||
);
|
||||
await aliceSessionBuilder.processPreKey(bobBundle);
|
||||
|
||||
await bobStore.storeSignedPreKey(2, bobSignedPreKey.keyPair);
|
||||
await bobStore.storePreKey(1, bobPreKey);
|
||||
}
|
||||
});
|
|
@ -12,6 +12,7 @@ describe('Startup', () => {
|
|||
});
|
||||
|
||||
it('should complete if user hasn’t previously synced', async () => {
|
||||
const ourNumber = '+15551234567';
|
||||
const deviceId = '2';
|
||||
const sendRequestConfigurationSyncMessage = sandbox.spy();
|
||||
const storagePutSpy = sandbox.spy();
|
||||
|
@ -25,15 +26,21 @@ describe('Startup', () => {
|
|||
},
|
||||
put: storagePutSpy,
|
||||
};
|
||||
const prepareForSend = () => ({
|
||||
wrap: promise => promise,
|
||||
sendOptions: {},
|
||||
});
|
||||
|
||||
const expected = {
|
||||
status: 'complete',
|
||||
};
|
||||
|
||||
const actual = await Startup.syncReadReceiptConfiguration({
|
||||
ourNumber,
|
||||
deviceId,
|
||||
sendRequestConfigurationSyncMessage,
|
||||
storage,
|
||||
prepareForSend,
|
||||
});
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
|
@ -43,9 +50,14 @@ describe('Startup', () => {
|
|||
});
|
||||
|
||||
it('should be skipped if this is the primary device', async () => {
|
||||
const ourNumber = '+15551234567';
|
||||
const deviceId = '1';
|
||||
const sendRequestConfigurationSyncMessage = () => {};
|
||||
const storage = {};
|
||||
const prepareForSend = () => ({
|
||||
wrap: promise => promise,
|
||||
sendOptions: {},
|
||||
});
|
||||
|
||||
const expected = {
|
||||
status: 'skipped',
|
||||
|
@ -53,15 +65,18 @@ describe('Startup', () => {
|
|||
};
|
||||
|
||||
const actual = await Startup.syncReadReceiptConfiguration({
|
||||
ourNumber,
|
||||
deviceId,
|
||||
sendRequestConfigurationSyncMessage,
|
||||
storage,
|
||||
prepareForSend,
|
||||
});
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should be skipped if user has previously synced', async () => {
|
||||
const ourNumber = '+15551234567';
|
||||
const deviceId = '2';
|
||||
const sendRequestConfigurationSyncMessage = () => {};
|
||||
const storage = {
|
||||
|
@ -73,6 +88,10 @@ describe('Startup', () => {
|
|||
return true;
|
||||
},
|
||||
};
|
||||
const prepareForSend = () => ({
|
||||
wrap: promise => promise,
|
||||
sendOptions: {},
|
||||
});
|
||||
|
||||
const expected = {
|
||||
status: 'skipped',
|
||||
|
@ -80,15 +99,18 @@ describe('Startup', () => {
|
|||
};
|
||||
|
||||
const actual = await Startup.syncReadReceiptConfiguration({
|
||||
ourNumber,
|
||||
deviceId,
|
||||
sendRequestConfigurationSyncMessage,
|
||||
storage,
|
||||
prepareForSend,
|
||||
});
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return error if sending of sync request fails', async () => {
|
||||
const ourNumber = '+15551234567';
|
||||
const deviceId = '2';
|
||||
|
||||
const sendRequestConfigurationSyncMessage = sandbox.stub();
|
||||
|
@ -105,11 +127,17 @@ describe('Startup', () => {
|
|||
},
|
||||
put: storagePutSpy,
|
||||
};
|
||||
const prepareForSend = () => ({
|
||||
wrap: promise => promise,
|
||||
sendOptions: {},
|
||||
});
|
||||
|
||||
const actual = await Startup.syncReadReceiptConfiguration({
|
||||
ourNumber,
|
||||
deviceId,
|
||||
sendRequestConfigurationSyncMessage,
|
||||
storage,
|
||||
prepareForSend,
|
||||
});
|
||||
|
||||
assert.equal(actual.status, 'error');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue