Merge branch 'clearnet' into restore-handle-configuration

pull/1528/head
Audric Ackermann 4 years ago
commit c55f204440
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -533,7 +533,10 @@
displayName: newName,
avatar: newAvatarPath,
});
conversation.commit();
await conversation.commit();
await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded(
true
);
} catch (error) {
window.log.error(
'showEditProfileDialog Error ensuring that image is properly sized:',
@ -545,9 +548,13 @@
conversation.setLokiProfile({
displayName: newName,
});
// might be good to not trigger a sync if the name did not change
await conversation.commit();
await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded(
true
);
}
conversation.commit();
// inform all your registered public servers
// could put load on all the servers
// if they just keep changing their names without sending messages

@ -2,7 +2,7 @@
const { isFunction, isNumber } = require('lodash');
const { createLastMessageUpdate } = require('../../../ts/types/Conversation');
const { arrayBufferToBase64, base64ToArrayBuffer } = require('../crypto');
const { arrayBufferToBase64 } = require('../crypto');
async function computeHash(arraybuffer) {
const hash = await crypto.subtle.digest({ name: 'SHA-512' }, arraybuffer);
@ -146,5 +146,4 @@ module.exports = {
maybeUpdateProfileAvatar,
createLastMessageUpdate,
arrayBufferToBase64,
base64ToArrayBuffer,
};

@ -2,7 +2,7 @@
"name": "session-desktop",
"productName": "Session",
"description": "Private messaging from your desktop",
"version": "1.4.9",
"version": "1.4.10",
"license": "GPL-3.0",
"author": {
"name": "Loki Project",

@ -502,7 +502,7 @@ const {
window.BlockedNumberController = BlockedNumberController;
window.deleteAccount = async reason => {
const syncedMessageSent = async () => {
const deleteEverything = async () => {
window.log.info(
'configuration message sent successfully. Deleting everything'
);
@ -517,20 +517,18 @@ window.deleteAccount = async reason => {
try {
window.log.info('DeleteAccount => Sending a last SyncConfiguration');
// be sure to wait for the message being effectively sent. Otherwise we won't be able to encrypt it for our devices !
window.log.info('Sending one last configuration message.')
await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded(
true
);
window.log.info('Last configuration message sent!')
await syncedMessageSent();
window.log.info('Last configuration message sent!');
await deleteEverything();
} catch (error) {
window.log.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await syncedMessageSent();
await deleteEverything();
} catch (e) {
window.log.error(e);
}

@ -217,8 +217,19 @@ message ConfigurationMessage {
repeated bytes admins = 5;
}
message Contact {
optional bytes publicKey = 1;
optional string name = 2;
optional string profilePicture = 3;
optional bytes profileKey = 4;
}
repeated ClosedGroup closedGroups = 1;
repeated string openGroups = 2;
optional string displayName = 3;
optional string profilePicture = 4;
optional bytes profileKey = 5;
repeated Contact contacts = 6;
}
message ReceiptMessage {

@ -11,13 +11,12 @@ import {
import { MessageCollection, MessageModel } from '../models/message';
import { HexKeyPair } from '../receiver/keypairs';
import { PubKey } from '../session/types';
import {
fromArrayBufferToBase64,
fromBase64ToArrayBuffer,
} from '../session/utils/String';
import { ConversationType } from '../state/ducks/conversations';
const {
base64ToArrayBuffer,
arrayBufferToBase64,
} = require('../../js/modules/crypto');
const DATABASE_UPDATE_TIMEOUT = 2 * 60 * 1000; // two minutes
const SQL_CHANNEL_KEY = 'sql-channel';
@ -371,7 +370,7 @@ function keysToArrayBuffer(keys: any, data: any) {
const value = _.get(data, key);
if (value) {
_.set(updated, key, base64ToArrayBuffer(value));
_.set(updated, key, fromBase64ToArrayBuffer(value));
}
}
@ -385,7 +384,7 @@ function keysFromArrayBuffer(keys: any, data: any) {
const value = _.get(data, key);
if (value) {
_.set(updated, key, arrayBufferToBase64(value));
_.set(updated, key, fromArrayBufferToBase64(value));
}
}

@ -30,6 +30,10 @@ import {
removeMessage as dataRemoveMessage,
updateConversation,
} from '../../ts/data/data';
import {
fromArrayBufferToBase64,
fromBase64ToArrayBuffer,
} from '../session/utils/String';
export interface OurLokiProfile {
displayName: string;
@ -837,7 +841,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (profileKey && typeof profileKey !== 'string') {
// eslint-disable-next-line no-param-reassign
// tslint:disable-next-line: no-parameter-reassignment
profileKey = window.Signal.Crypto.arrayBufferToBase64(profileKey);
profileKey = fromArrayBufferToBase64(profileKey);
}
const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer(
this.get('server')
@ -1312,7 +1316,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
await this.commit();
}
}
public async setProfileKey(profileKey: any) {
public async setProfileKey(profileKey: string) {
// profileKey is a string so we can compare it directly
if (this.get('profileKey') !== profileKey) {
this.set({
@ -1336,15 +1340,11 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
try {
const profileKeyBuffer = window.Signal.Crypto.base64ToArrayBuffer(
profileKey
);
const profileKeyBuffer = fromBase64ToArrayBuffer(profileKey);
const accessKeyBuffer = await window.Signal.Crypto.deriveAccessKey(
profileKeyBuffer
);
const accessKey = window.Signal.Crypto.arrayBufferToBase64(
accessKeyBuffer
);
const accessKey = fromArrayBufferToBase64(accessKeyBuffer);
this.set({ accessKey });
} catch (e) {
window.log.warn(`Failed to derive access key for ${this.id}`);

@ -2,6 +2,7 @@ import _ from 'lodash';
import { MessageModel } from '../models/message';
import { saveMessage } from '../../ts/data/data';
import { fromBase64ToArrayBuffer } from '../session/utils/String';
export async function downloadAttachment(attachment: any) {
const serverUrl = new URL(attachment.url).origin;
@ -64,8 +65,8 @@ export async function downloadAttachment(attachment: any) {
data = await window.textsecure.crypto.decryptAttachment(
data,
window.Signal.Crypto.base64ToArrayBuffer(key),
window.Signal.Crypto.base64ToArrayBuffer(digest)
fromBase64ToArrayBuffer(key),
fromBase64ToArrayBuffer(digest)
);
if (!size || size !== data.byteLength) {

@ -5,6 +5,7 @@ export const TTL_DEFAULT = {
TYPING_MESSAGE: 20 * SECONDS,
REGULAR_MESSAGE: 2 * DAYS,
ENCRYPTION_PAIR_GROUP: 4 * DAYS,
CONFIGURATION_MESSAGE: 4 * DAYS,
};
// User Interface

@ -444,10 +444,28 @@ async function sendAddedMembers(
expireTimer,
});
// if an expire timer is set, we have to send it to the joining members
// let expirationTimerMessage: ExpirationTimerUpdateMessage | undefined;
// if (expireTimer && expireTimer > 0) {
// const expireUpdate = {
// timestamp: Date.now(),
// expireTimer,
// groupId: groupId,
// };
// expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdate);
// }
const promises = addedMembers.map(async m => {
await ConversationController.getInstance().getOrCreateAndWait(m, 'private');
const memberPubKey = PubKey.cast(m);
await getMessageQueue().sendToPubKey(memberPubKey, newClosedGroupUpdate);
// if (expirationTimerMessage) {
// await getMessageQueue().sendToPubKey(
// memberPubKey,
// expirationTimerMessage
// );
// }
});
await Promise.all(promises);
}

@ -11,16 +11,28 @@ import { PubKey } from '../../../types';
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');
@ -29,10 +41,26 @@ export class ConfigurationMessage extends ContentMessage {
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 ttl(): number {
return Constants.TTL_DEFAULT.TYPING_MESSAGE;
return Constants.TTL_DEFAULT.CONFIGURATION_MESSAGE;
}
public contentProto(): SignalService.Content {
@ -45,15 +73,73 @@ export class ConfigurationMessage extends ContentMessage {
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 =>
new ConfigurationMessageClosedGroup(m).toProto()
);
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 constructor({
publicKey,
displayName,
profilePictureURL,
profileKey,
}: {
publicKey: string;
displayName: string;
profilePictureURL?: string;
profileKey?: Uint8Array;
}) {
this.publicKey = publicKey;
this.displayName = displayName;
this.profilePictureURL = profilePictureURL;
this.profileKey = profileKey;
// 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,
});
}
}

@ -6,14 +6,6 @@ import {
import { EncryptionType, PubKey } from '../types';
import { ClosedGroupMessage } from '../messages/outgoing/content/data/group/ClosedGroupMessage';
import { ClosedGroupNewMessage } from '../messages/outgoing/content/data/group/ClosedGroupNewMessage';
import {
ConfigurationMessage,
ConfigurationMessageClosedGroup,
} from '../messages/outgoing/content/ConfigurationMessage';
import uuid from 'uuid';
import { getLatestClosedGroupEncryptionKeyPair } from '../../../ts/data/data';
import { UserUtils } from '.';
import { ECKeyPair } from '../../receiver/keypairs';
import _ from 'lodash';
import { ConversationModel } from '../../models/conversation';
import { ClosedGroupEncryptionPairReplyMessage } from '../messages/outgoing/content/data/group/ClosedGroupEncryptionPairReplyMessage';
@ -64,53 +56,3 @@ export async function toRawMessage(
return rawMessage;
}
export const getCurrentConfigurationMessage = async (
convos: Array<ConversationModel>
) => {
const ourPubKey = UserUtils.getOurPubKeyStrFromCache();
const openGroupsIds = convos
.filter(c => !!c.get('active_at') && c.isPublic() && !c.get('left'))
.map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array<
string
>;
const closedGroupModels = convos.filter(
c =>
!!c.get('active_at') &&
c.isMediumGroup() &&
c.get('members').includes(ourPubKey) &&
!c.get('left') &&
!c.get('isKickedFromGroup') &&
!c.isBlocked()
);
const closedGroups = await Promise.all(
closedGroupModels.map(async c => {
const groupPubKey = c.get('id');
const fetchEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair(
groupPubKey
);
if (!fetchEncryptionKeyPair) {
return null;
}
return new ConfigurationMessageClosedGroup({
publicKey: groupPubKey,
name: c.get('name') || '',
members: c.get('members') || [],
admins: c.get('groupAdmins') || [],
encryptionKeyPair: ECKeyPair.fromHexKeyPair(fetchEncryptionKeyPair),
});
})
);
const onlyValidClosedGroup = closedGroups.filter(m => m !== null) as Array<
ConfigurationMessageClosedGroup
>;
return new ConfigurationMessage({
identifier: uuid(),
timestamp: Date.now(),
activeOpenGroups: openGroupsIds,
activeClosedGroups: onlyValidClosedGroup,
});
};

@ -34,3 +34,7 @@ export const toHex = (d: BufferType) => decode(d, 'hex');
export const fromHex = (d: string) => encode(d, 'hex');
export const fromHexToArray = (d: string) => new Uint8Array(encode(d, 'hex'));
export const fromBase64ToArrayBuffer = (d: string) => encode(d, 'base64');
export const fromArrayBufferToBase64 = (d: BufferType) => decode(d, 'base64');

@ -1,9 +1,21 @@
import { createOrUpdateItem, getItemById } from '../../../ts/data/data';
import {
createOrUpdateItem,
getItemById,
getLatestClosedGroupEncryptionKeyPair,
} from '../../../ts/data/data';
import { getMessageQueue } from '..';
import { ConversationController } from '../conversations';
import { getCurrentConfigurationMessage } from './Messages';
import { RawMessage } from '../types';
import { DAYS } from './Number';
import uuid from 'uuid';
import { UserUtils } from '.';
import { ECKeyPair } from '../../receiver/keypairs';
import {
ConfigurationMessage,
ConfigurationMessageClosedGroup,
ConfigurationMessageContact,
} from '../messages/outgoing/content/ConfigurationMessage';
import { ConversationModel } from '../../models/conversation';
import { fromHexToArray } from './String';
const ITEM_ID_LAST_SYNC_TIMESTAMP = 'lastSyncedTimestamp';
@ -42,37 +54,130 @@ export const syncConfigurationIfNeeded = async () => {
export const forceSyncConfigurationNowIfNeeded = async (
waitForMessageSent = false
) => {
const allConvos = ConversationController.getInstance().getConversations();
const configMessage = await getCurrentConfigurationMessage(allConvos);
) =>
new Promise(resolve => {
const allConvos = ConversationController.getInstance().getConversations();
async function waitForMessageSentEvent(message: RawMessage) {
return new Promise(resolve => {
if (message.identifier === configMessage.identifier) {
// might have fail in fact
debugger;
resolve(true);
void getCurrentConfigurationMessage(allConvos).then(configMessage => {
// console.warn('forceSyncConfigurationNowIfNeeded with', configMessage);
try {
// this just adds the message to the sending queue.
// if waitForMessageSent is set, we need to effectively wait until then
// tslint:disable-next-line: no-void-expression
const callback = waitForMessageSent
? () => {
resolve(true);
}
: undefined;
void getMessageQueue().sendSyncMessage(configMessage, callback as any);
// either we resolve from the callback if we need to wait for it,
// or we don't want to wait, we resolve it here.
if (!waitForMessageSent) {
resolve(true);
}
} catch (e) {
window.log.warn(
'Caught an error while sending our ConfigurationMessage:',
e
);
resolve(false);
}
});
}
});
try {
// passing the callback like that
if (waitForMessageSent) {
await getMessageQueue().sendSyncMessage(
configMessage,
waitForMessageSentEvent as any
export const getCurrentConfigurationMessage = async (
convos: Array<ConversationModel>
) => {
const ourPubKey = UserUtils.getOurPubKeyStrFromCache();
const ourConvo = convos.find(convo => convo.id === ourPubKey);
// Filter open groups
const openGroupsIds = convos
.filter(c => !!c.get('active_at') && c.isPublic() && !c.get('left'))
.map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array<
string
>;
// Filter Closed/Medium groups
const closedGroupModels = convos.filter(
c =>
!!c.get('active_at') &&
c.isMediumGroup() &&
c.get('members').includes(ourPubKey) &&
!c.get('left') &&
!c.get('isKickedFromGroup') &&
!c.isBlocked() &&
c.get('name')
);
const closedGroups = await Promise.all(
closedGroupModels.map(async c => {
const groupPubKey = c.get('id');
const fetchEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair(
groupPubKey
);
return waitForMessageSentEvent;
} else {
await getMessageQueue().sendSyncMessage(configMessage);
}
} catch (e) {
window.log.warn(
'Caught an error while sending our ConfigurationMessage:',
e
if (!fetchEncryptionKeyPair) {
return null;
}
return new ConfigurationMessageClosedGroup({
publicKey: groupPubKey,
name: c.get('name') || '',
members: c.get('members') || [],
admins: c.get('groupAdmins') || [],
encryptionKeyPair: ECKeyPair.fromHexKeyPair(fetchEncryptionKeyPair),
});
})
);
const onlyValidClosedGroup = closedGroups.filter(m => m !== null) as Array<
ConfigurationMessageClosedGroup
>;
// Filter contacts
const contactsModels = convos.filter(
c =>
!!c.get('active_at') &&
c.getLokiProfile()?.displayName &&
c.isPrivate() &&
!c.isBlocked()
);
const contacts = contactsModels.map(c => {
const profileKeyForContact = c.get('profileKey')
? fromHexToArray(c.get('profileKey') as string)
: undefined;
return new ConfigurationMessageContact({
publicKey: c.id,
displayName: c.getLokiProfile()?.displayName,
profilePictureURL: c.get('avatarPointer'),
profileKey: profileKeyForContact,
});
});
if (!ourConvo) {
window.log.error(
'Could not find our convo while building a configuration message.'
);
}
const profileKeyFromStorage = window.storage.get('profileKey');
const profileKey = profileKeyFromStorage
? new Uint8Array(profileKeyFromStorage)
: undefined;
const profilePicture = ourConvo?.get('avatarPointer') || undefined;
const displayName = ourConvo?.getLokiProfile()?.displayName || undefined;
return Promise.resolve();
return new ConfigurationMessage({
identifier: uuid(),
timestamp: Date.now(),
activeOpenGroups: openGroupsIds,
activeClosedGroups: onlyValidClosedGroup,
displayName,
profilePicture,
profileKey,
contacts,
});
};

@ -4,9 +4,11 @@ import { ECKeyPair } from '../../../../receiver/keypairs';
import {
ConfigurationMessage,
ConfigurationMessageClosedGroup,
ConfigurationMessageContact,
} from '../../../../session/messages/outgoing/content/ConfigurationMessage';
import { TestUtils } from '../../../test-utils';
// tslint:disable-next-line: max-func-body-length
describe('ConfigurationMessage', () => {
it('throw if closed group is not set', () => {
const activeClosedGroups = null as any;
@ -14,6 +16,8 @@ describe('ConfigurationMessage', () => {
activeClosedGroups,
activeOpenGroups: [],
timestamp: Date.now(),
displayName: 'displayName',
contacts: [],
};
expect(() => new ConfigurationMessage(params)).to.throw(
'closed group must be set'
@ -26,12 +30,52 @@ describe('ConfigurationMessage', () => {
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(4 * 24 * 60 * 60 * 1000);
});
describe('ConfigurationMessageClosedGroup', () => {
it('throw if closed group has no encryptionkeypair', () => {
const member = TestUtils.generateFakePubKey().key;
@ -137,4 +181,92 @@ describe('ConfigurationMessage', () => {
);
});
});
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
const params = {
publicKey: TestUtils.generateFakePubKey().key,
displayName: undefined as any,
};
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 profileAvatar 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'
);
});
});
});

@ -35,7 +35,9 @@ describe('ConfigurationMessage_receiving', () => {
activeOpenGroups: [],
activeClosedGroups: [],
timestamp: Date.now(),
identifier: 'whatever',
identifier: 'identifier',
displayName: 'displayName',
contacts: [],
});
});

@ -218,6 +218,8 @@ describe('Message Utils', () => {
timestamp: Date.now(),
activeOpenGroups: [],
activeClosedGroups: [],
displayName: 'displayName',
contacts: [],
});
const rawMessage = await MessageUtils.toRawMessage(device, msg);
expect(rawMessage.encryption).to.equal(EncryptionType.Fallback);

Loading…
Cancel
Save