Merge pull request #1199 from vincentbavitz/utils-tests

Utils Tests
pull/1208/head
Vince 5 years ago committed by GitHub
commit cef647f110
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,6 +3,7 @@ interface ConversationAttributes {
left: boolean; left: boolean;
expireTimer: number; expireTimer: number;
profileSharing: boolean; profileSharing: boolean;
secondaryStatus: boolean;
mentionedUs: boolean; mentionedUs: boolean;
unreadCount: number; unreadCount: number;
isArchived: boolean; isArchived: boolean;

@ -1,7 +1,7 @@
import { ConversationType } from '../../ts/state/ducks/conversations'; import { ConversationType } from '../../ts/state/ducks/conversations';
import { Mesasge } from '../../ts/types/Message'; import { Message } from '../../ts/types/Message';
type IdentityKey = { export type IdentityKey = {
id: string; id: string;
publicKey: ArrayBuffer; publicKey: ArrayBuffer;
firstUse: boolean; firstUse: boolean;
@ -9,14 +9,14 @@ type IdentityKey = {
nonblockingApproval: boolean; nonblockingApproval: boolean;
}; };
type PreKey = { export type PreKey = {
id: number; id: number;
publicKey: ArrayBuffer; publicKey: ArrayBuffer;
privateKey: ArrayBuffer; privateKey: ArrayBuffer;
recipient: string; recipient: string;
}; };
type SignedPreKey = { export type SignedPreKey = {
id: number; id: number;
publicKey: ArrayBuffer; publicKey: ArrayBuffer;
privateKey: ArrayBuffer; privateKey: ArrayBuffer;
@ -25,14 +25,14 @@ type SignedPreKey = {
signature: ArrayBuffer; signature: ArrayBuffer;
}; };
type ContactPreKey = { export type ContactPreKey = {
id: number; id: number;
identityKeyString: string; identityKeyString: string;
publicKey: ArrayBuffer; publicKey: ArrayBuffer;
keyId: number; keyId: number;
}; };
type ContactSignedPreKey = { export type ContactSignedPreKey = {
id: number; id: number;
identityKeyString: string; identityKeyString: string;
publicKey: ArrayBuffer; publicKey: ArrayBuffer;
@ -42,18 +42,18 @@ type ContactSignedPreKey = {
confirmed: boolean; confirmed: boolean;
}; };
type PairingAuthorisation = { export type PairingAuthorisation = {
primaryDevicePubKey: string; primaryDevicePubKey: string;
secondaryDevicePubKey: string; secondaryDevicePubKey: string;
requestSignature: ArrayBuffer; requestSignature: ArrayBuffer;
grantSignature?: ArrayBuffer; grantSignature?: ArrayBuffer;
}; };
type GuardNode = { export type GuardNode = {
ed25519PubKey: string; ed25519PubKey: string;
}; };
type SwarmNode = { export type SwarmNode = {
address: string; address: string;
ip: string; ip: string;
port: string; port: string;
@ -61,19 +61,19 @@ type SwarmNode = {
pubkey_x25519: string; pubkey_x25519: string;
}; };
type StorageItem = { export type StorageItem = {
id: string; id: string;
value: any; value: any;
}; };
type SessionDataInfo = { export type SessionDataInfo = {
id: string; id: string;
number: string; number: string;
deviceId: number; deviceId: number;
record: string; record: string;
}; };
type ServerToken = { export type ServerToken = {
serverUrl: string; serverUrl: string;
token: string; token: string;
}; };

@ -34,7 +34,7 @@ export async function waitForTask<T>(
return Promise.race([timeoutPromise, taskPromise]) as Promise<T>; return Promise.race([timeoutPromise, taskPromise]) as Promise<T>;
} }
interface PollOptions { export interface PollOptions {
timeout: number; timeout: number;
interval: number; interval: number;
} }
@ -43,7 +43,7 @@ interface PollOptions {
* Creates a promise which calls the `task` every `interval` until `done` is called or until `timeout` period is reached. * Creates a promise which calls the `task` every `interval` until `done` is called or until `timeout` period is reached.
* If `timeout` is reached then this will throw an Error. * If `timeout` is reached then this will throw an Error.
* *
* @param check The check which runs every `interval` ms. * @param task The task which runs every `interval` ms.
* @param options The polling options. * @param options The polling options.
*/ */
export async function poll( export async function poll(

@ -1,7 +1,7 @@
import ByteBuffer from 'bytebuffer'; import ByteBuffer from 'bytebuffer';
type Encoding = 'base64' | 'hex' | 'binary' | 'utf8'; export type Encoding = 'base64' | 'hex' | 'binary' | 'utf8';
type BufferType = ByteBuffer | Buffer | ArrayBuffer | Uint8Array; export type BufferType = ByteBuffer | Buffer | ArrayBuffer | Uint8Array;
/** /**
* Take a string value with the given encoding and converts it to an `ArrayBuffer`. * Take a string value with the given encoding and converts it to an `ArrayBuffer`.

@ -1,5 +1,5 @@
import * as _ from 'lodash'; import * as _ from 'lodash';
import { UserUtil } from '../../util/'; import { UserUtil } from '../../util';
import { getAllConversations } from '../../../js/modules/data'; import { getAllConversations } from '../../../js/modules/data';
import { MultiDeviceProtocol } from '../protocols'; import { MultiDeviceProtocol } from '../protocols';
import ByteBuffer from 'bytebuffer'; import ByteBuffer from 'bytebuffer';
@ -73,10 +73,7 @@ export async function getSyncContacts(): Promise<Array<any> | undefined> {
.filter(c => c.id !== primaryDevice.key); .filter(c => c.id !== primaryDevice.key);
// Return unique contacts // Return unique contacts
return _.uniqBy( return _.uniqBy([...primaryContacts, ...secondaryContacts], 'id');
[...primaryContacts, ...secondaryContacts],
device => !!device
);
} }
export async function filterOpenGroupsConvos( export async function filterOpenGroupsConvos(

@ -1,6 +1,6 @@
import * as MessageUtils from './Messages'; import * as MessageUtils from './Messages';
import * as GroupUtils from './Groups'; import * as GroupUtils from './Groups';
import * as SyncMessageUtils from './SyncMessageUtils'; import * as SyncMessageUtils from './SyncMessage';
import * as StringUtils from './String'; import * as StringUtils from './String';
import * as PromiseUtils from './Promise'; import * as PromiseUtils from './Promise';

@ -0,0 +1,63 @@
import chai from 'chai';
import { TestUtils } from '../../test-utils/';
import { MessageUtils } from '../../../session/utils/';
import { PubKey } from '../../../session/types/';
// tslint:disable-next-line: no-require-imports no-var-requires
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const { expect } = chai;
describe('Message Utils', () => {
describe('toRawMessage', () => {
it('can convert to raw message', async () => {
const device = TestUtils.generateFakePubKey();
const message = TestUtils.generateChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message);
expect(Object.keys(rawMessage)).to.have.length(6);
expect(rawMessage.identifier).to.exist;
expect(rawMessage.device).to.exist;
expect(rawMessage.encryption).to.exist;
expect(rawMessage.plainTextBuffer).to.exist;
expect(rawMessage.timestamp).to.exist;
expect(rawMessage.ttl).to.exist;
});
it('should generate valid plainTextBuffer', async () => {
const device = TestUtils.generateFakePubKey();
const message = TestUtils.generateChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message);
const rawBuffer = rawMessage.plainTextBuffer;
const rawBufferJSON = JSON.stringify(rawBuffer);
const messageBufferJSON = JSON.stringify(message.plainTextBuffer());
expect(rawBuffer instanceof Uint8Array).to.equal(
true,
'raw message did not contain a plainTextBuffer'
);
expect(rawBufferJSON).to.equal(
messageBufferJSON,
'plainTextBuffer was not converted correctly'
);
});
it('should maintain pubkey', async () => {
const device = TestUtils.generateFakePubKey();
const message = TestUtils.generateChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message);
const derivedPubKey = PubKey.from(rawMessage.device);
expect(derivedPubKey).to.exist;
expect(derivedPubKey?.isEqual(device)).to.equal(
true,
'pubkey of message was not converted correctly'
);
});
});
});

@ -0,0 +1,141 @@
import chai from 'chai';
import * as sinon from 'sinon';
import { PromiseUtils } from '../../../session/utils/';
// tslint:disable-next-line: no-require-imports no-var-requires
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const { expect } = chai;
describe('Promise Utils', () => {
const sandbox = sinon.createSandbox();
let pollSpy: sinon.SinonSpy<
[
(done: (arg: any) => void) => Promise<void> | void,
(Partial<PromiseUtils.PollOptions> | undefined)?
],
Promise<void>
>;
let waitForTaskSpy: sinon.SinonSpy<
[(done: (arg: any) => void) => Promise<void> | void, (number | undefined)?],
Promise<unknown>
>;
let waitUntilSpy: sinon.SinonSpy<
[() => Promise<boolean> | boolean, (number | undefined)?],
Promise<void>
>;
beforeEach(() => {
pollSpy = sandbox.spy(PromiseUtils, 'poll');
waitForTaskSpy = sandbox.spy(PromiseUtils, 'waitForTask');
waitUntilSpy = sandbox.spy(PromiseUtils, 'waitUntil');
});
afterEach(() => {
sandbox.restore();
});
describe('poll', () => {
it('will call done on finished', async () => {
// completionSpy will be called on done
const completionSpy = sandbox.spy();
// tslint:disable-next-line: mocha-unneeded-done
const task = (done: any) => {
completionSpy();
done();
};
const promise = PromiseUtils.poll(task, {});
await expect(promise).to.be.fulfilled;
expect(pollSpy.callCount).to.equal(1);
expect(completionSpy.callCount).to.equal(1);
});
it('can timeout a task', async () => {
// completionSpy will be called on done
const completionSpy = sandbox.spy();
const task = (_done: any) => undefined;
const promise = PromiseUtils.poll(task, { timeout: 1 });
await expect(promise).to.be.rejectedWith('Periodic check timeout');
expect(pollSpy.callCount).to.equal(1);
expect(completionSpy.callCount).to.equal(0);
});
it('will recur according to interval option', async () => {
const expectedRecurrences = 4;
const timeout = 1000;
const interval = timeout / expectedRecurrences;
const recurrenceSpy = sandbox.spy();
const task = (done: any) => {
recurrenceSpy();
// Done after we've been called `expectedRecurrences` times
if (recurrenceSpy.callCount === expectedRecurrences) {
done();
}
};
const promise = PromiseUtils.poll(task, { timeout, interval });
await expect(promise).to.be.fulfilled;
expect(pollSpy.callCount).to.equal(1);
expect(recurrenceSpy.callCount).to.equal(expectedRecurrences);
});
});
describe('waitForTask', () => {
it('can wait for a task', async () => {
// completionSpy will be called on done
const completionSpy = sandbox.spy();
// tslint:disable-next-line: mocha-unneeded-done
const task = (done: any) => {
completionSpy();
done();
};
const promise = PromiseUtils.waitForTask(task);
await expect(promise).to.be.fulfilled;
expect(waitForTaskSpy.callCount).to.equal(1);
expect(completionSpy.callCount).to.equal(1);
});
it('can timeout a task', async () => {
// completionSpy will be called on done
const completionSpy = sandbox.spy();
const task = async (_done: any) => undefined;
const promise = PromiseUtils.waitForTask(task, 1);
await expect(promise).to.be.rejectedWith('Task timed out.');
expect(waitForTaskSpy.callCount).to.equal(1);
expect(completionSpy.callCount).to.equal(0);
});
});
describe('waitUntil', () => {
it('can wait for check', async () => {
const check = () => true;
const promise = PromiseUtils.waitUntil(check);
await expect(promise).to.be.fulfilled;
expect(waitUntilSpy.callCount).to.equal(1);
});
it('can timeout a check', async () => {
const check = () => false;
const promise = PromiseUtils.waitUntil(check, 1);
await expect(promise).to.be.rejectedWith('Periodic check timeout');
expect(waitUntilSpy.callCount).to.equal(1);
});
});
});

@ -0,0 +1,227 @@
import chai from 'chai';
import ByteBuffer from 'bytebuffer';
// Can't import type as StringUtils.Encoding
import { Encoding } from '../../../session/utils/String';
import { StringUtils } from '../../../session/utils/';
// tslint:disable-next-line: no-require-imports no-var-requires
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const { expect } = chai;
describe('String Utils', () => {
describe('encode', () => {
it('can encode to base64', async () => {
const testString = 'AAAAAAAAAA';
const encoded = StringUtils.encode(testString, 'base64');
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
it('can encode to hex', async () => {
const testString = 'AAAAAAAAAA';
const encoded = StringUtils.encode(testString, 'hex');
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
it('wont encode invalid hex', async () => {
const testString = 'ZZZZZZZZZZ';
const encoded = StringUtils.encode(testString, 'hex');
expect(encoded.byteLength).to.equal(0);
});
it('can encode to binary', async () => {
const testString = 'AAAAAAAAAA';
const encoded = StringUtils.encode(testString, 'binary');
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
it('can encode to utf8', async () => {
const testString = 'AAAAAAAAAA';
const encoded = StringUtils.encode(testString, 'binary');
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
it('can encode empty string', async () => {
const testString = '';
expect(testString).to.have.length(0);
const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array<
Encoding
>).map(e => StringUtils.encode(testString, e));
allEncodedings.forEach(encoded => {
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.equal(0);
});
});
it('can encode huge string', async () => {
const stringSize = Math.pow(2, 16);
const testString = Array(stringSize)
.fill('0')
.join('');
const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array<
Encoding
>).map(e => StringUtils.encode(testString, e));
allEncodedings.forEach(encoded => {
expect(encoded instanceof ArrayBuffer).to.equal(
true,
'a buffer was not returned from `encode`'
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
});
it("won't encode illegal string length in hex", async () => {
const testString = 'A';
const encode = () => StringUtils.encode(testString, 'hex');
// Ensure string is odd length
expect(testString.length % 2).to.equal(1);
expect(encode).to.throw('Illegal str: Length not a multiple of 2');
});
it('can encode obscure string', async () => {
const testString =
'↓←¶ᶑᵶ⅑⏕→⅓‎ᵹ⅙ᵰᶎ⅔⅗↔‌ᶈ⅞⸜ᶊᵴᶉ↉¥ᶖᶋᶃᶓ⏦ᵾᶂᶆ↕⸝ᶔᶐ⏔£⏙⅐⅒ᶌ⁁ᶘᶄᶒᶸ⅘‏⅚⅛ᶙᶇᶕᶀ↑ᵿ⏠ᶍᵯ⏖⏗⅜ᶚᶏ⁊‍ᶁᶗᵽᵼ⅝⏘⅖⅕⏡';
// Not valid hex format; try test the others
const encodings = ['base64', 'binary', 'utf8'] as Array<Encoding>;
encodings.forEach(encoding => {
const encoded = StringUtils.encode(testString, encoding);
expect(encoded instanceof ArrayBuffer).to.equal(
true,
`a buffer was not returned using encoding: '${encoding}'`
);
expect(encoded.byteLength).to.be.greaterThan(0);
});
});
});
describe('decode', () => {
it('can decode empty buffer', async () => {
const buffer = new ByteBuffer(0);
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length(0);
});
});
it('can decode huge buffer', async () => {
const bytes = Math.pow(2, 16);
const bufferString = Array(bytes)
.fill('A')
.join('');
const buffer = ByteBuffer.fromUTF8(bufferString);
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length.greaterThan(0);
});
});
it('can decode from ByteBuffer', async () => {
const buffer = ByteBuffer.fromUTF8('AAAAAAAAAA');
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length.greaterThan(0);
});
});
it('can decode from Buffer', async () => {
const arrayBuffer = new ArrayBuffer(10);
const buffer = Buffer.from(arrayBuffer);
buffer.writeUInt8(0, 0);
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length.greaterThan(0);
});
});
it('can decode from ArrayBuffer', async () => {
const buffer = new ArrayBuffer(10);
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length.greaterThan(0);
});
});
it('can decode from Uint8Array', async () => {
const buffer = new Uint8Array(10);
const encodings = ['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>;
// Each encoding should be valid
encodings.forEach(encoding => {
const decoded = StringUtils.decode(buffer, encoding);
expect(decoded).to.exist;
expect(typeof decoded === String.name.toLowerCase());
expect(decoded).to.have.length.greaterThan(0);
});
});
});
});

@ -0,0 +1,117 @@
import chai from 'chai';
import * as sinon from 'sinon';
import { SyncMessageUtils } from '../../../session/utils/';
import { TestUtils } from '../../test-utils';
import { UserUtil } from '../../../util';
import { MultiDeviceProtocol } from '../../../session/protocols';
import { SyncMessage } from '../../../session/messages/outgoing';
// tslint:disable-next-line: no-require-imports no-var-requires
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const { expect } = chai;
describe('Sync Message Utils', () => {
describe('getSyncContacts', () => {
let getAllConversationsStub: sinon.SinonStub;
let getOrCreateAndWaitStub: sinon.SinonStub;
let getOrCreatAndWaitItem: any;
// Fill half with secondaries, half with primaries
const numConversations = 20;
const primaryConversations = new Array(numConversations / 2)
.fill({})
.map(
() =>
new TestUtils.MockConversation({
type: TestUtils.MockConversationType.Primary,
})
);
const secondaryConversations = new Array(numConversations / 2)
.fill({})
.map(
() =>
new TestUtils.MockConversation({
type: TestUtils.MockConversationType.Secondary,
})
);
const conversations = [...primaryConversations, ...secondaryConversations];
const sandbox = sinon.createSandbox();
const ourDevice = TestUtils.generateFakePubKey();
const ourNumber = ourDevice.key;
const ourPrimaryDevice = TestUtils.generateFakePubKey();
beforeEach(async () => {
// Util Stubs
TestUtils.stubWindow('Whisper', {
ConversationCollection: sandbox.stub(),
});
getAllConversationsStub = TestUtils.stubData(
'getAllConversations'
).resolves(conversations);
// Scale result in sync with secondaryConversations on callCount
getOrCreateAndWaitStub = sandbox.stub().callsFake(() => {
const item =
secondaryConversations[getOrCreateAndWaitStub.callCount - 1];
// Make the item a primary device to match the call in SyncMessage under secondaryContactsPromise
getOrCreatAndWaitItem = {
...item,
getPrimaryDevicePubKey: () => item.id,
attributes: {
secondaryStatus: false,
},
};
return getOrCreatAndWaitItem;
});
TestUtils.stubWindow('ConversationController', {
getOrCreateAndWait: getOrCreateAndWaitStub,
});
// Stubs
sandbox.stub(UserUtil, 'getCurrentDevicePubKey').resolves(ourNumber);
sandbox
.stub(MultiDeviceProtocol, 'getPrimaryDevice')
.resolves(ourPrimaryDevice);
});
afterEach(() => {
sandbox.restore();
TestUtils.restoreStubs();
});
it('can get sync contacts with only primary contacts', async () => {
getAllConversationsStub.resolves(primaryConversations);
const contacts = await SyncMessageUtils.getSyncContacts();
expect(getAllConversationsStub.callCount).to.equal(1);
// Each contact should be a primary device
expect(contacts).to.have.length(numConversations / 2);
expect(contacts?.find(c => c.attributes.secondaryStatus)).to.not.exist;
});
it('can get sync contacts of assorted primaries and secondaries', async () => {
// Map secondary contacts to stub resolution
const contacts = await SyncMessageUtils.getSyncContacts();
expect(getAllConversationsStub.callCount).to.equal(1);
// We should have numConversations unique contacts
expect(contacts).to.have.length(numConversations);
// All contacts should be primary; half of which some from secondaries in secondaryContactsPromise
expect(contacts?.find(c => c.attributes.secondaryStatus)).to.not.exist;
expect(contacts?.filter(c => c.isPrimary)).to.have.length(
numConversations / 2
);
});
});
});

@ -5,7 +5,8 @@ import {
} from '../../../session/messages/outgoing'; } from '../../../session/messages/outgoing';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { OpenGroup } from '../../../session/types'; import { OpenGroup } from '../../../session/types';
import { generateFakePubKey } from './pubkey'; import { generateFakePubKey, generateFakePubKeys } from './pubkey';
import { ConversationAttributes } from '../../../../js/models/conversations';
export function generateChatMessage(identifier?: string): ChatMessage { export function generateChatMessage(identifier?: string): ChatMessage {
return new ChatMessage({ return new ChatMessage({
@ -46,3 +47,68 @@ export function generateClosedGroupMessage(
chatMessage: generateChatMessage(), chatMessage: generateChatMessage(),
}); });
} }
interface MockConversationParams {
id?: string;
type: MockConversationType;
members?: Array<string>;
}
export enum MockConversationType {
Primary = 'primary',
Secondary = 'secondary',
Group = 'group',
}
export class MockConversation {
public id: string;
public type: MockConversationType;
public attributes: ConversationAttributes;
public isPrimary?: boolean;
constructor(params: MockConversationParams) {
const dayInSeconds = 86400;
this.type = params.type;
this.id = params.id ?? generateFakePubKey().key;
this.isPrimary = this.type === MockConversationType.Primary;
const members =
this.type === MockConversationType.Group
? params.members ?? generateFakePubKeys(10).map(m => m.key)
: [];
this.attributes = {
members,
left: false,
expireTimer: dayInSeconds,
profileSharing: true,
mentionedUs: false,
unreadCount: 99,
isArchived: false,
active_at: Date.now(),
timestamp: Date.now(),
secondaryStatus: !this.isPrimary,
};
}
public isPrivate() {
return true;
}
public isOurLocalDevice() {
return false;
}
public isBlocked() {
return false;
}
public getPrimaryDevicePubKey() {
if (this.type === MockConversationType.Group) {
return undefined;
}
return this.isPrimary ? this.id : generateFakePubKey().key;
}
}

Loading…
Cancel
Save