|
|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
/* global dcodeIO, window, log, textsecure */
|
|
|
|
|
/* global window, log, libloki */
|
|
|
|
|
/* global storage: false */
|
|
|
|
|
/* global Signal: false */
|
|
|
|
|
/* global log: false */
|
|
|
|
|
@ -7,13 +7,6 @@ const LokiAppDotNetAPI = require('./loki_app_dot_net_api');
|
|
|
|
|
|
|
|
|
|
const DEVICE_MAPPING_ANNOTATION_KEY = 'network.loki.messenger.devicemapping';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// returns the LokiFileServerAPI constructor with the serverUrl already consumed
|
|
|
|
|
function LokiFileServerAPIWrapper(serverUrl) {
|
|
|
|
|
return LokiFileServerAPI.bind(null, serverUrl);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// can have multiple of these objects instances as each user can have a
|
|
|
|
|
// different home server
|
|
|
|
|
class LokiFileServerAPI {
|
|
|
|
|
@ -60,43 +53,47 @@ class LokiFileServerAPI {
|
|
|
|
|
|
|
|
|
|
async verifyUserObjectDeviceMap(pubKeys, isRequest, iterator) {
|
|
|
|
|
const users = await this.getDeviceMappingForUsers(pubKeys);
|
|
|
|
|
// log.info('verifyUserObjectDeviceMap Found', users.length, 'users')
|
|
|
|
|
|
|
|
|
|
// go through each user and find deviceMap annotations
|
|
|
|
|
const notFoundUsers = [];
|
|
|
|
|
await Promise.all(users.map(async user => {
|
|
|
|
|
let found = false;
|
|
|
|
|
if (!user.annotations || !user.annotations.length) {
|
|
|
|
|
log.info(
|
|
|
|
|
`verifyUserObjectDeviceMap no annotation for ${user.username}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const mappingNote = user.annotations.find(note => note.type === DEVICE_MAPPING_ANNOTATION_KEY);
|
|
|
|
|
const { authorisations } = mappingNote.value;
|
|
|
|
|
if (!Array.isArray(authorisations)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await Promise.all(authorisations.map(async auth => {
|
|
|
|
|
// only skip, if in secondary search mode
|
|
|
|
|
if (isRequest && auth.secondaryDevicePubKey !== user.username) {
|
|
|
|
|
// this is not the authorization we're looking for
|
|
|
|
|
await Promise.all(
|
|
|
|
|
users.map(async user => {
|
|
|
|
|
let found = false;
|
|
|
|
|
if (!user.annotations || !user.annotations.length) {
|
|
|
|
|
log.info(
|
|
|
|
|
`Request and ${auth.secondaryDevicePubKey} != ${user.username}`
|
|
|
|
|
`verifyUserObjectDeviceMap no annotation for ${user.username}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const valid = await libloki.crypto.validateAuthorisation(auth);
|
|
|
|
|
// log.info('auth is valid for', user.username)
|
|
|
|
|
if (iterator(user.username, auth)) {
|
|
|
|
|
found = true;
|
|
|
|
|
const mappingNote = user.annotations.find(
|
|
|
|
|
note => note.type === DEVICE_MAPPING_ANNOTATION_KEY
|
|
|
|
|
);
|
|
|
|
|
const { authorisations } = mappingNote.value;
|
|
|
|
|
if (!Array.isArray(authorisations)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
})); // end map authorisations
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
notFoundUsers.push(user.username);
|
|
|
|
|
}
|
|
|
|
|
})); // end map users
|
|
|
|
|
await Promise.all(
|
|
|
|
|
authorisations.map(async auth => {
|
|
|
|
|
// only skip, if in secondary search mode
|
|
|
|
|
if (isRequest && auth.secondaryDevicePubKey !== user.username) {
|
|
|
|
|
// this is not the authorization we're looking for
|
|
|
|
|
log.info(
|
|
|
|
|
`Request and ${auth.secondaryDevicePubKey} != ${user.username}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const valid = await libloki.crypto.validateAuthorisation(auth);
|
|
|
|
|
if (valid && iterator(user.username, auth)) {
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
); // end map authorisations
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
notFoundUsers.push(user.username);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
); // end map users
|
|
|
|
|
// log.info('done with users', users.length);
|
|
|
|
|
return notFoundUsers;
|
|
|
|
|
}
|
|
|
|
|
@ -105,14 +102,13 @@ class LokiFileServerAPI {
|
|
|
|
|
// returns the relevant primary pubKeys
|
|
|
|
|
async verifyPrimaryPubKeys(pubKeys) {
|
|
|
|
|
const newSlavePrimaryMap = {}; // new slave to primary map
|
|
|
|
|
const checkSigs = {}; // cache for authorization
|
|
|
|
|
// checkSig disabled for now
|
|
|
|
|
// const checkSigs = {}; // cache for authorisation
|
|
|
|
|
const primaryPubKeys = [];
|
|
|
|
|
|
|
|
|
|
// go through multiDeviceResults and get primary Pubkey
|
|
|
|
|
await this.verifyUserObjectDeviceMap(pubKeys, true, (slaveKey, auth) => {
|
|
|
|
|
// log.info('slave iterator', slaveKey);
|
|
|
|
|
// if it doesn't throw, that means it's valid
|
|
|
|
|
// add map to newSlavePrimaryMap
|
|
|
|
|
// if we already have this key for a different device
|
|
|
|
|
if (
|
|
|
|
|
newSlavePrimaryMap[slaveKey] &&
|
|
|
|
|
newSlavePrimaryMap[slaveKey] !== auth.primaryDevicePubKey
|
|
|
|
|
@ -124,16 +120,27 @@ class LokiFileServerAPI {
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// log.info('valid', slaveKey);
|
|
|
|
|
// at this point it's valid
|
|
|
|
|
|
|
|
|
|
// add to primaryPubKeys
|
|
|
|
|
if (primaryPubKeys.indexOf(`@${auth.primaryDevicePubKey}`) === -1) {
|
|
|
|
|
primaryPubKeys.push(`@${auth.primaryDevicePubKey}`);
|
|
|
|
|
}
|
|
|
|
|
checkSigs[slaveKey] = auth;
|
|
|
|
|
|
|
|
|
|
// add authorisation cache
|
|
|
|
|
/*
|
|
|
|
|
if (checkSigs[`${auth.primaryDevicePubKey}_${slaveKey}`] !== undefined) {
|
|
|
|
|
log.warn(
|
|
|
|
|
`file server ${auth.primaryDevicePubKey} to ${slaveKey} double signed`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
checkSigs[`${auth.primaryDevicePubKey}_${slaveKey}`] = auth;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// add map to newSlavePrimaryMap
|
|
|
|
|
newSlavePrimaryMap[slaveKey] = auth.primaryDevicePubKey;
|
|
|
|
|
}); // end verifyUserObjectDeviceMap
|
|
|
|
|
|
|
|
|
|
// log.info('verifyUserObjectDeviceMap', pubKeys, '=>', primaryPubKeys);
|
|
|
|
|
|
|
|
|
|
// no valid primary pubkeys to check
|
|
|
|
|
if (!primaryPubKeys.length) {
|
|
|
|
|
// log.warn(`no valid primary pubkeys to check ${pubKeys}`);
|
|
|
|
|
@ -146,18 +153,22 @@ class LokiFileServerAPI {
|
|
|
|
|
const notFoundUsers = await this.verifyUserObjectDeviceMap(
|
|
|
|
|
primaryPubKeys,
|
|
|
|
|
false,
|
|
|
|
|
(primaryKey, auth) => {
|
|
|
|
|
// log.info('primary iterator', slaveKey);
|
|
|
|
|
primaryKey => {
|
|
|
|
|
// add to verified list if we don't already have it
|
|
|
|
|
if (verifiedPrimaryPKs.indexOf(`@${primaryKey}`) === -1) {
|
|
|
|
|
verifiedPrimaryPKs.push(`@${primaryKey}`);
|
|
|
|
|
}
|
|
|
|
|
// assuming both are ordered
|
|
|
|
|
|
|
|
|
|
// assuming both are ordered the same way
|
|
|
|
|
// make sure our secondary and primary authorization match
|
|
|
|
|
/*
|
|
|
|
|
if (
|
|
|
|
|
JSON.stringify(checkSigs[auth.secondaryDevicePubKey]) !==
|
|
|
|
|
JSON.stringify(auth)
|
|
|
|
|
JSON.stringify(checkSigs[
|
|
|
|
|
`${auth.primaryDevicePubKey}_${auth.secondaryDevicePubKey}`
|
|
|
|
|
]) !== JSON.stringify(auth)
|
|
|
|
|
) {
|
|
|
|
|
// should hopefully never happen
|
|
|
|
|
// it did, old pairing data, I think...
|
|
|
|
|
log.warn(
|
|
|
|
|
`Valid authorizations from ${
|
|
|
|
|
auth.secondaryDevicePubKey
|
|
|
|
|
@ -165,6 +176,7 @@ class LokiFileServerAPI {
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
); // end verifyUserObjectDeviceMap
|
|
|
|
|
@ -181,6 +193,7 @@ class LokiFileServerAPI {
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// FIXME: move to a return value since we're only scoped to pubkeys given
|
|
|
|
|
// make new map final
|
|
|
|
|
window.lokiPublicChatAPI.slavePrimaryMap = newSlavePrimaryMap;
|
|
|
|
|
|
|
|
|
|
|