chore: added tests for SnodeSignatures calls
parent
820103b340
commit
e8e0e19b40
@ -1,8 +1,9 @@
|
||||
import * as wrappers from 'libsodium-wrappers-sumo';
|
||||
type LibSodiumWrappers = typeof wrappers;
|
||||
|
||||
export async function getSodiumNode() {
|
||||
// don't ask me why, but when called from node we have to do this as the types are incorrect?!
|
||||
const anyWrappers = wrappers as any;
|
||||
await anyWrappers.ready;
|
||||
return anyWrappers.default;
|
||||
return anyWrappers.default as LibSodiumWrappers;
|
||||
}
|
||||
|
@ -0,0 +1,333 @@
|
||||
import { expect, use } from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import Sinon from 'sinon';
|
||||
import { HexString } from '../../../../node/hexStrings';
|
||||
import { getSodiumNode } from '../../../../node/sodiumNode';
|
||||
import { GetNetworkTime } from '../../../../session/apis/snode_api/getNetworkTime';
|
||||
import { SnodeNamespaces } from '../../../../session/apis/snode_api/namespaces';
|
||||
import { SnodeSignature } from '../../../../session/apis/snode_api/snodeSignatures';
|
||||
import { concatUInt8Array } from '../../../../session/crypto';
|
||||
import { UserUtils } from '../../../../session/utils';
|
||||
import { fromBase64ToArray, fromHexToArray } from '../../../../session/utils/String';
|
||||
import { toFixedUint8ArrayOfLength } from '../../../../types/sqlSharedTypes';
|
||||
|
||||
use(chaiAsPromised);
|
||||
|
||||
const validGroupPk = '03eef710fcaaa73fd50c4311333f5c496e0fdbbe9e8a70fdfa95e7ec62d5032f5c';
|
||||
const privKeyUint = toFixedUint8ArrayOfLength(
|
||||
concatUInt8Array(
|
||||
fromHexToArray('cd8488c39bf9972739046d627e7796b2bc0e38e2fa99fc4edd59205c28f2cdb1'),
|
||||
fromHexToArray(validGroupPk.slice(2))
|
||||
),
|
||||
64
|
||||
);
|
||||
|
||||
const userEd25519Keypair = {
|
||||
pubKey: '37e1631b002de498caf7c5c1712718bde7f257c6dadeed0c21abf5e939e6c309',
|
||||
privKey:
|
||||
'be1d11154ff9b6de77873f0b6b0bcc460000000000000000000000000000000037e1631b002de498caf7c5c1712718bde7f257c6dadeed0c21abf5e939e6c309',
|
||||
};
|
||||
|
||||
const hardcodedTimestamp = 1234;
|
||||
|
||||
async function verifySig(ret: { pubkey: string; signature: string }, verificationData: string) {
|
||||
const without03 = ret.pubkey.startsWith('03') ? ret.pubkey.slice(2) : ret.pubkey; //
|
||||
const pk = HexString.fromHexString(without03);
|
||||
const sodium = await getSodiumNode();
|
||||
const verified = sodium.crypto_sign_verify_detached(
|
||||
fromBase64ToArray(ret.signature),
|
||||
verificationData,
|
||||
pk
|
||||
);
|
||||
|
||||
if (!verified) {
|
||||
throw new Error('sig failed to be verified');
|
||||
}
|
||||
}
|
||||
|
||||
describe('SnodeSignature', () => {
|
||||
afterEach(() => {
|
||||
Sinon.restore();
|
||||
});
|
||||
|
||||
describe('getSnodeGroupSignatureParams', () => {
|
||||
beforeEach(() => {
|
||||
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(hardcodedTimestamp);
|
||||
});
|
||||
|
||||
describe('retrieve', () => {
|
||||
it('retrieve namespace ClosedGroupInfo', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'retrieve',
|
||||
namespace: SnodeNamespaces.ClosedGroupInfo,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
const verificationData = `retrieve${SnodeNamespaces.ClosedGroupInfo}${hardcodedTimestamp}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
|
||||
it('retrieve namespace ClosedGroupKeys', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'retrieve',
|
||||
namespace: SnodeNamespaces.ClosedGroupKeys,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
const verificationData = `retrieve${SnodeNamespaces.ClosedGroupKeys}${hardcodedTimestamp}`;
|
||||
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
|
||||
it('retrieve namespace ClosedGroupMessages', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'retrieve',
|
||||
namespace: SnodeNamespaces.ClosedGroupMessages,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
const verificationData = `retrieve${SnodeNamespaces.ClosedGroupMessages}${hardcodedTimestamp}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('store', () => {
|
||||
it('store namespace ClosedGroupInfo', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'store',
|
||||
namespace: SnodeNamespaces.ClosedGroupInfo,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
|
||||
const verificationData = `store${SnodeNamespaces.ClosedGroupInfo}${hardcodedTimestamp}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
|
||||
it('store namespace ClosedGroupKeys', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'store',
|
||||
namespace: SnodeNamespaces.ClosedGroupKeys,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
const verificationData = `store${SnodeNamespaces.ClosedGroupKeys}${hardcodedTimestamp}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
|
||||
it('store namespace ClosedGroupMessages', async () => {
|
||||
const ret = await SnodeSignature.getSnodeGroupSignatureParams({
|
||||
method: 'store',
|
||||
namespace: SnodeNamespaces.ClosedGroupMessages,
|
||||
groupIdentityPrivKey: privKeyUint,
|
||||
groupPk: validGroupPk,
|
||||
});
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
expect(ret.timestamp).to.be.eq(hardcodedTimestamp);
|
||||
const verificationData = `store${SnodeNamespaces.ClosedGroupMessages}${hardcodedTimestamp}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateUpdateExpiryGroupSignature', () => {
|
||||
it('throws if groupPk not given', async () => {
|
||||
const func = async () => {
|
||||
return SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: null as any,
|
||||
groupPrivKey: privKeyUint,
|
||||
messagesHashes: ['[;p['],
|
||||
shortenOrExtend: '',
|
||||
timestamp: hardcodedTimestamp,
|
||||
});
|
||||
};
|
||||
await expect(func()).to.be.rejectedWith(
|
||||
'generateUpdateExpiryGroupSignature groupPrivKey or groupPk is empty'
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if groupPrivKey is empty', async () => {
|
||||
const func = async () => {
|
||||
return SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: validGroupPk,
|
||||
groupPrivKey: new Uint8Array() as any,
|
||||
messagesHashes: ['[;p['],
|
||||
shortenOrExtend: '',
|
||||
timestamp: hardcodedTimestamp,
|
||||
});
|
||||
};
|
||||
await expect(func()).to.be.rejectedWith(
|
||||
'generateUpdateExpiryGroupSignature groupPrivKey or groupPk is empty'
|
||||
);
|
||||
});
|
||||
|
||||
it('works with valid pubkey and privkey', async () => {
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const timestamp = hardcodedTimestamp;
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: validGroupPk,
|
||||
groupPrivKey: privKeyUint,
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend: '',
|
||||
timestamp,
|
||||
});
|
||||
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
const verificationData = `expire${shortenOrExtend}${timestamp}${hashes.join('')}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
|
||||
it('fails with invalid timestamp', async () => {
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const timestamp = hardcodedTimestamp;
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: validGroupPk,
|
||||
groupPrivKey: privKeyUint,
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend: '',
|
||||
timestamp,
|
||||
});
|
||||
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
const verificationData = `expire${shortenOrExtend}${timestamp}1${hashes.join('')}`;
|
||||
const func = async () => verifySig(ret, verificationData);
|
||||
await expect(func()).rejectedWith('sig failed to be verified');
|
||||
});
|
||||
|
||||
it('fails with invalid hashes', async () => {
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const timestamp = hardcodedTimestamp;
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: validGroupPk,
|
||||
groupPrivKey: privKeyUint,
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend: '',
|
||||
timestamp,
|
||||
});
|
||||
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
const overridenHash = hashes.slice();
|
||||
overridenHash[0] = '1111';
|
||||
const verificationData = `expire${shortenOrExtend}${timestamp}${overridenHash.join('')}`;
|
||||
const func = async () => verifySig(ret, verificationData);
|
||||
await expect(func()).rejectedWith('sig failed to be verified');
|
||||
});
|
||||
|
||||
it('fails with invalid number of hashes', async () => {
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const timestamp = hardcodedTimestamp;
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryGroupSignature({
|
||||
groupPk: validGroupPk,
|
||||
groupPrivKey: privKeyUint,
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend: '',
|
||||
timestamp,
|
||||
});
|
||||
|
||||
expect(ret.pubkey).to.be.eq(validGroupPk);
|
||||
|
||||
const overridenHash = [hashes[0]];
|
||||
const verificationData = `expire${shortenOrExtend}${timestamp}${overridenHash.join('')}`;
|
||||
const func = async () => verifySig(ret, verificationData);
|
||||
await expect(func()).rejectedWith('sig failed to be verified');
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateUpdateExpiryOurSignature', () => {
|
||||
it('throws if our ed keypair is not set', async () => {
|
||||
Sinon.stub(UserUtils, 'getUserED25519KeyPair').resolves(null as any);
|
||||
|
||||
const func = async () => {
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const shortenOrExtend = '';
|
||||
return SnodeSignature.generateUpdateExpiryOurSignature({
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend,
|
||||
timestamp: hardcodedTimestamp,
|
||||
});
|
||||
};
|
||||
|
||||
await expect(func()).to.be.rejectedWith(
|
||||
'getSnodeSignatureParams "expiry": User has no getUserED25519KeyPair()'
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if invalid hashes', async () => {
|
||||
Sinon.stub(UserUtils, 'getUserED25519KeyPair').resolves(userEd25519Keypair);
|
||||
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryOurSignature({
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend,
|
||||
timestamp: hardcodedTimestamp,
|
||||
});
|
||||
const overridenHash = [hashes[0]];
|
||||
const verificationData = `expire${shortenOrExtend}${hardcodedTimestamp}${overridenHash.join(
|
||||
''
|
||||
)}`;
|
||||
|
||||
const func = async () => {
|
||||
return verifySig(ret, verificationData);
|
||||
};
|
||||
await expect(func()).to.be.rejectedWith('sig failed to be verified');
|
||||
});
|
||||
|
||||
it('throws if invalid timestamp', async () => {
|
||||
Sinon.stub(UserUtils, 'getUserED25519KeyPair').resolves(userEd25519Keypair);
|
||||
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryOurSignature({
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend,
|
||||
timestamp: hardcodedTimestamp,
|
||||
});
|
||||
const verificationData = `expire${shortenOrExtend}${hardcodedTimestamp}123${hashes.join('')}`;
|
||||
|
||||
const func = async () => {
|
||||
return verifySig(ret, verificationData);
|
||||
};
|
||||
await expect(func()).to.be.rejectedWith('sig failed to be verified');
|
||||
});
|
||||
|
||||
it('works with valid pubkey and privkey', async () => {
|
||||
Sinon.stub(UserUtils, 'getUserED25519KeyPair').resolves(userEd25519Keypair);
|
||||
|
||||
const hashes = ['hash4321', 'hash4221'];
|
||||
const timestamp = hardcodedTimestamp;
|
||||
const shortenOrExtend = '';
|
||||
const ret = await SnodeSignature.generateUpdateExpiryOurSignature({
|
||||
messagesHashes: hashes,
|
||||
shortenOrExtend: '',
|
||||
timestamp,
|
||||
});
|
||||
|
||||
expect(ret.pubkey).to.be.eq(userEd25519Keypair.pubKey);
|
||||
|
||||
const verificationData = `expire${shortenOrExtend}${timestamp}${hashes.join('')}`;
|
||||
await verifySig(ret, verificationData);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue