From ddde675ba8ba46da298ba2eb4899f51bd5f285f0 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Tue, 1 Oct 2019 12:41:38 -0700 Subject: [PATCH] stub out multidevice support, move token validation into server class --- js/modules/loki_app_dot_net_api.js | 182 +++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 47 deletions(-) diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index ca5bb3ade..968d838e5 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -140,6 +140,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; } @@ -311,6 +360,37 @@ class LokiAppDotNetServerAPI { return res.response.data.annotations || []; } + async getUsersAnnotations(pubKeys) { + if (!pubKeys) { + log.warn('No pubKeys provided to getUsersAnnotations!'); + return []; + } + if (!pubKeys.length) { + log.warn('No pubKeys given to getUsersAnnotations!'); + return []; + } + if (pubKeys.length > 200) { + log.warn('Too many pubKeys given to getUsersAnnotations!'); + } + console.log('getUsersAnnotations', pubKeys) + 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 }; @@ -417,53 +497,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 @@ -706,6 +739,8 @@ class LokiPublicChannelAPI { if (!res.err && res.response) { let receivedAt = new Date().getTime(); + const pubKeys = [] + const pendingMessages = [] res.response.data.reverse().forEach(async adnMessage => { // still update our last received if deleted, not signed or not valid this.lastGot = !this.lastGot @@ -751,6 +786,7 @@ class LokiPublicChannelAPI { return; // 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, @@ -762,6 +798,12 @@ class LokiPublicChannelAPI { ].splice(-5); const from = adnMessage.user.name; // profileName + console.log('checking', adnMessage.user.username, 'in', pubKeys) + if (pubKeys.indexOf(adnMessage.user.username) == -1) { + console.log('pushing pubkey', adnMessage.user.username) + pubKeys.push(adnMessage.user.username) + console.log('pubKeys', pubKeys) + } const messageData = { serverId: adnMessage.id, @@ -796,14 +838,60 @@ class LokiPublicChannelAPI { }; receivedAt += 1; // Ensure different arrival times + /* this.serverAPI.chatAPI.emit('publicMessage', { message: messageData, }); + */ + console.log('pushing back message from', adnMessage.user.username) + pendingMessages.push(messageData) // now process any user meta data updates // - update their conversation with a potentially new avatar }); this.conversation.setLastRetrievedMessage(this.lastGot); + + // + console.log('pendingMessages', pendingMessages.length) + if (pendingMessages.length) { + const slavePrimaryMap = {}; + + console.log('premultiDeviceResults', pubKeys) + if (pubKeys.length) { + const multiDeviceResults = await lokiFileServerAPI.getDeviceMappingForUsers(pubKeys); + console.log('multiDeviceResults', multiDeviceResults) + // no user or isPrimary means not multidevice, send event now + + + const primaryPubKeys = []; + // go through multiDeviceResults and get primary Pubkey + // verify secondary sig + // add map to slavePrimaryMap + + const verifiedPrimaryPKs = []; + // get a list of all of primary pubKeys to verify the secondaryDevice + const primaryDeviceResults = await lokiFileServerAPI.getDeviceMappingForUsers(primaryPubKeys); + // go through primaryDeviceResults and verify primary sig + // if not verified remove from slavePrimaryMap + + // get final list of verified chat server profile names + const verifiedDeviceResults = await this.getDeviceMappingForUsers(verifiedPrimaryPKs); + // go through verifiedDeviceResults + // find messages for original slave key using slavePrimaryMap + } + + pendingMessages.forEach(messageData => { + if (slavePrimaryMap[messageData.source]) { + // rewrite source, profile + messageData.source = slavePrimaryMap.username + messageData.message.profile.displayName = slavePrimaryMap.name + } + this.serverAPI.chatAPI.emit('publicMessage', { + message: messageData, + }); + }) + pendingMessages = [] + } } }