signature checking, hide your own message, addres potential race issues

pull/539/head
Ryan Tharp 6 years ago
parent 87474d48b5
commit 9ba641c8c1

@ -1,5 +1,6 @@
/* global log, textsecure, libloki, Signal, Whisper, Headers, ConversationController, /* global log, textsecure, libloki, Signal, Whisper, Headers, ConversationController,
clearTimeout, MessageController, libsignal, StringView, window, _, lokiFileServerAPI */ clearTimeout, MessageController, libsignal, StringView, window, _, lokiFileServerAPI,
dcodeIO */
const EventEmitter = require('events'); const EventEmitter = require('events');
const nodeFetch = require('node-fetch'); const nodeFetch = require('node-fetch');
const { URL, URLSearchParams } = require('url'); const { URL, URLSearchParams } = require('url');
@ -770,17 +771,17 @@ class LokiPublicChannelAPI {
!adnMessage.text || !adnMessage.text ||
adnMessage.is_deleted adnMessage.is_deleted
) { ) {
return; // Invalid or delete message return false; // Invalid or delete message
} }
const messengerData = await this.getMessengerData(adnMessage); const messengerData = await this.getMessengerData(adnMessage);
if (messengerData === false) { if (messengerData === false) {
return; return false;
} }
const { timestamp, quote } = messengerData; const { timestamp, quote } = messengerData;
if (!timestamp) { if (!timestamp) {
return; // Invalid message return false; // Invalid message
} }
// Duplicate check // Duplicate check
@ -798,7 +799,7 @@ class LokiPublicChannelAPI {
// Filter out any messages that we got previously // Filter out any messages that we got previously
if (this.lastMessagesCache.some(isDuplicate)) { if (this.lastMessagesCache.some(isDuplicate)) {
return; // Duplicate message return false; // Duplicate message
} }
// FIXME: maybe move after the de-multidev-decode // FIXME: maybe move after the de-multidev-decode
@ -858,7 +859,7 @@ class LokiPublicChannelAPI {
this.conversation.setLastRetrievedMessage(this.lastGot); this.conversation.setLastRetrievedMessage(this.lastGot);
if (pendingMessages.length) { if (pendingMessages.length) {
this.slavePrimaryMap = {}; const newSlavePrimaryMap = {};
// console.log('premultiDeviceResults', pubKeys) // console.log('premultiDeviceResults', pubKeys)
if (pubKeys.length) { if (pubKeys.length) {
@ -878,25 +879,42 @@ class LokiPublicChannelAPI {
if (Array.isArray(authorisations)) { if (Array.isArray(authorisations)) {
authorisations.forEach(auth => { authorisations.forEach(auth => {
// console.log('auth', auth); // console.log('auth', auth);
// FIXME: verify secondary sig try {
if (1) { // request (secondary wants to be paired with this primary)
// add map to slavePrimaryMap window.libloki.crypto.verifyPairingSignature(
auth.primaryDevicePubKey,
auth.secondaryDevicePubKey,
dcodeIO.ByteBuffer.wrap(
auth.requestSignature,
'base64'
).toArrayBuffer(),
textsecure.protobuf.PairingAuthorisationMessage.Type
.REQUEST
);
// if it doesn't throw, that means it's valid
// add map to newSlavePrimaryMap
if ( if (
this.slavePrimaryMap[user.username] && newSlavePrimaryMap[user.username] &&
this.slavePrimaryMap[user.username] !== newSlavePrimaryMap[user.username] !==
auth.primaryDevicePubKey auth.primaryDevicePubKey
) { ) {
log.warn( log.warn(
`file server user annotation primaryKey mismatch, had ${ `file server user annotation primaryKey mismatch, had ${
this.slavePrimaryMap[user.username] newSlavePrimaryMap[user.username]
} now ${auth.primaryDevicePubKey} for ${ } now ${auth.primaryDevicePubKey} for ${
user.username user.username
}` }`
); );
return; return;
} }
this.slavePrimaryMap[user.username] = newSlavePrimaryMap[user.username] =
auth.primaryDevicePubKey; auth.primaryDevicePubKey;
} catch (e) {
log.warn(
`Invalid grant signature on SecondaryPubKey ${
auth.secondaryDevicePubKey
}`
);
} }
}); });
} }
@ -905,7 +923,7 @@ class LokiPublicChannelAPI {
}); });
} }
}); });
log.info('updated slavePrimaryMap', this.slavePrimaryMap); // log.info('tenative slavePrimaryMap', newSlavePrimaryMap);
const primaryPubKeys = []; const primaryPubKeys = [];
const slaveMessages = {}; const slaveMessages = {};
@ -916,8 +934,8 @@ class LokiPublicChannelAPI {
log.warn('invalid pendingMessages'); log.warn('invalid pendingMessages');
return; return;
} }
if (this.slavePrimaryMap[messageData.source]) { if (newSlavePrimaryMap[messageData.source]) {
const primaryPubKey = this.slavePrimaryMap[messageData.source]; const primaryPubKey = newSlavePrimaryMap[messageData.source];
// add to lookup (if we don't already have it) // add to lookup (if we don't already have it)
if (primaryPubKeys.indexOf(`@${primaryPubKey}`) === -1) { if (primaryPubKeys.indexOf(`@${primaryPubKey}`) === -1) {
primaryPubKeys.push(`@${primaryPubKey}`); primaryPubKeys.push(`@${primaryPubKey}`);
@ -944,43 +962,69 @@ class LokiPublicChannelAPI {
); );
// go through primaryDeviceResults // go through primaryDeviceResults
primaryDeviceResults.forEach(user => { primaryDeviceResults.forEach(user => {
let found = false;
if (user.annotations) { if (user.annotations) {
user.annotations.forEach(note => { user.annotations.forEach(note => {
if (note.type === 'network.loki.messenger.devicemapping') { if (note.type === 'network.loki.messenger.devicemapping') {
if (note.value.isPrimary) { if (note.value.isPrimary) {
const { authorisations } = note.value; const { authorisations } = note.value;
let found = false;
if (Array.isArray(authorisations)) { if (Array.isArray(authorisations)) {
authorisations.forEach(auth => { authorisations.forEach(auth => {
// FIXME: verify primary sig try {
if ( // grant (primary approves this secondary)
verifiedPrimaryPKs.indexOf( window.libloki.crypto.verifyPairingSignature(
`@${auth.primaryDevicePubKey}` auth.primaryDevicePubKey,
) === -1 auth.secondaryDevicePubKey,
) { dcodeIO.ByteBuffer.wrap(
verifiedPrimaryPKs.push( auth.grantSignature,
`@${auth.primaryDevicePubKey}` 'base64'
).toArrayBuffer(),
textsecure.protobuf.PairingAuthorisationMessage.Type
.GRANT
);
if (
verifiedPrimaryPKs.indexOf(
`@${auth.primaryDevicePubKey}`
) === -1
) {
verifiedPrimaryPKs.push(
`@${auth.primaryDevicePubKey}`
);
}
found = true;
} catch (e) {
log.warn(
`Invalid grant signature on PrimaryPubKey ${
auth.primaryDevicePubKey
}`
); );
} }
found = true;
}); });
} }
if (found) {
return;
}
// if not verified remove from slavePrimaryMap
} }
// not primary or verified
/*
Object.keys(slavePrimaryMap).forEach(slaveKey => {
if (slavePrimaryMap[slaveKey] ==
})
*/
} }
}); });
} }
if (found) {
return;
}
// if not verified remove this user pubkey from newSlavePrimaryMap
Object.keys(newSlavePrimaryMap).forEach(slaveKey => {
if (newSlavePrimaryMap[slaveKey] === user.username) {
log.warn(
`removing unverifible ${slaveKey} to ${user.username} mapping`
);
delete newSlavePrimaryMap[slaveKey];
}
});
}); });
// update this.slavePrimaryMap live with updated map
this.slavePrimaryMap = newSlavePrimaryMap;
log.info(
`Updated device mappings ${JSON.stringify(this.slavePrimaryMap)}`
);
// get final list of verified chat server profile names // get final list of verified chat server profile names
const verifiedDeviceResults = await this.serverAPI.getUsersAnnotations( const verifiedDeviceResults = await this.serverAPI.getUsersAnnotations(
pubKeys pubKeys
@ -988,11 +1032,21 @@ class LokiPublicChannelAPI {
// console.log('verifiedDeviceResults', verifiedDeviceResults) // console.log('verifiedDeviceResults', verifiedDeviceResults)
// go through verifiedDeviceResults // go through verifiedDeviceResults
this.primaryUserProfileName = {}; const newPrimaryUserProfileName = {};
verifiedDeviceResults.forEach(user => { verifiedDeviceResults.forEach(user => {
this.primaryUserProfileName[user.username] = user.name; newPrimaryUserProfileName[user.username] = user.name;
}); });
// replace whole
this.primaryUserProfileName = newPrimaryUserProfileName;
// process remaining messages
const ourNumber = textsecure.storage.user.getNumber();
Object.keys(slaveMessages).forEach(slaveKey => { Object.keys(slaveMessages).forEach(slaveKey => {
// prevent our own sent messages from coming back in
if (slaveKey === ourNumber) {
// we originally sent these
return;
}
const primaryPubKey = this.slavePrimaryMap[slaveKey]; const primaryPubKey = this.slavePrimaryMap[slaveKey];
slaveMessages[slaveKey].forEach(messageDataP => { slaveMessages[slaveKey].forEach(messageDataP => {
const messageData = messageDataP; // for linter const messageData = messageDataP; // for linter
@ -1009,12 +1063,13 @@ class LokiPublicChannelAPI {
}); });
}); });
}); });
} } // end if there are pending pubkeys to look up
// console.log('pendingMessages len', pendingMessages.length); // console.log('pendingMessages len', pendingMessages.length);
// console.log('pendingMessages', pendingMessages); // console.log('pendingMessages', pendingMessages);
// find messages for original slave key using slavePrimaryMap // find messages for original slave key using slavePrimaryMap
if (pendingMessages.length) { if (pendingMessages.length) {
const ourNumber = textsecure.storage.user.getNumber();
pendingMessages.forEach(messageDataP => { pendingMessages.forEach(messageDataP => {
const messageData = messageDataP; // for linter const messageData = messageDataP; // for linter
// why am I getting these? // why am I getting these?
@ -1022,10 +1077,15 @@ class LokiPublicChannelAPI {
log.warn(`invalid pendingMessages ${pendingMessages}`); log.warn(`invalid pendingMessages ${pendingMessages}`);
return; return;
} }
// prevent our own sent messages from coming back in
if (messageData.source === ourNumber) {
// we originally sent this
return;
}
if (this.slavePrimaryMap[messageData.source]) { if (this.slavePrimaryMap[messageData.source]) {
// rewrite source, profile // rewrite source, profile
const primaryPubKey = this.slavePrimaryMap[messageData.source]; const primaryPubKey = this.slavePrimaryMap[messageData.source];
log.info('Rewriting', messageData.source, 'to', primaryPubKey); log.info(`Rewriting ${messageData.source} to ${primaryPubKey}`);
messageData.source = primaryPubKey; messageData.source = primaryPubKey;
messageData.message.profile.displayName = this.primaryUserProfileName[ messageData.message.profile.displayName = this.primaryUserProfileName[
primaryPubKey primaryPubKey

Loading…
Cancel
Save