Accept profile keys for unknown members in groups

This commit is contained in:
trevor-signal 2023-10-13 21:14:46 -04:00 committed by GitHub
parent c892febdbc
commit b6f1b8b577
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 32 deletions

View file

@ -5464,7 +5464,7 @@ function profileKeyHasChanged(
function hasProfileKey(userId: ServiceIdString) {
const conversation = window.ConversationController.get(userId);
if (!conversation) {
return true;
return false;
}
const existingBase64 = conversation.get('profileKey');

View file

@ -72,6 +72,7 @@ export type BootstrapOptions = Readonly<{
linkedDevices?: number;
contactCount?: number;
contactsWithoutProfileKey?: number;
unknownContactCount?: number;
contactNames?: ReadonlyArray<string>;
contactPreKeyCount?: number;
}>;
@ -82,6 +83,7 @@ type BootstrapInternalOptions = Pick<BootstrapOptions, 'extraConfig'> &
linkedDevices: number;
contactCount: number;
contactsWithoutProfileKey: number;
unknownContactCount: number;
contactNames: ReadonlyArray<string>;
}>;
@ -116,6 +118,7 @@ export class Bootstrap {
private readonly options: BootstrapInternalOptions;
private privContacts?: ReadonlyArray<PrimaryDevice>;
private privContactsWithoutProfileKey?: ReadonlyArray<PrimaryDevice>;
private privUnknownContacts?: ReadonlyArray<PrimaryDevice>;
private privPhone?: PrimaryDevice;
private privDesktop?: Device;
private storagePath?: string;
@ -132,6 +135,7 @@ export class Bootstrap {
linkedDevices: 5,
contactCount: MAX_CONTACTS,
contactsWithoutProfileKey: 0,
unknownContactCount: 0,
contactNames: CONTACT_NAMES,
benchmark: false,
@ -139,7 +143,9 @@ export class Bootstrap {
};
assert(
this.options.contactCount + this.options.contactsWithoutProfileKey <=
this.options.contactCount +
this.options.contactsWithoutProfileKey +
this.options.unknownContactCount <=
this.options.contactNames.length
);
}
@ -152,13 +158,8 @@ export class Bootstrap {
const { port } = this.server.address();
debug('started server on port=%d', port);
const contactNames = this.options.contactNames.slice(
0,
this.options.contactCount + this.options.contactsWithoutProfileKey
);
const allContacts = await Promise.all(
contactNames.map(async profileName => {
this.options.contactNames.map(async profileName => {
const primary = await this.server.createPrimaryDevice({
profileName,
});
@ -172,9 +173,14 @@ export class Bootstrap {
})
);
this.privContacts = allContacts.slice(0, this.options.contactCount);
this.privContactsWithoutProfileKey = allContacts.slice(
this.contacts.length
this.privContacts = allContacts.splice(0, this.options.contactCount);
this.privContactsWithoutProfileKey = allContacts.splice(
0,
this.options.contactsWithoutProfileKey
);
this.privUnknownContacts = allContacts.splice(
0,
this.options.unknownContactCount
);
this.privPhone = await this.server.createPrimaryDevice({
@ -386,9 +392,20 @@ export class Bootstrap {
);
return this.privContactsWithoutProfileKey;
}
public get unknownContacts(): ReadonlyArray<PrimaryDevice> {
assert(
this.privUnknownContacts,
'Bootstrap has to be initialized first, see: bootstrap.init()'
);
return this.privUnknownContacts;
}
public get allContacts(): ReadonlyArray<PrimaryDevice> {
return [...this.contacts, ...this.contactsWithoutProfileKey];
return [
...this.contacts,
...this.contactsWithoutProfileKey,
...this.unknownContacts,
];
}
//

View file

@ -22,18 +22,13 @@ describe('unknown contacts', function (this: Mocha.Suite) {
let unknownContact: PrimaryDevice;
beforeEach(async () => {
bootstrap = new Bootstrap();
bootstrap = new Bootstrap({ contactCount: 1, unknownContactCount: 1 });
await bootstrap.init();
app = await bootstrap.link();
page = await app.getWindow();
const { server, desktop } = bootstrap;
unknownContact = await server.createPrimaryDevice({
profileName: 'Hugh Ameye',
});
const ourKey = await desktop.popSingleUseKey();
await unknownContact.addSingleUseKey(desktop, ourKey);
const { unknownContacts } = bootstrap;
[unknownContact] = unknownContacts;
});
afterEach(async function (this: Mocha.Context) {

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import type { Group } from '@signalapp/mock-server';
import type { Group, PrimaryDevice } from '@signalapp/mock-server';
import { Proto, ServiceIdKind } from '@signalapp/mock-server';
import createDebug from 'debug';
@ -19,18 +19,22 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
let bootstrap: Bootstrap;
let app: App;
let group: Group;
let unknownContact: PrimaryDevice;
beforeEach(async () => {
bootstrap = new Bootstrap();
bootstrap = new Bootstrap({
contactCount: 10,
unknownContactCount: 3,
});
await bootstrap.init();
const { contacts } = bootstrap;
const { contacts, unknownContacts } = bootstrap;
const [first, second] = contacts;
[unknownContact] = unknownContacts;
group = await first.createGroup({
title: 'Invite by PNI',
members: [first, second],
members: [first, second, unknownContact],
});
app = await bootstrap.link();
@ -42,7 +46,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
});
// Verify that created group has pending member
assert.strictEqual(group.state?.members?.length, 2);
assert.strictEqual(group.state?.members?.length, 3);
assert(!group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));
@ -77,7 +81,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
group = await phone.waitForGroupUpdate(group);
assert.strictEqual(group.revision, 2);
assert.strictEqual(group.state?.members?.length, 3);
assert.strictEqual(group.state?.members?.length, 4);
assert(group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));
@ -109,13 +113,22 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
.locator('.module-message-request-actions button >> "Accept"')
.waitFor({ state: 'hidden' });
debug('Leave the group through settings');
await window
.locator('button.module-ConversationHeader__button--more')
.click();
await window.locator('.react-contextmenu-item >> "Group settings"').click();
debug(
'Checking that we see all members of group, including (previously) unknown contact'
);
await window
.locator('.ConversationDetails-panel-section__title >> "4 members"')
.waitFor();
await window.getByText(unknownContact.profileName).waitFor();
debug('Leave the group through settings');
await conversationStack
.locator('.conversation-details-panel >> "Leave group"')
.click();
@ -125,7 +138,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
debug('Waiting for final group update');
group = await phone.waitForGroupUpdate(group);
assert.strictEqual(group.revision, 4);
assert.strictEqual(group.state?.members?.length, 2);
assert.strictEqual(group.state?.members?.length, 3);
assert(!group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));
@ -149,7 +162,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
group = await phone.waitForGroupUpdate(group);
assert.strictEqual(group.revision, 2);
assert.strictEqual(group.state?.members?.length, 2);
assert.strictEqual(group.state?.members?.length, 3);
assert(!group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));
@ -209,7 +222,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
group = await phone.waitForGroupUpdate(group);
assert.strictEqual(group.revision, 3);
assert.strictEqual(group.state?.members?.length, 3);
assert.strictEqual(group.state?.members?.length, 4);
assert(group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));
@ -261,7 +274,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
group = await phone.waitForGroupUpdate(group);
assert.strictEqual(group.revision, 3);
assert.strictEqual(group.state?.members?.length, 2);
assert.strictEqual(group.state?.members?.length, 3);
assert(!group.getMemberByServiceId(desktop.aci));
assert(!group.getMemberByServiceId(desktop.pni));
assert(!group.getPendingMemberByServiceId(desktop.aci));