session-desktop/ts/test/session/unit/libsession_wrapper/libsession_wrapper_contacts...

299 lines
11 KiB
TypeScript

import { expect } from 'chai';
import { from_hex, from_string } from 'libsodium-wrappers-sumo';
// tslint:disable: chai-vague-errors no-unused-expression no-http-string no-octal-literal whitespace no-require-imports variable-name
import * as SessionUtilWrapper from 'session_util_wrapper';
describe('libsession_contacts', () => {
// Note: To run this test, you need to compile the libsession wrapper for node (and not for electron).
// To do this, you can cd to the node_module/libsession_wrapper folder and do
// yarn configure && yarn build
// once that is done, you can rename this file and remove the _skip suffix so that test is run.
// We have to disable it by filename as nodejs tries to load the module during the import step above, and fails as it is not compiled for nodejs but for electron.
it('libsession_contacts', () => {
const edSecretKey = from_hex(
'0123456789abcdef0123456789abcdef000000000000000000000000000000004cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7'
);
// const SessionUtilWrapper = require('session_util_wrapper');
// Initialize a brand new, empty config because we have no dump data to deal with.
const contacts = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
// We don't need to push anything, since this is an empty config
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(false);
const real_id = '050000000000000000000000000000000000000000000000000000000000000000';
// Since it's empty there shouldn't be a get result.
expect(contacts.get(real_id)).to.be.null;
const created = contacts.getOrCreate(real_id);
expect(created).to.be.not.null;
expect(created.id).to.be.eq(real_id);
expect(created.name).to.be.null;
expect(created.nickname).to.be.null;
expect(created.approved).to.be.eq(false);
expect(created.approvedMe).to.be.eq(false);
expect(created.blocked).to.be.eq(false);
expect(created.id).to.be.eq(real_id);
expect(created.profilePicture?.url).to.be.eq(undefined);
expect(created.profilePicture?.key).to.be.eq(undefined);
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(false);
expect(contacts.push().seqno === 0);
created.name = 'Joe';
created.nickname = 'Joey';
created.approved = true;
created.approvedMe = true;
contacts.set(created);
let updated = contacts.get(real_id);
expect(updated).to.not.be.null;
expect(updated).to.not.be.undefined;
expect(updated?.id).to.be.eq(real_id);
expect(updated?.name).to.be.eq('Joe');
expect(updated?.nickname).to.be.eq('Joey');
expect(updated?.approved).to.be.true;
expect(updated?.approvedMe).to.be.true;
expect(updated?.blocked).to.be.false;
expect(updated?.profilePicture).to.be.undefined;
created.profilePicture = { key: new Uint8Array([1, 2, 3]), url: 'fakeUrl' };
contacts.set(created);
const updated2 = contacts.get(real_id);
expect(updated2?.profilePicture?.url).to.be.deep.eq('fakeUrl');
expect(updated2?.profilePicture?.key).to.be.deep.eq(new Uint8Array([1, 2, 3]));
expect(contacts.needsPush()).to.be.eql(true);
expect(contacts.needsDump()).to.be.eql(true);
let push1 = contacts.push();
expect(push1.seqno).to.be.eq(1);
// Pretend we uploaded it
contacts.confirmPushed(push1.seqno);
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(true);
const dump = contacts.dump();
const contacts2 = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, dump);
expect(contacts2.needsPush()).to.be.eql(false);
expect(contacts2.needsDump()).to.be.eql(false);
expect(contacts2.push().seqno).to.be.eq(1);
// Because we just called dump() above, to load up
// contacts2.
expect(contacts2.needsDump()).to.be.eql(false);
const x = contacts2.get(real_id);
expect(x?.id).to.be.eq(real_id);
expect(x?.name).to.be.eq('Joe');
expect(x?.nickname).to.be.eq('Joey');
expect(x?.approved).to.be.true;
expect(x?.approvedMe).to.be.true;
expect(x?.blocked).to.be.false;
const anotherId = '051111111111111111111111111111111111111111111111111111111111111111';
contacts2.getOrCreate(anotherId);
contacts2.set({
id: anotherId,
});
// We're not setting any fields, but we should still keep a record of the session id
expect(contacts2.needsPush()).to.be.true;
let push2 = contacts2.push();
push1.seqno = push2.seqno;
push1.data = push2.data;
expect(push1.seqno).to.be.equal(2);
contacts.merge([push1.data]);
contacts2.confirmPushed(push1.seqno);
expect(contacts.needsPush()).to.be.false;
expect(contacts.push().seqno).to.be.eq(push1.seqno);
// Iterate through and make sure we got everything we expected
const allContacts = contacts.getAll();
const session_ids = allContacts.map((m: any) => m.id);
const nicknames = allContacts.map((m: any) => m.nickname || '(N/A)');
expect(session_ids.length).to.be.eq(2);
expect(session_ids).to.be.deep.eq([real_id, anotherId]);
expect(nicknames).to.be.deep.eq(['Joey', '(N/A)']);
// Conflict! Oh no!
// On client 1 delete a contact:
contacts.erase(real_id);
const shouldBeErased = contacts.get(real_id);
expect(shouldBeErased).to.be.null;
// Client 2 adds a new friend:
const third_id = '052222222222222222222222222222222222222222222222222222222222222222';
contacts2.setNickname(third_id, 'Nickname 3');
contacts2.setApproved(third_id, true);
contacts2.setBlocked(third_id, true);
contacts2.setProfilePicture(third_id, 'http://example.com/huge.bmp', from_string('qwerty'));
expect(contacts.needsPush()).to.be.true;
expect(contacts2.needsPush()).to.be.true;
push1 = contacts.push();
push2 = contacts2.push();
expect(push1.seqno).to.be.eq(push2.seqno);
expect(push1.data).to.not.be.deep.eq(push2.data);
contacts.confirmPushed(push1.seqno);
contacts2.confirmPushed(push2.seqno);
contacts.merge([push2.data]);
expect(contacts.needsPush()).to.be.true;
contacts2.merge([push1.data]);
expect(contacts2.needsPush()).to.be.true;
push1 = contacts.push();
expect(push1.seqno).to.be.eq(push2.seqno + 1);
push2 = contacts2.push();
expect(push1.seqno).to.be.deep.eq(push2.seqno);
expect(push1.data).to.be.deep.eq(push2.data);
contacts.confirmPushed(push1.seqno);
contacts2.confirmPushed(push2.seqno);
expect(contacts.needsPush()).to.be.false;
expect(contacts2.needsPush()).to.be.false;
const allContacts2 = contacts.getAll();
const sessionIds2 = allContacts2.map((m: any) => m.id);
const nicknames2 = allContacts2.map((m: any) => m.nickname || '(N/A)');
expect(sessionIds2.length).to.be.eq(2);
expect(nicknames2.length).to.be.eq(2);
expect(sessionIds2).to.be.deep.eq([anotherId, third_id]);
expect(nicknames2).to.be.deep.eq(['(N/A)', 'Nickname 3']);
});
it('libsession_contacts_c', () => {
const edSecretKey = from_hex(
'0123456789abcdef0123456789abcdef000000000000000000000000000000004cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7'
);
const SessionUtilWrapper = require('session_util_wrapper');
// Initialize a brand new, empty config because we have no dump data to deal with.
const contacts = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
const realId = '050000000000000000000000000000000000000000000000000000000000000000';
expect(contacts.get(realId)).to.be.null;
const c = contacts.getOrCreate(realId);
expect(c.id).to.be.eq(realId);
expect(c.name).to.be.null;
expect(c.nickname).to.be.null;
expect(c.approved).to.be.false;
expect(c.approvedMe).to.be.false;
expect(c.blocked).to.be.false;
expect(c.profilePicture?.key).to.be.undefined;
expect(c.profilePicture?.url).to.be.undefined;
c.name = 'Joe';
c.nickname = 'Joey';
c.approved = true;
c.approvedMe = true;
contacts.set(c); // FIXME use .set when ready
// contacts.setName(real_id, c.name);
// contacts.setNickname(real_id, c.nickname);
// contacts.setApproved(real_id, c.approved);
// contacts.setApprovedMe(real_id, c.approvedMe);
const c2 = contacts.getOrCreate(realId);
expect(c2.name).to.be.eq('Joe');
expect(c2.nickname).to.be.eq('Joey');
expect(c2.approved).to.be.true;
expect(c2.approvedMe).to.be.true;
expect(c2.blocked).to.be.false;
expect(c2.profilePicture?.key).to.be.undefined;
expect(c2.profilePicture?.url).to.be.undefined;
expect(contacts.needsDump()).to.be.true;
expect(contacts.needsPush()).to.be.true;
let push1 = contacts.push();
expect(push1.seqno).to.be.equal(1);
const contacts2 = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
let accepted = contacts2.merge([push1.data]);
expect(accepted).to.be.equal(1);
contacts.confirmPushed(push1.seqno);
let c3 = contacts2.getOrCreate(realId);
expect(c3.name).to.be.eq('Joe');
expect(c3.nickname).to.be.eq('Joey');
expect(c3.approved).to.be.true;
expect(c3.approvedMe).to.be.true;
expect(c3.blocked).to.be.false;
expect(c3.profilePicture?.key).to.be.undefined;
expect(c3.profilePicture?.url).to.be.undefined;
const another_id = '051111111111111111111111111111111111111111111111111111111111111111';
c3 = contacts.getOrCreate(another_id);
expect(c3.name).to.be.null;
expect(c3.nickname).to.be.null;
expect(c3.approved).to.be.false;
expect(c3.approvedMe).to.be.false;
expect(c3.blocked).to.be.false;
expect(c3.profilePicture?.key).to.be.undefined;
expect(c3.profilePicture?.url).to.be.undefined;
contacts2.set(c3);
let push2 = contacts2.push();
accepted = contacts.merge([push2.data]);
expect(accepted).to.be.equal(1);
const allContacts2 = contacts.getAll();
const session_ids2 = allContacts2.map((m: any) => m.id);
const nicknames2 = allContacts2.map((m: any) => m.nickname || '(N/A)');
expect(session_ids2.length).to.be.eq(2);
expect(nicknames2.length).to.be.eq(2);
expect(session_ids2).to.be.deep.eq([realId, another_id]);
expect(nicknames2).to.be.deep.eq(['Joey', '(N/A)']);
// Changing things while iterating:
// no need to support this in JS for now.
const allContacts3 = contacts.getAll();
let deletions = 0;
let non_deletions = 0;
allContacts3.forEach((c: any) => {
if (c.id !== realId) {
contacts.erase(c.id);
deletions++;
} else {
non_deletions++;
}
});
expect(deletions).to.be.eq(1);
expect(non_deletions).to.be.eq(1);
expect(contacts.get(realId)).to.exist;
expect(contacts.get(another_id)).to.be.null;
});
});