|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
/* 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 nodeFetch = require('node-fetch');
|
|
|
|
|
const { URL, URLSearchParams } = require('url');
|
|
|
|
@ -770,17 +771,17 @@ class LokiPublicChannelAPI {
|
|
|
|
|
!adnMessage.text ||
|
|
|
|
|
adnMessage.is_deleted
|
|
|
|
|
) {
|
|
|
|
|
return; // Invalid or delete message
|
|
|
|
|
return false; // Invalid or delete message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const messengerData = await this.getMessengerData(adnMessage);
|
|
|
|
|
if (messengerData === false) {
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { timestamp, quote } = messengerData;
|
|
|
|
|
if (!timestamp) {
|
|
|
|
|
return; // Invalid message
|
|
|
|
|
return false; // Invalid message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Duplicate check
|
|
|
|
@ -798,7 +799,7 @@ class LokiPublicChannelAPI {
|
|
|
|
|
|
|
|
|
|
// Filter out any messages that we got previously
|
|
|
|
|
if (this.lastMessagesCache.some(isDuplicate)) {
|
|
|
|
|
return; // Duplicate message
|
|
|
|
|
return false; // Duplicate message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: maybe move after the de-multidev-decode
|
|
|
|
@ -858,7 +859,7 @@ class LokiPublicChannelAPI {
|
|
|
|
|
this.conversation.setLastRetrievedMessage(this.lastGot);
|
|
|
|
|
|
|
|
|
|
if (pendingMessages.length) {
|
|
|
|
|
this.slavePrimaryMap = {};
|
|
|
|
|
const newSlavePrimaryMap = {};
|
|
|
|
|
|
|
|
|
|
// console.log('premultiDeviceResults', pubKeys)
|
|
|
|
|
if (pubKeys.length) {
|
|
|
|
@ -878,25 +879,42 @@ class LokiPublicChannelAPI {
|
|
|
|
|
if (Array.isArray(authorisations)) {
|
|
|
|
|
authorisations.forEach(auth => {
|
|
|
|
|
// console.log('auth', auth);
|
|
|
|
|
// FIXME: verify secondary sig
|
|
|
|
|
if (1) {
|
|
|
|
|
// add map to slavePrimaryMap
|
|
|
|
|
try {
|
|
|
|
|
// request (secondary wants to be paired with this primary)
|
|
|
|
|
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 (
|
|
|
|
|
this.slavePrimaryMap[user.username] &&
|
|
|
|
|
this.slavePrimaryMap[user.username] !==
|
|
|
|
|
newSlavePrimaryMap[user.username] &&
|
|
|
|
|
newSlavePrimaryMap[user.username] !==
|
|
|
|
|
auth.primaryDevicePubKey
|
|
|
|
|
) {
|
|
|
|
|
log.warn(
|
|
|
|
|
`file server user annotation primaryKey mismatch, had ${
|
|
|
|
|
this.slavePrimaryMap[user.username]
|
|
|
|
|
newSlavePrimaryMap[user.username]
|
|
|
|
|
} now ${auth.primaryDevicePubKey} for ${
|
|
|
|
|
user.username
|
|
|
|
|
}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.slavePrimaryMap[user.username] =
|
|
|
|
|
newSlavePrimaryMap[user.username] =
|
|
|
|
|
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 slaveMessages = {};
|
|
|
|
@ -916,8 +934,8 @@ class LokiPublicChannelAPI {
|
|
|
|
|
log.warn('invalid pendingMessages');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (this.slavePrimaryMap[messageData.source]) {
|
|
|
|
|
const primaryPubKey = this.slavePrimaryMap[messageData.source];
|
|
|
|
|
if (newSlavePrimaryMap[messageData.source]) {
|
|
|
|
|
const primaryPubKey = newSlavePrimaryMap[messageData.source];
|
|
|
|
|
// add to lookup (if we don't already have it)
|
|
|
|
|
if (primaryPubKeys.indexOf(`@${primaryPubKey}`) === -1) {
|
|
|
|
|
primaryPubKeys.push(`@${primaryPubKey}`);
|
|
|
|
@ -944,43 +962,69 @@ class LokiPublicChannelAPI {
|
|
|
|
|
);
|
|
|
|
|
// go through primaryDeviceResults
|
|
|
|
|
primaryDeviceResults.forEach(user => {
|
|
|
|
|
let found = false;
|
|
|
|
|
if (user.annotations) {
|
|
|
|
|
user.annotations.forEach(note => {
|
|
|
|
|
if (note.type === 'network.loki.messenger.devicemapping') {
|
|
|
|
|
if (note.value.isPrimary) {
|
|
|
|
|
const { authorisations } = note.value;
|
|
|
|
|
let found = false;
|
|
|
|
|
if (Array.isArray(authorisations)) {
|
|
|
|
|
authorisations.forEach(auth => {
|
|
|
|
|
// FIXME: verify primary sig
|
|
|
|
|
if (
|
|
|
|
|
verifiedPrimaryPKs.indexOf(
|
|
|
|
|
`@${auth.primaryDevicePubKey}`
|
|
|
|
|
) === -1
|
|
|
|
|
) {
|
|
|
|
|
verifiedPrimaryPKs.push(
|
|
|
|
|
`@${auth.primaryDevicePubKey}`
|
|
|
|
|
try {
|
|
|
|
|
// grant (primary approves this secondary)
|
|
|
|
|
window.libloki.crypto.verifyPairingSignature(
|
|
|
|
|
auth.primaryDevicePubKey,
|
|
|
|
|
auth.secondaryDevicePubKey,
|
|
|
|
|
dcodeIO.ByteBuffer.wrap(
|
|
|
|
|
auth.grantSignature,
|
|
|
|
|
'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
|
|
|
|
|
const verifiedDeviceResults = await this.serverAPI.getUsersAnnotations(
|
|
|
|
|
pubKeys
|
|
|
|
@ -988,11 +1032,21 @@ class LokiPublicChannelAPI {
|
|
|
|
|
// console.log('verifiedDeviceResults', verifiedDeviceResults)
|
|
|
|
|
|
|
|
|
|
// go through verifiedDeviceResults
|
|
|
|
|
this.primaryUserProfileName = {};
|
|
|
|
|
const newPrimaryUserProfileName = {};
|
|
|
|
|
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 => {
|
|
|
|
|
// prevent our own sent messages from coming back in
|
|
|
|
|
if (slaveKey === ourNumber) {
|
|
|
|
|
// we originally sent these
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const primaryPubKey = this.slavePrimaryMap[slaveKey];
|
|
|
|
|
slaveMessages[slaveKey].forEach(messageDataP => {
|
|
|
|
|
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', pendingMessages);
|
|
|
|
|
// find messages for original slave key using slavePrimaryMap
|
|
|
|
|
if (pendingMessages.length) {
|
|
|
|
|
const ourNumber = textsecure.storage.user.getNumber();
|
|
|
|
|
pendingMessages.forEach(messageDataP => {
|
|
|
|
|
const messageData = messageDataP; // for linter
|
|
|
|
|
// why am I getting these?
|
|
|
|
@ -1022,10 +1077,15 @@ class LokiPublicChannelAPI {
|
|
|
|
|
log.warn(`invalid pendingMessages ${pendingMessages}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// prevent our own sent messages from coming back in
|
|
|
|
|
if (messageData.source === ourNumber) {
|
|
|
|
|
// we originally sent this
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (this.slavePrimaryMap[messageData.source]) {
|
|
|
|
|
// rewrite source, profile
|
|
|
|
|
const primaryPubKey = this.slavePrimaryMap[messageData.source];
|
|
|
|
|
log.info('Rewriting', messageData.source, 'to', primaryPubKey);
|
|
|
|
|
log.info(`Rewriting ${messageData.source} to ${primaryPubKey}`);
|
|
|
|
|
messageData.source = primaryPubKey;
|
|
|
|
|
messageData.message.profile.displayName = this.primaryUserProfileName[
|
|
|
|
|
primaryPubKey
|
|
|
|
|