fix: remove all of the ConfiguratioMessage (legacy) logic
parent
0fbb0cc852
commit
c9b2d69a73
@ -1,217 +0,0 @@
|
|||||||
// this is not a very good name, but a configuration message is a message sent to our other devices so sync our current public and closed groups
|
|
||||||
|
|
||||||
import { SignalService } from '../../../../protobuf';
|
|
||||||
import { MessageParams } from '../Message';
|
|
||||||
import { ECKeyPair } from '../../../../receiver/keypairs';
|
|
||||||
import { fromHexToArray } from '../../../utils/String';
|
|
||||||
import { PubKey } from '../../../types';
|
|
||||||
import { ContentMessage } from '..';
|
|
||||||
|
|
||||||
interface ConfigurationMessageParams extends MessageParams {
|
|
||||||
activeClosedGroups: Array<ConfigurationMessageClosedGroup>;
|
|
||||||
activeOpenGroups: Array<string>;
|
|
||||||
displayName: string;
|
|
||||||
profilePicture?: string;
|
|
||||||
profileKey?: Uint8Array;
|
|
||||||
contacts: Array<ConfigurationMessageContact>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ConfigurationMessage extends ContentMessage {
|
|
||||||
public readonly activeClosedGroups: Array<ConfigurationMessageClosedGroup>;
|
|
||||||
public readonly activeOpenGroups: Array<string>;
|
|
||||||
public readonly displayName: string;
|
|
||||||
public readonly profilePicture?: string;
|
|
||||||
public readonly profileKey?: Uint8Array;
|
|
||||||
public readonly contacts: Array<ConfigurationMessageContact>;
|
|
||||||
|
|
||||||
constructor(params: ConfigurationMessageParams) {
|
|
||||||
super({ timestamp: params.timestamp, identifier: params.identifier });
|
|
||||||
this.activeClosedGroups = params.activeClosedGroups;
|
|
||||||
this.activeOpenGroups = params.activeOpenGroups;
|
|
||||||
this.displayName = params.displayName;
|
|
||||||
this.profilePicture = params.profilePicture;
|
|
||||||
this.profileKey = params.profileKey;
|
|
||||||
this.contacts = params.contacts;
|
|
||||||
|
|
||||||
if (!this.activeClosedGroups) {
|
|
||||||
throw new Error('closed group must be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.activeOpenGroups) {
|
|
||||||
throw new Error('open group must be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.displayName || !this.displayName?.length) {
|
|
||||||
throw new Error('displayName must be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.profilePicture && typeof this.profilePicture !== 'string') {
|
|
||||||
throw new Error('profilePicture set but not an Uin8Array');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.profileKey && !(this.profileKey instanceof Uint8Array)) {
|
|
||||||
throw new Error('profileKey set but not an Uin8Array');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.contacts) {
|
|
||||||
throw new Error('contacts must be set');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public contentProto(): SignalService.Content {
|
|
||||||
return new SignalService.Content({
|
|
||||||
configurationMessage: this.configurationProto(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configurationProto(): SignalService.ConfigurationMessage {
|
|
||||||
return new SignalService.ConfigurationMessage({
|
|
||||||
closedGroups: this.mapClosedGroupsObjectToProto(this.activeClosedGroups),
|
|
||||||
openGroups: this.activeOpenGroups,
|
|
||||||
displayName: this.displayName,
|
|
||||||
profilePicture: this.profilePicture,
|
|
||||||
profileKey: this.profileKey,
|
|
||||||
contacts: this.mapContactsObjectToProto(this.contacts),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapClosedGroupsObjectToProto(
|
|
||||||
closedGroups: Array<ConfigurationMessageClosedGroup>
|
|
||||||
): Array<SignalService.ConfigurationMessage.ClosedGroup> {
|
|
||||||
return (closedGroups || []).map(m => m.toProto());
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapContactsObjectToProto(
|
|
||||||
contacts: Array<ConfigurationMessageContact>
|
|
||||||
): Array<SignalService.ConfigurationMessage.Contact> {
|
|
||||||
return (contacts || []).map(m => m.toProto());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ConfigurationMessageContact {
|
|
||||||
public publicKey: string;
|
|
||||||
public displayName: string;
|
|
||||||
public profilePictureURL?: string;
|
|
||||||
public profileKey?: Uint8Array;
|
|
||||||
public isApproved?: boolean;
|
|
||||||
public isBlocked?: boolean;
|
|
||||||
public didApproveMe?: boolean;
|
|
||||||
|
|
||||||
public constructor({
|
|
||||||
publicKey,
|
|
||||||
displayName,
|
|
||||||
profilePictureURL,
|
|
||||||
profileKey,
|
|
||||||
isApproved,
|
|
||||||
isBlocked,
|
|
||||||
didApproveMe,
|
|
||||||
}: {
|
|
||||||
publicKey: string;
|
|
||||||
displayName: string;
|
|
||||||
profilePictureURL?: string;
|
|
||||||
profileKey?: Uint8Array;
|
|
||||||
isApproved?: boolean;
|
|
||||||
isBlocked?: boolean;
|
|
||||||
didApproveMe?: boolean;
|
|
||||||
}) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.profilePictureURL = profilePictureURL;
|
|
||||||
this.profileKey = profileKey;
|
|
||||||
this.isApproved = isApproved;
|
|
||||||
this.isBlocked = isBlocked;
|
|
||||||
this.didApproveMe = didApproveMe;
|
|
||||||
|
|
||||||
// will throw if public key is invalid
|
|
||||||
PubKey.cast(publicKey);
|
|
||||||
|
|
||||||
if (this.displayName?.length === 0) {
|
|
||||||
throw new Error('displayName must be set or undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.profilePictureURL !== undefined && this.profilePictureURL?.length === 0) {
|
|
||||||
throw new Error('profilePictureURL must either undefined or not empty');
|
|
||||||
}
|
|
||||||
if (this.profileKey !== undefined && this.profileKey?.length === 0) {
|
|
||||||
throw new Error('profileKey must either undefined or not empty');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public toProto(): SignalService.ConfigurationMessage.Contact {
|
|
||||||
return new SignalService.ConfigurationMessage.Contact({
|
|
||||||
publicKey: fromHexToArray(this.publicKey),
|
|
||||||
name: this.displayName,
|
|
||||||
profilePicture: this.profilePictureURL,
|
|
||||||
profileKey: this.profileKey,
|
|
||||||
isApproved: this.isApproved,
|
|
||||||
isBlocked: this.isBlocked,
|
|
||||||
didApproveMe: this.didApproveMe,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ConfigurationMessageClosedGroup {
|
|
||||||
public publicKey: string;
|
|
||||||
public name: string;
|
|
||||||
public encryptionKeyPair: ECKeyPair;
|
|
||||||
public members: Array<string>;
|
|
||||||
public admins: Array<string>;
|
|
||||||
|
|
||||||
public constructor({
|
|
||||||
publicKey,
|
|
||||||
name,
|
|
||||||
encryptionKeyPair,
|
|
||||||
members,
|
|
||||||
admins,
|
|
||||||
}: {
|
|
||||||
publicKey: string;
|
|
||||||
name: string;
|
|
||||||
encryptionKeyPair: ECKeyPair;
|
|
||||||
members: Array<string>;
|
|
||||||
admins: Array<string>;
|
|
||||||
}) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.name = name;
|
|
||||||
this.encryptionKeyPair = encryptionKeyPair;
|
|
||||||
this.members = members;
|
|
||||||
this.admins = admins;
|
|
||||||
|
|
||||||
// will throw if publik key is invalid
|
|
||||||
PubKey.cast(publicKey);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!encryptionKeyPair?.privateKeyData?.byteLength ||
|
|
||||||
!encryptionKeyPair?.publicKeyData?.byteLength
|
|
||||||
) {
|
|
||||||
throw new Error('Encryption key pair looks invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.name?.length) {
|
|
||||||
throw new Error('name must be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.members?.length) {
|
|
||||||
throw new Error('members must be set');
|
|
||||||
}
|
|
||||||
if (!this.admins?.length) {
|
|
||||||
throw new Error('admins must be set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.admins.some(a => !this.members.includes(a))) {
|
|
||||||
throw new Error('some admins are not members');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public toProto(): SignalService.ConfigurationMessage.ClosedGroup {
|
|
||||||
return new SignalService.ConfigurationMessage.ClosedGroup({
|
|
||||||
publicKey: fromHexToArray(this.publicKey),
|
|
||||||
name: this.name,
|
|
||||||
encryptionKeyPair: {
|
|
||||||
publicKey: this.encryptionKeyPair.publicKeyData,
|
|
||||||
privateKey: this.encryptionKeyPair.privateKeyData,
|
|
||||||
},
|
|
||||||
members: this.members.map(fromHexToArray),
|
|
||||||
admins: this.admins.map(fromHexToArray),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,251 +0,0 @@
|
|||||||
import { expect } from 'chai';
|
|
||||||
import { ECKeyPair } from '../../../../receiver/keypairs';
|
|
||||||
import { TTL_DEFAULT } from '../../../../session/constants';
|
|
||||||
|
|
||||||
import {
|
|
||||||
ConfigurationMessage,
|
|
||||||
ConfigurationMessageClosedGroup,
|
|
||||||
ConfigurationMessageContact,
|
|
||||||
} from '../../../../session/messages/outgoing/controlMessage/ConfigurationMessage';
|
|
||||||
import { TestUtils } from '../../../test-utils';
|
|
||||||
|
|
||||||
describe('ConfigurationMessage', () => {
|
|
||||||
it('throw if closed group is not set', () => {
|
|
||||||
const activeClosedGroups = null as any;
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups,
|
|
||||||
activeOpenGroups: [],
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: 'displayName',
|
|
||||||
contacts: [],
|
|
||||||
};
|
|
||||||
expect(() => new ConfigurationMessage(params)).to.throw('closed group must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if open group is not set', () => {
|
|
||||||
const activeOpenGroups = null as any;
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups: [],
|
|
||||||
activeOpenGroups,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: 'displayName',
|
|
||||||
contacts: [],
|
|
||||||
};
|
|
||||||
expect(() => new ConfigurationMessage(params)).to.throw('open group must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if display name is not set', () => {
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups: [],
|
|
||||||
activeOpenGroups: [],
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: undefined as any,
|
|
||||||
contacts: [],
|
|
||||||
};
|
|
||||||
expect(() => new ConfigurationMessage(params)).to.throw('displayName must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if display name is set but empty', () => {
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups: [],
|
|
||||||
activeOpenGroups: [],
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: undefined as any,
|
|
||||||
contacts: [],
|
|
||||||
};
|
|
||||||
expect(() => new ConfigurationMessage(params)).to.throw('displayName must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ttl is 4 days', () => {
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups: [],
|
|
||||||
activeOpenGroups: [],
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: 'displayName',
|
|
||||||
contacts: [],
|
|
||||||
};
|
|
||||||
const configMessage = new ConfigurationMessage(params);
|
|
||||||
expect(configMessage.ttl()).to.be.equal(TTL_DEFAULT.TTL_MAX);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ConfigurationMessageClosedGroup', () => {
|
|
||||||
it('throw if closed group has no encryptionkeypair', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [member],
|
|
||||||
encryptionKeyPair: undefined as any,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw(
|
|
||||||
'Encryption key pair looks invalid'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if closed group has invalid encryptionkeypair', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [member],
|
|
||||||
encryptionKeyPair: new ECKeyPair(new Uint8Array(), new Uint8Array()),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw(
|
|
||||||
'Encryption key pair looks invalid'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if closed group has invalid pubkey', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: 'invalidpubkey',
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [member],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if closed group has invalid name', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: '',
|
|
||||||
members: [member],
|
|
||||||
admins: [member],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('name must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if members is empty', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [],
|
|
||||||
admins: [member],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('members must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if admins is empty', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('admins must be set');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if some admins are not members', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const admin = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [admin],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw(
|
|
||||||
'some admins are not members'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ConfigurationMessageContact', () => {
|
|
||||||
it('throws if contacts is not set', () => {
|
|
||||||
const params = {
|
|
||||||
activeClosedGroups: [],
|
|
||||||
activeOpenGroups: [],
|
|
||||||
timestamp: Date.now(),
|
|
||||||
displayName: 'displayName',
|
|
||||||
contacts: undefined as any,
|
|
||||||
};
|
|
||||||
expect(() => new ConfigurationMessage(params)).to.throw('contacts must be set');
|
|
||||||
});
|
|
||||||
it('throw if some admins are not members', () => {
|
|
||||||
const member = TestUtils.generateFakePubKey().key;
|
|
||||||
const admin = TestUtils.generateFakePubKey().key;
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
name: 'groupname',
|
|
||||||
members: [member],
|
|
||||||
admins: [admin],
|
|
||||||
encryptionKeyPair: TestUtils.generateFakeECKeyPair(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageClosedGroup(params)).to.throw(
|
|
||||||
'some admins are not members'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if the contact has not a valid pubkey', () => {
|
|
||||||
const params = {
|
|
||||||
publicKey: '05',
|
|
||||||
displayName: 'contactDisplayName',
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params)).to.throw();
|
|
||||||
|
|
||||||
const params2 = {
|
|
||||||
publicKey: undefined as any,
|
|
||||||
displayName: 'contactDisplayName',
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params2)).to.throw();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if the contact has an empty display name', () => {
|
|
||||||
// a display name cannot be empty nor undefined
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params2)).to.throw();
|
|
||||||
|
|
||||||
const params2 = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
displayName: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params2)).to.throw();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if the contact has a profilePictureURL set but empty', () => {
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
displayName: 'contactDisplayName',
|
|
||||||
profilePictureURL: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params)).to.throw(
|
|
||||||
'profilePictureURL must either undefined or not empty'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throw if the contact has a profileKey set but empty', () => {
|
|
||||||
const params = {
|
|
||||||
publicKey: TestUtils.generateFakePubKey().key,
|
|
||||||
displayName: 'contactDisplayName',
|
|
||||||
profileKey: new Uint8Array(),
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => new ConfigurationMessageContact(params)).to.throw(
|
|
||||||
'profileKey must either undefined or not empty'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,20 +1,5 @@
|
|||||||
// `missingCaseError` is useful for compile-time checking that all `case`s in
|
// `missingCaseError` is useful for compile-time checking that all `case`s in
|
||||||
// a `switch` statement have been handled, e.g.
|
// a `switch` statement have been handled, e.g.
|
||||||
//
|
//
|
||||||
// type AttachmentType = 'media' | 'documents';
|
|
||||||
//
|
|
||||||
// const type: AttachmentType = selectedTab;
|
|
||||||
// switch (type) {
|
|
||||||
// case 'media':
|
|
||||||
// return <MediaGridItem/>;
|
|
||||||
// case 'documents':
|
|
||||||
// return <DocumentListItem/>;
|
|
||||||
// default:
|
|
||||||
// return missingCaseError(type);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// If we extended `AttachmentType` to `'media' | 'documents' | 'links'` the code
|
|
||||||
// above would trigger a compiler error stating that `'links'` has not been
|
|
||||||
// handled by our `switch` / `case` statement which is useful for code
|
|
||||||
// maintenance and system evolution.
|
|
||||||
export const missingCaseError = (x: never): TypeError => new TypeError(`Unhandled case: ${x}`);
|
export const missingCaseError = (x: never): TypeError => new TypeError(`Unhandled case: ${x}`);
|
||||||
|
Loading…
Reference in New Issue