mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
Merge pull request #539 from neuroscr/multidevice-publicchat
[multi-device] public chat
This commit is contained in:
commit
a2e8e6480f
|
@ -1445,7 +1445,10 @@
|
|||
return handleProfileUpdate({ data, confirm, messageDescriptor });
|
||||
}
|
||||
|
||||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
|
||||
const allOurDevices = await libloki.storage.getAllDevicePubKeysForPrimaryPubKey(
|
||||
primaryDeviceKey
|
||||
);
|
||||
const descriptorId = await textsecure.MessageReceiver.arrayBufferToString(
|
||||
messageDescriptor.id
|
||||
);
|
||||
|
@ -1453,7 +1456,7 @@
|
|||
if (
|
||||
messageDescriptor.type === 'group' &&
|
||||
descriptorId.match(/^publicChat:/) &&
|
||||
data.source === ourNumber
|
||||
allOurDevices.includes(data.source)
|
||||
) {
|
||||
// Public chat messages from ourselves should be outgoing
|
||||
message = await createSentMessage(data);
|
||||
|
|
|
@ -1268,7 +1268,11 @@
|
|||
|
||||
this.trigger('sent', this);
|
||||
if (this.get('type') !== 'friend-request') {
|
||||
this.sendSyncMessage();
|
||||
const c = this.getConversation();
|
||||
// Don't bother sending sync messages to public chats
|
||||
if (!c.isPublic()) {
|
||||
this.sendSyncMessage();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(result => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* global log, textsecure, libloki, Signal, Whisper, Headers, ConversationController,
|
||||
clearTimeout, MessageController, libsignal, StringView, window, _, dcodeIO, Buffer */
|
||||
clearTimeout, MessageController, libsignal, StringView, window, _, lokiFileServerAPI,
|
||||
dcodeIO, Buffer */
|
||||
const EventEmitter = require('events');
|
||||
const nodeFetch = require('node-fetch');
|
||||
const { URL, URLSearchParams } = require('url');
|
||||
|
@ -16,12 +17,17 @@ const ATTACHMENT_TYPE = 'net.app.core.oembed';
|
|||
const LOKI_ATTACHMENT_TYPE = 'attachment';
|
||||
const LOKI_PREVIEW_TYPE = 'preview';
|
||||
|
||||
// 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() {
|
||||
|
@ -162,6 +168,55 @@ class LokiAppDotNetServerAPI {
|
|||
}
|
||||
}
|
||||
this.token = token;
|
||||
|
||||
// verify token info
|
||||
const tokenRes = await this.serverRequest('token');
|
||||
// if no problems and we have data
|
||||
if (
|
||||
!tokenRes.err &&
|
||||
tokenRes.response &&
|
||||
tokenRes.response.data &&
|
||||
tokenRes.response.data.user
|
||||
) {
|
||||
// get our profile name and write it to the network
|
||||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const profileConvo = ConversationController.get(ourNumber);
|
||||
const profileName = profileConvo.getProfileName();
|
||||
|
||||
// update profile name as needed
|
||||
if (tokenRes.response.data.user.name !== profileName) {
|
||||
if (profileName) {
|
||||
// will need this when we add an annotation
|
||||
/*
|
||||
const privKey = await this.serverAPI.chatAPI.getPrivateKey();
|
||||
// we might need an annotation that sets the homeserver for media
|
||||
// better to include this with each attachment...
|
||||
const objToSign = {
|
||||
name: profileName,
|
||||
version: 1,
|
||||
annotations: [],
|
||||
};
|
||||
const sig = await libsignal.Curve.async.calculateSignature(
|
||||
privKey,
|
||||
JSON.stringify(objToSign)
|
||||
);
|
||||
*/
|
||||
|
||||
await this.serverRequest('users/me', {
|
||||
method: 'PATCH',
|
||||
objBody: {
|
||||
name: profileName,
|
||||
},
|
||||
});
|
||||
// no big deal if it fails...
|
||||
// } else {
|
||||
// should we update the local from the server?
|
||||
// guessing no because there will be multiple servers
|
||||
}
|
||||
// update our avatar if needed
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -338,6 +393,36 @@ class LokiAppDotNetServerAPI {
|
|||
return res.response.data.annotations || [];
|
||||
}
|
||||
|
||||
async getUsers(pubKeys) {
|
||||
if (!pubKeys) {
|
||||
log.warn('No pubKeys provided to getUsers!');
|
||||
return [];
|
||||
}
|
||||
// ok to call without
|
||||
if (!pubKeys.length) {
|
||||
return [];
|
||||
}
|
||||
if (pubKeys.length > 200) {
|
||||
log.warn('Too many pubKeys given to getUsers!');
|
||||
}
|
||||
const res = await this.serverRequest('users', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
ids: pubKeys.join(','),
|
||||
include_user_annotations: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.err || !res.response || !res.response.data) {
|
||||
if (res.err) {
|
||||
log.error(`Error ${res.err}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
return res.response.data || [];
|
||||
}
|
||||
|
||||
// Only one annotation at a time
|
||||
async setSelfAnnotation(type, value) {
|
||||
const annotation = { type };
|
||||
|
@ -481,53 +566,6 @@ class LokiPublicChannelAPI {
|
|||
}
|
||||
|
||||
await this.conversation.setModerators(moderators || []);
|
||||
|
||||
// get token info
|
||||
const tokenRes = await this.serverRequest('token');
|
||||
// if no problems and we have data
|
||||
if (
|
||||
!tokenRes.err &&
|
||||
tokenRes.response &&
|
||||
tokenRes.response.data &&
|
||||
tokenRes.response.data.user
|
||||
) {
|
||||
// get our profile name and write it to the network
|
||||
const profileConvo = ConversationController.get(ourNumber);
|
||||
const profileName = profileConvo.getProfileName();
|
||||
|
||||
// update profile name as needed
|
||||
if (tokenRes.response.data.user.name !== profileName) {
|
||||
if (profileName) {
|
||||
// will need this when we add an annotation
|
||||
/*
|
||||
const privKey = await this.serverAPI.chatAPI.getPrivateKey();
|
||||
// we might need an annotation that sets the homeserver for media
|
||||
// better to include this with each attachment...
|
||||
const objToSign = {
|
||||
name: profileName,
|
||||
version: 1,
|
||||
annotations: [],
|
||||
};
|
||||
const sig = await libsignal.Curve.async.calculateSignature(
|
||||
privKey,
|
||||
JSON.stringify(objToSign)
|
||||
);
|
||||
*/
|
||||
|
||||
await this.serverRequest('users/me', {
|
||||
method: 'PATCH',
|
||||
objBody: {
|
||||
name: profileName,
|
||||
},
|
||||
});
|
||||
// no big deal if it fails...
|
||||
// } else {
|
||||
// should we update the local from the server?
|
||||
// guessing no because there will be multiple servers
|
||||
}
|
||||
// update our avatar if needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete a message on the server
|
||||
|
@ -798,9 +836,17 @@ class LokiPublicChannelAPI {
|
|||
params,
|
||||
});
|
||||
|
||||
if (!res.err && res.response) {
|
||||
let receivedAt = new Date().getTime();
|
||||
res.response.data.reverse().forEach(async adnMessage => {
|
||||
if (res.err || !res.response) {
|
||||
return;
|
||||
}
|
||||
|
||||
let receivedAt = new Date().getTime();
|
||||
const pubKeys = [];
|
||||
let pendingMessages = [];
|
||||
|
||||
// the signature forces this to be async
|
||||
pendingMessages = await Promise.all(
|
||||
res.response.data.reverse().map(async adnMessage => {
|
||||
// still update our last received if deleted, not signed or not valid
|
||||
this.lastGot = !this.lastGot
|
||||
? adnMessage.id
|
||||
|
@ -813,17 +859,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, attachments, preview } = messengerData;
|
||||
if (!timestamp) {
|
||||
return; // Invalid message
|
||||
return false; // Invalid message
|
||||
}
|
||||
|
||||
// Duplicate check
|
||||
|
@ -841,9 +887,10 @@ 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
|
||||
// Add the message to the lastMessage cache and keep the last 5 recent messages
|
||||
this.lastMessagesCache = [
|
||||
...this.lastMessagesCache,
|
||||
|
@ -856,6 +903,12 @@ class LokiPublicChannelAPI {
|
|||
|
||||
const from = adnMessage.user.name || 'Anonymous'; // profileName
|
||||
|
||||
// track sources for multidevice support
|
||||
if (pubKeys.indexOf(`@${adnMessage.user.username}`) === -1) {
|
||||
pubKeys.push(`@${adnMessage.user.username}`);
|
||||
}
|
||||
|
||||
// generate signal message object
|
||||
const messageData = {
|
||||
serverId: adnMessage.id,
|
||||
clientVerified: true,
|
||||
|
@ -863,6 +916,7 @@ class LokiPublicChannelAPI {
|
|||
source: adnMessage.user.username,
|
||||
sourceDevice: 1,
|
||||
timestamp,
|
||||
|
||||
serverTimestamp: timestamp,
|
||||
receivedAt,
|
||||
isPublic: true,
|
||||
|
@ -890,15 +944,91 @@ class LokiPublicChannelAPI {
|
|||
};
|
||||
receivedAt += 1; // Ensure different arrival times
|
||||
|
||||
// now process any user meta data updates
|
||||
// - update their conversation with a potentially new avatar
|
||||
return messageData;
|
||||
})
|
||||
);
|
||||
this.conversation.setLastRetrievedMessage(this.lastGot);
|
||||
|
||||
// do we really need this?
|
||||
if (!pendingMessages.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get list of verified primary PKs
|
||||
const verifiedPrimaryPKs = await lokiFileServerAPI.verifyPrimaryPubKeys(
|
||||
pubKeys
|
||||
);
|
||||
// access slavePrimaryMap set by verifyPrimaryPubKeys
|
||||
const { slavePrimaryMap } = this.serverAPI.chatAPI;
|
||||
|
||||
// sort pending messages by if slave device or not
|
||||
/* eslint-disable no-param-reassign */
|
||||
const slaveMessages = pendingMessages.reduce((retval, messageData) => {
|
||||
// if a known slave, queue
|
||||
if (slavePrimaryMap[messageData.source]) {
|
||||
// delay sending the message
|
||||
if (retval[messageData.source] === undefined) {
|
||||
retval[messageData.source] = [messageData];
|
||||
} else {
|
||||
retval[messageData.source].push(messageData);
|
||||
}
|
||||
} else {
|
||||
// no user or isPrimary means not multidevice, send event now
|
||||
this.serverAPI.chatAPI.emit('publicMessage', {
|
||||
message: messageData,
|
||||
});
|
||||
}
|
||||
return retval;
|
||||
}, {});
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
// now process any user meta data updates
|
||||
// - update their conversation with a potentially new avatar
|
||||
pendingMessages = []; // allow memory to be freed
|
||||
|
||||
// get actual chat server data (mainly the name rn) of primary device
|
||||
const verifiedDeviceResults = await this.serverAPI.getUsers(
|
||||
verifiedPrimaryPKs
|
||||
);
|
||||
|
||||
// build map of userProfileName to primaryKeys
|
||||
/* eslint-disable no-param-reassign */
|
||||
this.primaryUserProfileName = verifiedDeviceResults.reduce(
|
||||
(mapOut, user) => {
|
||||
mapOut[user.username] = user.name;
|
||||
return mapOut;
|
||||
},
|
||||
{}
|
||||
);
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
// process remaining messages
|
||||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
Object.keys(slaveMessages).forEach(slaveKey => {
|
||||
// prevent our own device sent messages from coming back in
|
||||
if (slaveKey === ourNumber) {
|
||||
// we originally sent these
|
||||
return;
|
||||
}
|
||||
|
||||
// look up primary device once
|
||||
const primaryPubKey = slavePrimaryMap[slaveKey];
|
||||
|
||||
// send out remaining messages for this merged identity
|
||||
slaveMessages[slaveKey].forEach(messageDataP => {
|
||||
const messageData = messageDataP; // for linter
|
||||
if (slavePrimaryMap[messageData.source]) {
|
||||
// rewrite source, profile
|
||||
messageData.source = primaryPubKey;
|
||||
messageData.message.profile.displayName = this.primaryUserProfileName[
|
||||
primaryPubKey
|
||||
];
|
||||
}
|
||||
this.serverAPI.chatAPI.emit('publicMessage', {
|
||||
message: messageData,
|
||||
});
|
||||
});
|
||||
this.conversation.setLastRetrievedMessage(this.lastGot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static getPreviewFromAnnotation(annotation) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global window, log, libloki */
|
||||
/* global storage: false */
|
||||
/* global Signal: false */
|
||||
/* global log: false */
|
||||
|
@ -6,6 +7,8 @@ const LokiAppDotNetAPI = require('./loki_app_dot_net_api');
|
|||
|
||||
const DEVICE_MAPPING_ANNOTATION_KEY = 'network.loki.messenger.devicemapping';
|
||||
|
||||
// can have multiple of these objects instances as each user can have a
|
||||
// different home server
|
||||
class LokiFileServerAPI {
|
||||
constructor(ourKey) {
|
||||
this.ourKey = ourKey;
|
||||
|
@ -43,6 +46,166 @@ class LokiFileServerAPI {
|
|||
return this._setOurDeviceMapping(authorisations, isPrimary);
|
||||
}
|
||||
|
||||
async getDeviceMappingForUsers(pubKeys) {
|
||||
const users = await this._server.getUsers(pubKeys);
|
||||
return users;
|
||||
}
|
||||
|
||||
async verifyUserObjectDeviceMap(pubKeys, isRequest, iterator) {
|
||||
const users = await this.getDeviceMappingForUsers(pubKeys);
|
||||
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
|
||||
// verifies list of pubKeys for any deviceMappings
|
||||
// returns the relevant primary pubKeys
|
||||
async verifyPrimaryPubKeys(pubKeys) {
|
||||
const newSlavePrimaryMap = {}; // new slave to primary map
|
||||
// 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) => {
|
||||
// if we already have this key for a different device
|
||||
if (
|
||||
newSlavePrimaryMap[slaveKey] &&
|
||||
newSlavePrimaryMap[slaveKey] !== auth.primaryDevicePubKey
|
||||
) {
|
||||
log.warn(
|
||||
`file server user annotation primaryKey mismatch, had ${
|
||||
newSlavePrimaryMap[slaveKey]
|
||||
} now ${auth.primaryDevicePubKey} for ${slaveKey}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
// at this point it's valid
|
||||
|
||||
// add to primaryPubKeys
|
||||
if (primaryPubKeys.indexOf(`@${auth.primaryDevicePubKey}`) === -1) {
|
||||
primaryPubKeys.push(`@${auth.primaryDevicePubKey}`);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// no valid primary pubkeys to check
|
||||
if (!primaryPubKeys.length) {
|
||||
// log.warn(`no valid primary pubkeys to check ${pubKeys}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
const verifiedPrimaryPKs = [];
|
||||
|
||||
// get a list of all of primary pubKeys to verify the secondaryDevice assertion
|
||||
const notFoundUsers = await this.verifyUserObjectDeviceMap(
|
||||
primaryPubKeys,
|
||||
false,
|
||||
primaryKey => {
|
||||
// add to verified list if we don't already have it
|
||||
if (verifiedPrimaryPKs.indexOf(`@${primaryKey}`) === -1) {
|
||||
verifiedPrimaryPKs.push(`@${primaryKey}`);
|
||||
}
|
||||
|
||||
// assuming both are ordered the same way
|
||||
// make sure our secondary and primary authorization match
|
||||
/*
|
||||
if (
|
||||
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
|
||||
} does not match ${primaryKey}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
); // end verifyUserObjectDeviceMap
|
||||
|
||||
// remove from newSlavePrimaryMap if no valid mapping is found
|
||||
notFoundUsers.forEach(primaryPubKey => {
|
||||
Object.keys(newSlavePrimaryMap).forEach(slaveKey => {
|
||||
if (newSlavePrimaryMap[slaveKey] === primaryPubKey) {
|
||||
log.warn(
|
||||
`removing unverifible ${slaveKey} to ${primaryPubKey} mapping`
|
||||
);
|
||||
delete newSlavePrimaryMap[slaveKey];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// FIXME: move to a return value since we're only scoped to pubkeys given
|
||||
// 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',
|
||||
|
|
|
@ -175,16 +175,13 @@
|
|||
return signature;
|
||||
}
|
||||
|
||||
async function validateAuthorisation(authorisation) {
|
||||
async function verifyAuthorisation(authorisation) {
|
||||
const {
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
requestSignature,
|
||||
grantSignature,
|
||||
} = authorisation;
|
||||
const alreadySecondaryDevice = !!window.storage.get('isSecondaryDevice');
|
||||
const ourPubKey = textsecure.storage.user.getNumber();
|
||||
const isRequest = !grantSignature;
|
||||
const isGrant = !!grantSignature;
|
||||
if (!primaryDevicePubKey || !secondaryDevicePubKey) {
|
||||
window.log.warn(
|
||||
|
@ -196,19 +193,6 @@
|
|||
'Received a pairing request with missing request signature. Ignored.'
|
||||
);
|
||||
return false;
|
||||
} else if (isRequest && alreadySecondaryDevice) {
|
||||
window.log.warn(
|
||||
'Received a pairing request while being a secondary device. Ignored.'
|
||||
);
|
||||
return false;
|
||||
} else if (isRequest && authorisation.primaryDevicePubKey !== ourPubKey) {
|
||||
window.log.warn(
|
||||
'Received a pairing request addressed to another pubkey. Ignored.'
|
||||
);
|
||||
return false;
|
||||
} else if (isRequest && authorisation.secondaryDevicePubKey === ourPubKey) {
|
||||
window.log.warn('Received a pairing request from ourselves. Ignored.');
|
||||
return false;
|
||||
}
|
||||
const verify = async (signature, signatureType) => {
|
||||
const encoding = typeof signature === 'string' ? 'base64' : undefined;
|
||||
|
@ -228,6 +212,7 @@
|
|||
window.log.error(e);
|
||||
return false;
|
||||
}
|
||||
// can't have grant without requestSignature?
|
||||
if (isGrant) {
|
||||
try {
|
||||
await verify(grantSignature, PairingType.GRANT);
|
||||
|
@ -242,6 +227,33 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: rename to include the fact it's relative to YOUR device
|
||||
async function validateAuthorisation(authorisation) {
|
||||
const {
|
||||
primaryDevicePubKey,
|
||||
secondaryDevicePubKey,
|
||||
grantSignature,
|
||||
} = authorisation;
|
||||
const alreadySecondaryDevice = !!window.storage.get('isSecondaryDevice');
|
||||
const ourPubKey = textsecure.storage.user.getNumber();
|
||||
const isRequest = !grantSignature;
|
||||
if (isRequest && alreadySecondaryDevice) {
|
||||
window.log.warn(
|
||||
'Received a pairing request while being a secondary device. Ignored.'
|
||||
);
|
||||
return false;
|
||||
} else if (isRequest && primaryDevicePubKey !== ourPubKey) {
|
||||
window.log.warn(
|
||||
'Received a pairing request addressed to another pubkey. Ignored.'
|
||||
);
|
||||
return false;
|
||||
} else if (isRequest && secondaryDevicePubKey === ourPubKey) {
|
||||
window.log.warn('Received a pairing request from ourselves. Ignored.');
|
||||
return false;
|
||||
}
|
||||
return this.verifyAuthorisation(authorisation);
|
||||
}
|
||||
|
||||
async function verifyPairingSignature(
|
||||
primaryDevicePubKey,
|
||||
secondaryPubKey,
|
||||
|
@ -307,6 +319,7 @@
|
|||
decryptToken,
|
||||
generateSignatureForPairing,
|
||||
verifyPairingSignature,
|
||||
verifyAuthorisation,
|
||||
validateAuthorisation,
|
||||
PairingType,
|
||||
// for testing
|
||||
|
|
Loading…
Reference in a new issue