mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
Filter invalid authorisations from the file server
This commit is contained in:
parent
2e82bf98c1
commit
d4ea483aa0
5 changed files with 167 additions and 35 deletions
38
libloki/crypto.d.ts
vendored
38
libloki/crypto.d.ts
vendored
|
@ -1,27 +1,27 @@
|
|||
import { PairingAuthorisation } from "../js/modules/data";
|
||||
import { PairingAuthorisation } from '../js/modules/data';
|
||||
|
||||
declare enum PairingTypeEnum {
|
||||
REQUEST = 1,
|
||||
GRANT
|
||||
GRANT,
|
||||
}
|
||||
|
||||
export interface CryptoInterface {
|
||||
DHDecrypt: any,
|
||||
DHEncrypt: any,
|
||||
DecryptGCM: any, // AES-GCM
|
||||
EncryptGCM: any, // AES-GCM
|
||||
FallBackDecryptionError: any,
|
||||
FallBackSessionCipher: any,
|
||||
LokiSessionCipher: any,
|
||||
PairingType: PairingTypeEnum,
|
||||
_decodeSnodeAddressToPubKey: any,
|
||||
decryptForPubkey: any,
|
||||
decryptToken: any,
|
||||
encryptForPubkey: any,
|
||||
generateEphemeralKeyPair: any,
|
||||
generateSignatureForPairing: any,
|
||||
sha512: any,
|
||||
validateAuthorisation: any,
|
||||
DHDecrypt: any;
|
||||
DHEncrypt: any;
|
||||
DecryptGCM: any; // AES-GCM
|
||||
EncryptGCM: any; // AES-GCM
|
||||
FallBackDecryptionError: any;
|
||||
FallBackSessionCipher: any;
|
||||
LokiSessionCipher: any;
|
||||
PairingType: PairingTypeEnum;
|
||||
_decodeSnodeAddressToPubKey: any;
|
||||
decryptForPubkey: any;
|
||||
decryptToken: any;
|
||||
encryptForPubkey: any;
|
||||
generateEphemeralKeyPair: any;
|
||||
generateSignatureForPairing: any;
|
||||
sha512: any;
|
||||
validateAuthorisation: any;
|
||||
verifyAuthorisation(authorisation: PairingAuthorisation): Promise<boolean>;
|
||||
verifyPairingSignature: any,
|
||||
verifyPairingSignature: any;
|
||||
}
|
||||
|
|
2
libloki/index.d.ts
vendored
2
libloki/index.d.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import { CryptoInterface } from "./crypto";
|
||||
import { CryptoInterface } from './crypto';
|
||||
|
||||
export interface Libloki {
|
||||
api: any;
|
||||
|
|
|
@ -82,25 +82,45 @@ export class MultiDeviceProtocol {
|
|||
const mapping = await window.lokiFileServerAPI.getUserDeviceMapping(
|
||||
device.key
|
||||
);
|
||||
// TODO: Filter out invalid authorisations
|
||||
|
||||
if (!mapping || !mapping.authorisations) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return mapping.authorisations.map(
|
||||
({
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
requestSignature,
|
||||
grantSignature,
|
||||
}) => ({
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
requestSignature: StringUtils.encode(requestSignature, 'base64'),
|
||||
grantSignature: StringUtils.encode(grantSignature, 'base64'),
|
||||
})
|
||||
);
|
||||
try {
|
||||
const authorisations = mapping.authorisations.map(
|
||||
({
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
requestSignature,
|
||||
grantSignature,
|
||||
}) => ({
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
requestSignature: StringUtils.encode(requestSignature, 'base64'),
|
||||
grantSignature: StringUtils.encode(grantSignature, 'base64'),
|
||||
})
|
||||
);
|
||||
|
||||
const validAuthorisations = await Promise.all(
|
||||
authorisations.map(async authoritsation => {
|
||||
const valid = await window.libloki.crypto.verifyAuthorisation(
|
||||
authoritsation
|
||||
);
|
||||
return valid ? authoritsation : undefined;
|
||||
})
|
||||
);
|
||||
|
||||
return validAuthorisations.filter(a => !!a) as Array<
|
||||
PairingAuthorisation
|
||||
>;
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`MultiDeviceProtocol::fetchPairingAuthorisation: Failed to map authorisations for ${device.key}.`,
|
||||
e
|
||||
);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ describe('MessageEncrypter', () => {
|
|||
TestUtils.stubWindow('libloki', {
|
||||
crypto: {
|
||||
FallBackSessionCipher: Stubs.FallBackSessionCipherStub,
|
||||
},
|
||||
} as any,
|
||||
});
|
||||
|
||||
sandbox.stub(UserUtil, 'getCurrentDevicePubKey').resolves(ourNumber);
|
||||
|
|
|
@ -71,6 +71,21 @@ describe('MultiDeviceProtocol', () => {
|
|||
});
|
||||
|
||||
describe('fetchPairingAuthorisations', () => {
|
||||
let verifyAuthorisationStub: sinon.SinonStub<
|
||||
[PairingAuthorisation],
|
||||
Promise<boolean>
|
||||
>;
|
||||
beforeEach(() => {
|
||||
verifyAuthorisationStub = sandbox
|
||||
.stub<[PairingAuthorisation], Promise<boolean>>()
|
||||
.resolves(true);
|
||||
TestUtils.stubWindow('libloki', {
|
||||
crypto: {
|
||||
verifyAuthorisation: verifyAuthorisationStub,
|
||||
} as any,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw if lokiFileServerAPI does not exist', async () => {
|
||||
TestUtils.stubWindow('lokiFileServerAPI', undefined);
|
||||
expect(
|
||||
|
@ -125,9 +140,96 @@ describe('MultiDeviceProtocol', () => {
|
|||
networkAuth.grantSignature
|
||||
);
|
||||
});
|
||||
|
||||
it('should not return invalid authorisations', async () => {
|
||||
const networkAuth = {
|
||||
primaryDevicePubKey:
|
||||
'05caa6310a490415df45f8f4ad1b3655ad7a11e722257887a30cf71601d679720b',
|
||||
secondaryDevicePubKey:
|
||||
'051296b9588641eea268d60ad6636eecb53a95150e91c0531a00203e01a2c16a39',
|
||||
requestSignature:
|
||||
'+knEdlenTV+MooRqlFsZRPWW8s9pcjKwB40fY5o0GJmAi2RPZtaVGRTqgApTIn2zPBTE4GQlmPD7uxcczHDjAg==',
|
||||
grantSignature:
|
||||
'eKzcOWMEVetybkuiVK2u18B9en5pywohn2Hn25/VOVTMrIsKSCW4xXpqwipfqvgvi62WtUt6SA9bCEB5Ngcyiw==',
|
||||
};
|
||||
|
||||
const stub = sinon.stub().resolves({
|
||||
isPrimary: false,
|
||||
authorisations: [networkAuth],
|
||||
});
|
||||
TestUtils.stubWindow('lokiFileServerAPI', {
|
||||
getUserDeviceMapping: stub,
|
||||
});
|
||||
|
||||
verifyAuthorisationStub.resolves(false);
|
||||
|
||||
const authorisations = await MultiDeviceProtocol.fetchPairingAuthorisations(
|
||||
TestUtils.generateFakePubKey()
|
||||
);
|
||||
expect(verifyAuthorisationStub.callCount).to.equal(1);
|
||||
expect(authorisations.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should handle incorrect pairing authorisations from the file server', async () => {
|
||||
const invalidAuth = {
|
||||
primaryDevicePubKey:
|
||||
'05caa6310a490415df45f8f4ad1b3655ad7a11e722257887a30cf71601d679720b',
|
||||
secondaryDevicePubKey:
|
||||
'051296b9588641eea268d60ad6636eecb53a95150e91c0531a00203e01a2c16a39',
|
||||
requestSignatures:
|
||||
'+knEdlenTV+MooRqlFsZRPWW8s9pcjKwB40fY5o0GJmAi2RPZtaVGRTqgApTIn2zPBTE4GQlmPD7uxcczHDjAg==',
|
||||
};
|
||||
|
||||
const stub = sinon.stub().resolves({
|
||||
isPrimary: false,
|
||||
authorisations: [invalidAuth],
|
||||
});
|
||||
TestUtils.stubWindow('lokiFileServerAPI', {
|
||||
getUserDeviceMapping: stub,
|
||||
});
|
||||
const authorisations = await MultiDeviceProtocol.fetchPairingAuthorisations(
|
||||
TestUtils.generateFakePubKey()
|
||||
);
|
||||
expect(authorisations.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should return empty array if mapping is null', async () => {
|
||||
const stub = sinon.stub().resolves(null);
|
||||
TestUtils.stubWindow('lokiFileServerAPI', {
|
||||
getUserDeviceMapping: stub,
|
||||
});
|
||||
|
||||
const authorisations = await MultiDeviceProtocol.fetchPairingAuthorisations(
|
||||
TestUtils.generateFakePubKey()
|
||||
);
|
||||
expect(authorisations.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should return empty array if authorisations in mapping are null', async () => {
|
||||
const stub = sinon.stub().resolves({
|
||||
isPrimary: false,
|
||||
authorisations: null,
|
||||
});
|
||||
TestUtils.stubWindow('lokiFileServerAPI', {
|
||||
getUserDeviceMapping: stub,
|
||||
});
|
||||
|
||||
const authorisations = await MultiDeviceProtocol.fetchPairingAuthorisations(
|
||||
TestUtils.generateFakePubKey()
|
||||
);
|
||||
expect(authorisations.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchPairingAuthorisationIfNeeded', () => {
|
||||
beforeEach(() => {
|
||||
TestUtils.stubWindow('libloki', {
|
||||
crypto: {
|
||||
verifyAuthorisation: async () => true,
|
||||
} as any,
|
||||
});
|
||||
});
|
||||
|
||||
let fetchPairingAuthorisationStub: sinon.SinonStub<
|
||||
[PubKey],
|
||||
Promise<Array<PairingAuthorisation>>
|
||||
|
@ -250,6 +352,16 @@ describe('MultiDeviceProtocol', () => {
|
|||
expect(allDevicePubKeys).to.have.same.members(devices.map(d => d.key));
|
||||
}
|
||||
});
|
||||
|
||||
it('should return the passed in user device if no pairing authorisations are found', async () => {
|
||||
const pubKey = TestUtils.generateFakePubKey();
|
||||
sandbox
|
||||
.stub(MultiDeviceProtocol, 'getPairingAuthorisations')
|
||||
.resolves([]);
|
||||
const allDevices = await MultiDeviceProtocol.getAllDevices(pubKey);
|
||||
expect(allDevices).to.have.length(1);
|
||||
expect(allDevices[0].key).to.equal(pubKey.key);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPrimaryDevice', () => {
|
||||
|
|
Loading…
Reference in a new issue