Accept profile keys for unknown members in groups
This commit is contained in:
parent
c892febdbc
commit
b6f1b8b577
4 changed files with 57 additions and 32 deletions
|
@ -5464,7 +5464,7 @@ function profileKeyHasChanged(
|
||||||
function hasProfileKey(userId: ServiceIdString) {
|
function hasProfileKey(userId: ServiceIdString) {
|
||||||
const conversation = window.ConversationController.get(userId);
|
const conversation = window.ConversationController.get(userId);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingBase64 = conversation.get('profileKey');
|
const existingBase64 = conversation.get('profileKey');
|
||||||
|
|
|
@ -72,6 +72,7 @@ export type BootstrapOptions = Readonly<{
|
||||||
linkedDevices?: number;
|
linkedDevices?: number;
|
||||||
contactCount?: number;
|
contactCount?: number;
|
||||||
contactsWithoutProfileKey?: number;
|
contactsWithoutProfileKey?: number;
|
||||||
|
unknownContactCount?: number;
|
||||||
contactNames?: ReadonlyArray<string>;
|
contactNames?: ReadonlyArray<string>;
|
||||||
contactPreKeyCount?: number;
|
contactPreKeyCount?: number;
|
||||||
}>;
|
}>;
|
||||||
|
@ -82,6 +83,7 @@ type BootstrapInternalOptions = Pick<BootstrapOptions, 'extraConfig'> &
|
||||||
linkedDevices: number;
|
linkedDevices: number;
|
||||||
contactCount: number;
|
contactCount: number;
|
||||||
contactsWithoutProfileKey: number;
|
contactsWithoutProfileKey: number;
|
||||||
|
unknownContactCount: number;
|
||||||
contactNames: ReadonlyArray<string>;
|
contactNames: ReadonlyArray<string>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ export class Bootstrap {
|
||||||
private readonly options: BootstrapInternalOptions;
|
private readonly options: BootstrapInternalOptions;
|
||||||
private privContacts?: ReadonlyArray<PrimaryDevice>;
|
private privContacts?: ReadonlyArray<PrimaryDevice>;
|
||||||
private privContactsWithoutProfileKey?: ReadonlyArray<PrimaryDevice>;
|
private privContactsWithoutProfileKey?: ReadonlyArray<PrimaryDevice>;
|
||||||
|
private privUnknownContacts?: ReadonlyArray<PrimaryDevice>;
|
||||||
private privPhone?: PrimaryDevice;
|
private privPhone?: PrimaryDevice;
|
||||||
private privDesktop?: Device;
|
private privDesktop?: Device;
|
||||||
private storagePath?: string;
|
private storagePath?: string;
|
||||||
|
@ -132,6 +135,7 @@ export class Bootstrap {
|
||||||
linkedDevices: 5,
|
linkedDevices: 5,
|
||||||
contactCount: MAX_CONTACTS,
|
contactCount: MAX_CONTACTS,
|
||||||
contactsWithoutProfileKey: 0,
|
contactsWithoutProfileKey: 0,
|
||||||
|
unknownContactCount: 0,
|
||||||
contactNames: CONTACT_NAMES,
|
contactNames: CONTACT_NAMES,
|
||||||
benchmark: false,
|
benchmark: false,
|
||||||
|
|
||||||
|
@ -139,7 +143,9 @@ export class Bootstrap {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
this.options.contactCount + this.options.contactsWithoutProfileKey <=
|
this.options.contactCount +
|
||||||
|
this.options.contactsWithoutProfileKey +
|
||||||
|
this.options.unknownContactCount <=
|
||||||
this.options.contactNames.length
|
this.options.contactNames.length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -152,13 +158,8 @@ export class Bootstrap {
|
||||||
const { port } = this.server.address();
|
const { port } = this.server.address();
|
||||||
debug('started server on port=%d', port);
|
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(
|
const allContacts = await Promise.all(
|
||||||
contactNames.map(async profileName => {
|
this.options.contactNames.map(async profileName => {
|
||||||
const primary = await this.server.createPrimaryDevice({
|
const primary = await this.server.createPrimaryDevice({
|
||||||
profileName,
|
profileName,
|
||||||
});
|
});
|
||||||
|
@ -172,9 +173,14 @@ export class Bootstrap {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.privContacts = allContacts.slice(0, this.options.contactCount);
|
this.privContacts = allContacts.splice(0, this.options.contactCount);
|
||||||
this.privContactsWithoutProfileKey = allContacts.slice(
|
this.privContactsWithoutProfileKey = allContacts.splice(
|
||||||
this.contacts.length
|
0,
|
||||||
|
this.options.contactsWithoutProfileKey
|
||||||
|
);
|
||||||
|
this.privUnknownContacts = allContacts.splice(
|
||||||
|
0,
|
||||||
|
this.options.unknownContactCount
|
||||||
);
|
);
|
||||||
|
|
||||||
this.privPhone = await this.server.createPrimaryDevice({
|
this.privPhone = await this.server.createPrimaryDevice({
|
||||||
|
@ -386,9 +392,20 @@ export class Bootstrap {
|
||||||
);
|
);
|
||||||
return this.privContactsWithoutProfileKey;
|
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> {
|
public get allContacts(): ReadonlyArray<PrimaryDevice> {
|
||||||
return [...this.contacts, ...this.contactsWithoutProfileKey];
|
return [
|
||||||
|
...this.contacts,
|
||||||
|
...this.contactsWithoutProfileKey,
|
||||||
|
...this.unknownContacts,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -22,18 +22,13 @@ describe('unknown contacts', function (this: Mocha.Suite) {
|
||||||
let unknownContact: PrimaryDevice;
|
let unknownContact: PrimaryDevice;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
bootstrap = new Bootstrap();
|
bootstrap = new Bootstrap({ contactCount: 1, unknownContactCount: 1 });
|
||||||
await bootstrap.init();
|
await bootstrap.init();
|
||||||
app = await bootstrap.link();
|
app = await bootstrap.link();
|
||||||
page = await app.getWindow();
|
page = await app.getWindow();
|
||||||
|
|
||||||
const { server, desktop } = bootstrap;
|
const { unknownContacts } = bootstrap;
|
||||||
unknownContact = await server.createPrimaryDevice({
|
[unknownContact] = unknownContacts;
|
||||||
profileName: 'Hugh Ameye',
|
|
||||||
});
|
|
||||||
|
|
||||||
const ourKey = await desktop.popSingleUseKey();
|
|
||||||
await unknownContact.addSingleUseKey(desktop, ourKey);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function (this: Mocha.Context) {
|
afterEach(async function (this: Mocha.Context) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
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 { Proto, ServiceIdKind } from '@signalapp/mock-server';
|
||||||
import createDebug from 'debug';
|
import createDebug from 'debug';
|
||||||
|
|
||||||
|
@ -19,18 +19,22 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
let bootstrap: Bootstrap;
|
let bootstrap: Bootstrap;
|
||||||
let app: App;
|
let app: App;
|
||||||
let group: Group;
|
let group: Group;
|
||||||
|
let unknownContact: PrimaryDevice;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
bootstrap = new Bootstrap();
|
bootstrap = new Bootstrap({
|
||||||
|
contactCount: 10,
|
||||||
|
unknownContactCount: 3,
|
||||||
|
});
|
||||||
await bootstrap.init();
|
await bootstrap.init();
|
||||||
|
|
||||||
const { contacts } = bootstrap;
|
const { contacts, unknownContacts } = bootstrap;
|
||||||
|
|
||||||
const [first, second] = contacts;
|
const [first, second] = contacts;
|
||||||
|
[unknownContact] = unknownContacts;
|
||||||
|
|
||||||
group = await first.createGroup({
|
group = await first.createGroup({
|
||||||
title: 'Invite by PNI',
|
title: 'Invite by PNI',
|
||||||
members: [first, second],
|
members: [first, second, unknownContact],
|
||||||
});
|
});
|
||||||
|
|
||||||
app = await bootstrap.link();
|
app = await bootstrap.link();
|
||||||
|
@ -42,7 +46,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify that created group has pending member
|
// 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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
||||||
|
@ -77,7 +81,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
|
|
||||||
group = await phone.waitForGroupUpdate(group);
|
group = await phone.waitForGroupUpdate(group);
|
||||||
assert.strictEqual(group.revision, 2);
|
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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
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"')
|
.locator('.module-message-request-actions button >> "Accept"')
|
||||||
.waitFor({ state: 'hidden' });
|
.waitFor({ state: 'hidden' });
|
||||||
|
|
||||||
debug('Leave the group through settings');
|
|
||||||
await window
|
await window
|
||||||
.locator('button.module-ConversationHeader__button--more')
|
.locator('button.module-ConversationHeader__button--more')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
await window.locator('.react-contextmenu-item >> "Group settings"').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
|
await conversationStack
|
||||||
.locator('.conversation-details-panel >> "Leave group"')
|
.locator('.conversation-details-panel >> "Leave group"')
|
||||||
.click();
|
.click();
|
||||||
|
@ -125,7 +138,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
debug('Waiting for final group update');
|
debug('Waiting for final group update');
|
||||||
group = await phone.waitForGroupUpdate(group);
|
group = await phone.waitForGroupUpdate(group);
|
||||||
assert.strictEqual(group.revision, 4);
|
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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
||||||
|
@ -149,7 +162,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
|
|
||||||
group = await phone.waitForGroupUpdate(group);
|
group = await phone.waitForGroupUpdate(group);
|
||||||
assert.strictEqual(group.revision, 2);
|
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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
||||||
|
@ -209,7 +222,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
|
|
||||||
group = await phone.waitForGroupUpdate(group);
|
group = await phone.waitForGroupUpdate(group);
|
||||||
assert.strictEqual(group.revision, 3);
|
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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
||||||
|
@ -261,7 +274,7 @@ describe('pnp/accept gv2 invite', function (this: Mocha.Suite) {
|
||||||
|
|
||||||
group = await phone.waitForGroupUpdate(group);
|
group = await phone.waitForGroupUpdate(group);
|
||||||
assert.strictEqual(group.revision, 3);
|
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.aci));
|
||||||
assert(!group.getMemberByServiceId(desktop.pni));
|
assert(!group.getMemberByServiceId(desktop.pni));
|
||||||
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
assert(!group.getPendingMemberByServiceId(desktop.aci));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue