verifyUserObjectDeviceMap() and refactor out verifyPrimaryPubKeys()

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

@ -1,3 +1,4 @@
/* global dcodeIO, window, log, textsecure */
/* global storage: false */
/* global Signal: false */
@ -10,6 +11,8 @@ 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 {
constructor(serverUrl, ourKey) {
this.ourKey = ourKey;
@ -45,6 +48,179 @@ class LokiFileServerAPI {
return users;
}
async verifyUserObjectDeviceMap(
pubKeys,
isRequest,
iterator,
notFoundHandler
) {
const users = await this.getDeviceMappingForUsers(pubKeys);
// log.info('verifyUserObjectDeviceMap Found', users.length, 'users')
// go through each user and find deviceMap annotations
users.forEach(user => {
let found = false;
if (user.annotations) {
user.annotations.forEach(note => {
if (note.type === 'network.loki.messenger.devicemapping') {
// is desired type
if (
(isRequest && note.value.isPrimary === '0') ||
(!isRequest && note.value.isPrimary !== '0')
) {
const { authorisations } = note.value;
if (Array.isArray(authorisations)) {
authorisations.forEach(auth => {
// log.info('devmap auth', 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;
}
// log.info('auth', auth);
try {
// request (secondary wants to be paired with this primary)
// grant (primary approves this secondary)
window.libloki.crypto.verifyPairingSignature(
auth.primaryDevicePubKey,
auth.secondaryDevicePubKey,
dcodeIO.ByteBuffer.wrap(
isRequest ? auth.requestSignature : auth.grantSignature,
'base64'
).toArrayBuffer(),
isRequest
? textsecure.protobuf.PairingAuthorisationMessage.Type
.REQUEST
: textsecure.protobuf.PairingAuthorisationMessage.Type
.GRANT
);
// log.info('auth is valid for', user.username)
if (iterator(user.username, auth)) {
found = true;
}
} catch (e) {
log.warn(
`Invalid signature on pubkey ${
user.username
} authorization ${
auth.secondaryDevicePubKey
} isRequest ${isRequest}`
);
}
}); // end forEach authorisations
}
}
}
}); // end forEach annotations
}
if (notFoundHandler) {
if (found) {
return;
}
notFoundHandler(user.username);
}
}); // end forEach users
// log.info('done with users', users.length);
}
// verifies list of pubKeys for any deviceMappings
// returns the relevant primary pubKeys
async verifyPrimaryPubKeys(pubKeys) {
const newSlavePrimaryMap = {}; // new slave to primary map
const checkSigs = {}; // cache for authorization
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 (
newSlavePrimaryMap[slaveKey] &&
newSlavePrimaryMap[slaveKey] !== auth.primaryDevicePubKey
) {
log.warn(
`file server user annotation primaryKey mismatch, had ${
newSlavePrimaryMap[slaveKey]
} now ${auth.primaryDevicePubKey} for ${slaveKey}`
);
return;
}
// log.info('valid', slaveKey);
if (primaryPubKeys.indexOf(`@${auth.primaryDevicePubKey}`) === -1) {
primaryPubKeys.push(`@${auth.primaryDevicePubKey}`);
}
checkSigs[slaveKey] = auth;
newSlavePrimaryMap[slaveKey] = auth.primaryDevicePubKey;
}); // end verifyUserObjectDeviceMap
// log.info('verifyUserObjectDeviceMap', pubKeys, '=>', primaryPubKeys);
// no valid primary pubkeys to check
if (!primaryPubKeys.length) {
return [];
}
const verifiedPrimaryPKs = [];
// get a list of all of primary pubKeys to verify the secondaryDevice assertion
await this.verifyUserObjectDeviceMap(
primaryPubKeys,
false,
(primaryKey, auth) => {
// log.info('primary iterator', slaveKey);
if (verifiedPrimaryPKs.indexOf(`@${primaryKey}`) === -1) {
verifiedPrimaryPKs.push(`@${primaryKey}`);
}
// 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 ${primaryKey}`
);
return false;
}
return true;
},
primaryPubKey => {
// if not verified remove this user pubkey from newSlavePrimaryMap
Object.keys(newSlavePrimaryMap).forEach(slaveKey => {
if (newSlavePrimaryMap[slaveKey] === primaryPubKey) {
log.warn(
`removing unverifible ${slaveKey} to ${primaryPubKey} mapping`
);
delete newSlavePrimaryMap[slaveKey];
}
});
}
); // end verifyUserObjectDeviceMap
// make new map final
window.lokiPublicChatAPI.slavePrimaryMap = newSlavePrimaryMap;
log.info(
`Updated device mappings ${JSON.stringify(
window.lokiPublicChatAPI.slavePrimaryMap
)}`
);
return verifiedPrimaryPKs;
}
_setOurDeviceMapping(authorisations, isPrimary) {
const content = {
isPrimary: isPrimary ? '1' : '0',

Loading…
Cancel
Save