signal-desktop/ts/test-electron/util/sendToGroup_test.ts

348 lines
9 KiB
TypeScript
Raw Normal View History

2021-05-25 22:40:04 +00:00
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
2022-07-08 20:46:25 +00:00
import * as sinon from 'sinon';
import { LibSignalErrorBase } from '@signalapp/libsignal-client';
2021-05-25 22:40:04 +00:00
import {
_analyzeSenderKeyDevices,
_shouldFailSend,
} from '../../util/sendToGroup';
2022-07-08 20:46:25 +00:00
import { UUID } from '../../types/UUID';
2021-05-25 22:40:04 +00:00
import type { DeviceType } from '../../textsecure/Types.d';
import {
ConnectTimeoutError,
HTTPError,
IncorrectSenderKeyAuthError,
MessageError,
OutgoingIdentityKeyError,
OutgoingMessageError,
SendMessageChallengeError,
SendMessageNetworkError,
SendMessageProtoError,
UnknownRecipientError,
UnregisteredUserError,
} from '../../textsecure/Errors';
2021-05-25 22:40:04 +00:00
describe('sendToGroup', () => {
2022-07-08 20:46:25 +00:00
const uuidOne = UUID.generate().toString();
const uuidTwo = UUID.generate().toString();
let sandbox: sinon.SinonSandbox;
beforeEach(() => {
sandbox = sinon.createSandbox();
const stub = sandbox.stub(UUID, 'lookup');
stub.withArgs(uuidOne).returns(new UUID(uuidOne));
stub.withArgs(uuidTwo).returns(new UUID(uuidTwo));
stub.returns(undefined);
});
afterEach(() => {
sandbox.restore();
});
2021-05-25 22:40:04 +00:00
describe('#_analyzeSenderKeyDevices', () => {
function getDefaultDeviceList(): Array<DeviceType> {
return [
{
2022-07-08 20:46:25 +00:00
identifier: uuidOne,
2021-05-25 22:40:04 +00:00
id: 1,
registrationId: 11,
2021-05-25 22:40:04 +00:00
},
{
2022-07-08 20:46:25 +00:00
identifier: uuidOne,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 22,
2021-05-25 22:40:04 +00:00
},
{
2022-07-08 20:46:25 +00:00
identifier: uuidTwo,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 33,
2021-05-25 22:40:04 +00:00
},
];
}
it('returns nothing if new and previous lists are the same', () => {
const memberDevices = getDefaultDeviceList();
const devicesForSend = getDefaultDeviceList();
const {
newToMemberDevices,
newToMemberUuids,
removedFromMemberDevices,
removedFromMemberUuids,
} = _analyzeSenderKeyDevices(memberDevices, devicesForSend);
assert.isEmpty(newToMemberDevices);
assert.isEmpty(newToMemberUuids);
assert.isEmpty(removedFromMemberDevices);
assert.isEmpty(removedFromMemberUuids);
});
it('returns set of new devices', () => {
const memberDevices = getDefaultDeviceList();
const devicesForSend = getDefaultDeviceList();
memberDevices.pop();
memberDevices.pop();
const {
newToMemberDevices,
newToMemberUuids,
removedFromMemberDevices,
removedFromMemberUuids,
} = _analyzeSenderKeyDevices(memberDevices, devicesForSend);
assert.deepEqual(newToMemberDevices, [
{
2022-07-08 20:46:25 +00:00
identifier: uuidOne,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 22,
2021-05-25 22:40:04 +00:00
},
{
2022-07-08 20:46:25 +00:00
identifier: uuidTwo,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 33,
2021-05-25 22:40:04 +00:00
},
]);
2022-07-08 20:46:25 +00:00
assert.deepEqual(newToMemberUuids, [uuidOne, uuidTwo]);
2021-05-25 22:40:04 +00:00
assert.isEmpty(removedFromMemberDevices);
assert.isEmpty(removedFromMemberUuids);
});
it('returns set of removed devices', () => {
const memberDevices = getDefaultDeviceList();
const devicesForSend = getDefaultDeviceList();
devicesForSend.pop();
devicesForSend.pop();
const {
newToMemberDevices,
newToMemberUuids,
removedFromMemberDevices,
removedFromMemberUuids,
} = _analyzeSenderKeyDevices(memberDevices, devicesForSend);
assert.isEmpty(newToMemberDevices);
assert.isEmpty(newToMemberUuids);
assert.deepEqual(removedFromMemberDevices, [
{
2022-07-08 20:46:25 +00:00
identifier: uuidOne,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 22,
2021-05-25 22:40:04 +00:00
},
{
2022-07-08 20:46:25 +00:00
identifier: uuidTwo,
2021-05-25 22:40:04 +00:00
id: 2,
registrationId: 33,
2021-05-25 22:40:04 +00:00
},
]);
2022-07-08 20:46:25 +00:00
assert.deepEqual(removedFromMemberUuids, [uuidOne, uuidTwo]);
2021-05-25 22:40:04 +00:00
});
it('returns empty removals if partial send', () => {
const memberDevices = getDefaultDeviceList();
const devicesForSend = getDefaultDeviceList();
devicesForSend.pop();
devicesForSend.pop();
const isPartialSend = true;
const {
newToMemberDevices,
newToMemberUuids,
removedFromMemberDevices,
removedFromMemberUuids,
} = _analyzeSenderKeyDevices(
memberDevices,
devicesForSend,
isPartialSend
);
assert.isEmpty(newToMemberDevices);
assert.isEmpty(newToMemberUuids);
assert.isEmpty(removedFromMemberDevices);
assert.isEmpty(removedFromMemberUuids);
});
});
describe('#_shouldFailSend', () => {
it('returns false for a generic error', async () => {
const error = new Error('generic');
assert.isFalse(_shouldFailSend(error, 'testing generic'));
});
it("returns true for any error with 'untrusted' identity", async () => {
const error = new LibSignalErrorBase(
'untrusted identity',
'UntrustedIdentity',
'ignored'
);
assert.isTrue(_shouldFailSend(error, 'logId'));
});
it('returns true for certain types of error subclasses', async () => {
assert.isTrue(
_shouldFailSend(
new OutgoingIdentityKeyError('something'),
'testing OutgoingIdentityKeyError'
)
);
assert.isTrue(
_shouldFailSend(
new UnregisteredUserError(
'something',
new HTTPError('something', {
code: 400,
headers: {},
})
),
'testing UnregisteredUserError'
)
);
assert.isTrue(
_shouldFailSend(
new ConnectTimeoutError('something'),
'testing ConnectTimeoutError'
)
);
});
it('returns false for unspecified error codes', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const error: any = new Error('generic');
error.code = 422;
assert.isFalse(_shouldFailSend(error, 'testing generic 422'));
error.code = 204;
assert.isFalse(_shouldFailSend(error, 'testing generic 204'));
});
it('returns false for specific errors', () => {
const unknownRecipient = new UnknownRecipientError();
assert.isFalse(
_shouldFailSend(unknownRecipient, 'testing unknown recipient')
);
const incorrectAuth = new IncorrectSenderKeyAuthError();
assert.isFalse(_shouldFailSend(incorrectAuth, 'testing incorrect auth'));
});
it('returns true for a specified error codes', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const error: any = new Error('generic');
error.code = 428;
assert.isTrue(_shouldFailSend(error, 'testing generic'));
assert.isTrue(
_shouldFailSend(
new HTTPError('something', {
code: 404,
headers: {},
}),
'testing HTTPError'
)
);
assert.isTrue(
_shouldFailSend(
new OutgoingMessageError(
'something',
null,
null,
new HTTPError('something', {
code: 413,
headers: {},
})
),
'testing OutgoingMessageError'
)
);
assert.isTrue(
_shouldFailSend(
new OutgoingMessageError(
'something',
null,
null,
new HTTPError('something', {
code: 429,
headers: {},
})
),
'testing OutgoingMessageError'
)
);
assert.isTrue(
_shouldFailSend(
new SendMessageNetworkError(
'something',
null,
new HTTPError('something', {
code: 428,
headers: {},
})
),
'testing SendMessageNetworkError'
)
);
assert.isTrue(
_shouldFailSend(
new SendMessageChallengeError(
'something',
new HTTPError('something', {
code: 500,
headers: {},
})
),
'testing SendMessageChallengeError'
)
);
assert.isTrue(
_shouldFailSend(
new MessageError(
'something',
new HTTPError('something', {
code: 508,
headers: {},
})
),
'testing MessageError'
)
);
});
it('returns true for errors inside of SendMessageProtoError', () => {
assert.isTrue(
_shouldFailSend(
new SendMessageProtoError({}),
'testing missing errors list'
)
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const error: any = new Error('generic');
error.code = 428;
assert.isTrue(
_shouldFailSend(
new SendMessageProtoError({ errors: [error] }),
'testing one error with code'
)
);
assert.isTrue(
_shouldFailSend(
new SendMessageProtoError({
errors: [
new Error('something'),
new ConnectTimeoutError('something'),
],
}),
'testing ConnectTimeoutError'
)
);
});
});
2021-05-25 22:40:04 +00:00
});