move file server related functions into file server, make multidevice states global

pull/539/head
Ryan Tharp 6 years ago
parent 206d29b033
commit 7f433f3df0

@ -1,6 +1,5 @@
/* global log, textsecure, libloki, Signal, Whisper, Headers, ConversationController,
clearTimeout, MessageController, libsignal, StringView, window, _, lokiFileServerAPI,
dcodeIO */
clearTimeout, MessageController, libsignal, StringView, window, _, lokiFileServerAPI */
const EventEmitter = require('events');
const nodeFetch = require('node-fetch');
const { URL, URLSearchParams } = require('url');
@ -12,12 +11,17 @@ const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 5s
const PUBLICCHAT_MOD_POLL_EVERY = 30 * 1000; // 30s
const PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES = 10 * 1000; // 10s
// not quite a singleton yet (one for chat and one per file server)
class LokiAppDotNetAPI extends EventEmitter {
constructor(ourKey) {
super();
this.ourKey = ourKey;
this.servers = [];
this.myPrivateKey = false;
// Multidevice states
this.slavePrimaryMap = {};
this.primaryUserProfileName = {};
}
async close() {
@ -445,10 +449,6 @@ class LokiPublicChannelAPI {
// Cache for duplicate checking
this.lastMessagesCache = [];
// Multidevice states
this.slavePrimaryMap = {};
this.primaryUserProfileName = {};
// end properties
log.info(`registered LokiPublicChannel ${channelId}`);
@ -859,93 +859,23 @@ class LokiPublicChannelAPI {
this.conversation.setLastRetrievedMessage(this.lastGot);
if (pendingMessages.length) {
const newSlavePrimaryMap = {};
const checkSigs = {};
// console.log('premultiDeviceResults', pubKeys)
// console.log('premultiDeviceResults', pubKeys);
if (pubKeys.length) {
const multiDeviceResults = await lokiFileServerAPI.getDeviceMappingForUsers(
const verifiedPrimaryPKs = await lokiFileServerAPI.verifyPrimaryPubKeys(
pubKeys
);
// console.log('multiDeviceResults', multiDeviceResults);
multiDeviceResults.forEach(user => {
if (user.annotations) {
user.annotations.forEach(note => {
if (note.type === 'network.loki.messenger.devicemapping') {
// console.log('devmap note', note);
// is slave?
if (note.value.isPrimary === '0') {
const { authorisations } = note.value;
if (Array.isArray(authorisations)) {
authorisations.forEach(auth => {
if (auth.secondaryDevicePubKey !== user.username) {
// this is not the authorization we're looking for
return;
}
// console.log('auth', auth);
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 (
newSlavePrimaryMap[user.username] &&
newSlavePrimaryMap[user.username] !==
auth.primaryDevicePubKey
) {
log.warn(
`file server user annotation primaryKey mismatch, had ${
newSlavePrimaryMap[user.username]
} now ${auth.primaryDevicePubKey} for ${
user.username
}`
);
return;
}
checkSigs[user.username] = auth;
newSlavePrimaryMap[user.username] =
auth.primaryDevicePubKey;
} catch (e) {
log.warn(
`Invalid grant signature on SecondaryPubKey ${
auth.secondaryDevicePubKey
}`
);
}
});
}
}
}
});
}
});
// log.info('tenative slavePrimaryMap', newSlavePrimaryMap);
const { slavePrimaryMap } = this.serverAPI.chatAPI;
const primaryPubKeys = [];
const slaveMessages = {};
// go through multiDeviceResults and get primary Pubkey
// sort pending messages
pendingMessages.forEach(messageData => {
// why am I getting these?
if (messageData === undefined) {
log.warn('invalid pendingMessages');
return;
}
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}`);
}
// if a known slave, queue
if (slavePrimaryMap[messageData.source]) {
// delay sending the message
if (slaveMessages[messageData.source] === undefined) {
slaveMessages[messageData.source] = [messageData];
@ -961,93 +891,6 @@ class LokiPublicChannelAPI {
});
pendingMessages = []; // free memory
const verifiedPrimaryPKs = [];
if (primaryPubKeys.length) {
// get a list of all of primary pubKeys to verify the secondaryDevice
const primaryDeviceResults = await lokiFileServerAPI.getDeviceMappingForUsers(
primaryPubKeys
);
// 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;
if (Array.isArray(authorisations)) {
authorisations.forEach(auth => {
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}`
);
}
// assuming both are ordered
// make sure our secondary and primary authorization match
if (
JSON.stringify(
checkSigs[auth.secondaryDevicePubKey]
) !== JSON.stringify(auth)
) {
// should hopefully never happen
log.warn(
`Valid authorizations from ${
auth.secondaryDevicePubKey
} does not match ${auth.primaryDevicePubKey}`
);
return;
}
found = true;
} catch (e) {
log.warn(
`Invalid grant signature on PrimaryPubKey ${
auth.primaryDevicePubKey
}`
);
}
});
}
}
}
});
}
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)}`
);
// if we have verified primaryKeys then update them
if (verifiedPrimaryPKs.length) {
// get final list of verified chat server profile names
@ -1073,10 +916,10 @@ class LokiPublicChannelAPI {
// we originally sent these
return;
}
const primaryPubKey = this.slavePrimaryMap[slaveKey];
const primaryPubKey = slavePrimaryMap[slaveKey];
slaveMessages[slaveKey].forEach(messageDataP => {
const messageData = messageDataP; // for linter
if (this.slavePrimaryMap[messageData.source]) {
if (slavePrimaryMap[messageData.source]) {
// rewrite source, profile
messageData.source = primaryPubKey;
messageData.message.profile.displayName = this.primaryUserProfileName[
@ -1095,6 +938,7 @@ class LokiPublicChannelAPI {
// console.log('pendingMessages', pendingMessages);
// find messages for original slave key using slavePrimaryMap
if (pendingMessages.length) {
const { slavePrimaryMap } = this.serverAPI.chatAPI;
const ourNumber = textsecure.storage.user.getNumber();
pendingMessages.forEach(messageDataP => {
const messageData = messageDataP; // for linter
@ -1108,9 +952,9 @@ class LokiPublicChannelAPI {
// we originally sent this
return;
}
if (this.slavePrimaryMap[messageData.source]) {
if (slavePrimaryMap[messageData.source]) {
// rewrite source, profile
const primaryPubKey = this.slavePrimaryMap[messageData.source];
const primaryPubKey = slavePrimaryMap[messageData.source];
log.info(`Rewriting ${messageData.source} to ${primaryPubKey}`);
messageData.source = primaryPubKey;
messageData.message.profile.displayName = this.primaryUserProfileName[

Loading…
Cancel
Save