rebuild-ui
							parent
							
								
									4b517ffd92
								
							
						
					
					
						commit
						95c5a881e1
					
				| @ -1,535 +0,0 @@ | |||||||
| /* global |  | ||||||
|   textsecure, |  | ||||||
|   libsignal, |  | ||||||
|   window, |  | ||||||
|   libloki, |  | ||||||
|   StringView, |  | ||||||
|   lokiMessageAPI, |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| /* eslint-disable more/no-then */ |  | ||||||
| /* eslint-disable no-unreachable */ |  | ||||||
| const NUM_SEND_CONNECTIONS = 3; |  | ||||||
| 
 |  | ||||||
| const getTTLForType = type => { |  | ||||||
|   switch (type) { |  | ||||||
|     case 'pairing-request': |  | ||||||
|       return window.libsession.Constants.TTL_DEFAULT.PAIRING_REQUEST; |  | ||||||
|     case 'device-unpairing': |  | ||||||
|       return window.libsession.Constants.TTL_DEFAULT.DEVICE_UNPAIRING; |  | ||||||
|     case 'onlineBroadcast': |  | ||||||
|       return window.libsession.Constants.TTL_DEFAULT.ONLINE_BROADCAST; |  | ||||||
|     default: |  | ||||||
|       return window.libsession.Constants.TTL_DEFAULT.REGULAR_MESSAGE; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| function _getPaddedMessageLength(messageLength) { |  | ||||||
|   const messageLengthWithTerminator = messageLength + 1; |  | ||||||
|   let messagePartCount = Math.floor(messageLengthWithTerminator / 160); |  | ||||||
| 
 |  | ||||||
|   if (messageLengthWithTerminator % 160 !== 0) { |  | ||||||
|     messagePartCount += 1; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return messagePartCount * 160; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function _convertMessageToText(messageBuffer) { |  | ||||||
|   const plaintext = new Uint8Array( |  | ||||||
|     _getPaddedMessageLength(messageBuffer.byteLength + 1) - 1 |  | ||||||
|   ); |  | ||||||
|   plaintext.set(new Uint8Array(messageBuffer)); |  | ||||||
|   plaintext[messageBuffer.byteLength] = 0x80; |  | ||||||
| 
 |  | ||||||
|   return plaintext; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function _getPlaintext(messageBuffer) { |  | ||||||
|   return _convertMessageToText(messageBuffer); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function wrapInWebsocketMessage(outgoingObject, timestamp) { |  | ||||||
|   const source = |  | ||||||
|     outgoingObject.type === |  | ||||||
|     textsecure.protobuf.Envelope.Type.UNIDENTIFIED_SENDER |  | ||||||
|       ? null |  | ||||||
|       : outgoingObject.ourKey; |  | ||||||
| 
 |  | ||||||
|   const messageEnvelope = new textsecure.protobuf.Envelope({ |  | ||||||
|     type: outgoingObject.type, |  | ||||||
|     source, |  | ||||||
|     sourceDevice: outgoingObject.sourceDevice, |  | ||||||
|     timestamp, |  | ||||||
|     content: outgoingObject.content, |  | ||||||
|   }); |  | ||||||
|   const requestMessage = new textsecure.protobuf.WebSocketRequestMessage({ |  | ||||||
|     id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0], // random ID for now
 |  | ||||||
|     verb: 'PUT', |  | ||||||
|     path: '/api/v1/message', |  | ||||||
|     body: messageEnvelope.encode().toArrayBuffer(), |  | ||||||
|   }); |  | ||||||
|   const websocketMessage = new textsecure.protobuf.WebSocketMessage({ |  | ||||||
|     type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, |  | ||||||
|     request: requestMessage, |  | ||||||
|   }); |  | ||||||
|   const bytes = new Uint8Array(websocketMessage.encode().toArrayBuffer()); |  | ||||||
|   return bytes; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function getStaleDeviceIdsForNumber(number) { |  | ||||||
|   return textsecure.storage.protocol.getDeviceIds(number).then(deviceIds => { |  | ||||||
|     if (deviceIds.length === 0) { |  | ||||||
|       return [1]; |  | ||||||
|     } |  | ||||||
|     const updateDevices = []; |  | ||||||
|     return Promise.all( |  | ||||||
|       deviceIds.map(deviceId => { |  | ||||||
|         const address = new libsignal.SignalProtocolAddress(number, deviceId); |  | ||||||
|         const sessionCipher = new libsignal.SessionCipher( |  | ||||||
|           textsecure.storage.protocol, |  | ||||||
|           address |  | ||||||
|         ); |  | ||||||
|         return sessionCipher.hasOpenSession().then(hasSession => { |  | ||||||
|           if (!hasSession) { |  | ||||||
|             updateDevices.push(deviceId); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|       }) |  | ||||||
|     ).then(() => updateDevices); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function OutgoingMessage( |  | ||||||
|   server, |  | ||||||
|   timestamp, |  | ||||||
|   numbers, |  | ||||||
|   message, |  | ||||||
|   silent, |  | ||||||
|   callback, |  | ||||||
|   options = {} |  | ||||||
| ) { |  | ||||||
|   if (message instanceof textsecure.protobuf.DataMessage) { |  | ||||||
|     const content = new textsecure.protobuf.Content(); |  | ||||||
|     content.dataMessage = message; |  | ||||||
|     // eslint-disable-next-line no-param-reassign
 |  | ||||||
|     message = content; |  | ||||||
|   } |  | ||||||
|   this.server = server; |  | ||||||
|   this.timestamp = timestamp; |  | ||||||
|   this.numbers = numbers; |  | ||||||
|   this.message = message; // ContentMessage proto
 |  | ||||||
|   this.callback = callback; |  | ||||||
|   this.silent = silent; |  | ||||||
| 
 |  | ||||||
|   this.numbersCompleted = 0; |  | ||||||
|   this.errors = []; |  | ||||||
|   this.successfulNumbers = []; |  | ||||||
|   this.fallBackEncryption = false; |  | ||||||
|   this.failoverNumbers = []; |  | ||||||
|   this.unidentifiedDeliveries = []; |  | ||||||
| 
 |  | ||||||
|   const { |  | ||||||
|     numberInfo, |  | ||||||
|     senderCertificate, |  | ||||||
|     online, |  | ||||||
|     messageType, |  | ||||||
|     isPublic, |  | ||||||
|     isMediumGroup, |  | ||||||
|     publicSendData, |  | ||||||
|     autoSession, |  | ||||||
|   } = options || {}; |  | ||||||
|   this.numberInfo = numberInfo; |  | ||||||
|   this.isPublic = isPublic; |  | ||||||
|   this.isMediumGroup = !!isMediumGroup; |  | ||||||
|   this.isGroup = !!( |  | ||||||
|     this.message && |  | ||||||
|     this.message.dataMessage && |  | ||||||
|     this.message.dataMessage.group |  | ||||||
|   ); |  | ||||||
|   this.publicSendData = publicSendData; |  | ||||||
|   this.senderCertificate = senderCertificate; |  | ||||||
|   this.online = online; |  | ||||||
|   this.messageType = messageType || 'outgoing'; |  | ||||||
|   this.autoSession = autoSession || false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| OutgoingMessage.prototype = { |  | ||||||
|   constructor: OutgoingMessage, |  | ||||||
|   numberCompleted() { |  | ||||||
|     this.numbersCompleted += 1; |  | ||||||
|     if (this.numbersCompleted >= this.numbers.length) { |  | ||||||
|       this.callback({ |  | ||||||
|         successfulNumbers: this.successfulNumbers, |  | ||||||
|         failoverNumbers: this.failoverNumbers, |  | ||||||
|         errors: this.errors, |  | ||||||
|         unidentifiedDeliveries: this.unidentifiedDeliveries, |  | ||||||
|         messageType: this.messageType, |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   registerError(number, reason, error) { |  | ||||||
|     if (!error || (error.name === 'HTTPError' && error.code !== 404)) { |  | ||||||
|       // eslint-disable-next-line no-param-reassign
 |  | ||||||
|       error = new textsecure.OutgoingMessageError( |  | ||||||
|         number, |  | ||||||
|         this.message.toArrayBuffer(), |  | ||||||
|         this.timestamp, |  | ||||||
|         error |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // eslint-disable-next-line no-param-reassign
 |  | ||||||
|     error.number = number; |  | ||||||
|     // eslint-disable-next-line no-param-reassign
 |  | ||||||
|     error.reason = reason; |  | ||||||
|     this.errors[this.errors.length] = error; |  | ||||||
|     this.numberCompleted(); |  | ||||||
|   }, |  | ||||||
|   reloadDevicesAndSend(primaryPubKey, multiDevice = true) { |  | ||||||
|     const ourNumber = textsecure.storage.user.getNumber(); |  | ||||||
| 
 |  | ||||||
|     if (!multiDevice) { |  | ||||||
|       if (primaryPubKey === ourNumber) { |  | ||||||
|         return Promise.resolve(); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return this.doSendMessage(primaryPubKey, [primaryPubKey]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return ( |  | ||||||
|       window.libsession.Protocols.MultiDeviceProtocol.getAllDevices( |  | ||||||
|         primaryPubKey |  | ||||||
|       ) |  | ||||||
|         // Don't send to ourselves
 |  | ||||||
|         .then(devicesPubKeys => |  | ||||||
|           devicesPubKeys.filter(pubKey => pubKey.key !== ourNumber) |  | ||||||
|         ) |  | ||||||
|         .then(devicesPubKeys => { |  | ||||||
|           if (devicesPubKeys.length === 0) { |  | ||||||
|             // No need to start the sending of message without a recipient
 |  | ||||||
|             return Promise.resolve(); |  | ||||||
|           } |  | ||||||
|           return this.doSendMessage(primaryPubKey, devicesPubKeys); |  | ||||||
|         }) |  | ||||||
|     ); |  | ||||||
|   }, |  | ||||||
| 
 |  | ||||||
|   getKeysForNumber(number, updateDevices) { |  | ||||||
|     const handleResult = response => |  | ||||||
|       Promise.all( |  | ||||||
|         response.devices.map(device => { |  | ||||||
|           // eslint-disable-next-line no-param-reassign
 |  | ||||||
|           device.identityKey = response.identityKey; |  | ||||||
|           if ( |  | ||||||
|             updateDevices === undefined || |  | ||||||
|             updateDevices.indexOf(device.deviceId) > -1 |  | ||||||
|           ) { |  | ||||||
|             const address = new libsignal.SignalProtocolAddress( |  | ||||||
|               number, |  | ||||||
|               device.deviceId |  | ||||||
|             ); |  | ||||||
|             const builder = new libsignal.SessionBuilder( |  | ||||||
|               textsecure.storage.protocol, |  | ||||||
|               address |  | ||||||
|             ); |  | ||||||
|             if (device.registrationId === 0) { |  | ||||||
|               window.log.info('device registrationId 0!'); |  | ||||||
|             } |  | ||||||
|             return builder |  | ||||||
|               .processPreKey(device) |  | ||||||
|               .then(async () => { |  | ||||||
|                 // TODO: only remove the keys that were used above!
 |  | ||||||
|                 await libloki.storage.removeContactPreKeyBundle(number); |  | ||||||
|                 return true; |  | ||||||
|               }) |  | ||||||
|               .catch(error => { |  | ||||||
|                 if (error.message === 'Identity key changed') { |  | ||||||
|                   // eslint-disable-next-line no-param-reassign
 |  | ||||||
|                   error.timestamp = this.timestamp; |  | ||||||
|                   // eslint-disable-next-line no-param-reassign
 |  | ||||||
|                   error.originalMessage = this.message.toArrayBuffer(); |  | ||||||
|                   // eslint-disable-next-line no-param-reassign
 |  | ||||||
|                   error.identityKey = device.identityKey; |  | ||||||
|                 } |  | ||||||
|                 throw error; |  | ||||||
|               }); |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           return false; |  | ||||||
|         }) |  | ||||||
|       ); |  | ||||||
|     let promise = Promise.resolve(true); |  | ||||||
|     updateDevices.forEach(device => { |  | ||||||
|       promise = promise.then(() => |  | ||||||
|         Promise.all([ |  | ||||||
|           textsecure.storage.protocol.loadContactPreKey(number), |  | ||||||
|           textsecure.storage.protocol.loadContactSignedPreKey(number), |  | ||||||
|         ]) |  | ||||||
|           .then(keys => { |  | ||||||
|             const [preKey, signedPreKey] = keys; |  | ||||||
|             if (preKey === undefined || signedPreKey === undefined) { |  | ||||||
|               return false; |  | ||||||
|             } |  | ||||||
|             const identityKey = StringView.hexToArrayBuffer(number); |  | ||||||
|             return handleResult({ |  | ||||||
|               identityKey, |  | ||||||
|               devices: [ |  | ||||||
|                 { deviceId: device, preKey, signedPreKey, registrationId: 0 }, |  | ||||||
|               ], |  | ||||||
|             }).then(results => results.every(value => value === true)); |  | ||||||
|           }) |  | ||||||
|           .catch(e => { |  | ||||||
|             throw e; |  | ||||||
|           }) |  | ||||||
|       ); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     return promise; |  | ||||||
|   }, |  | ||||||
| 
 |  | ||||||
|   // Default ttl to 24 hours if no value provided
 |  | ||||||
|   async transmitMessage(number, data, timestamp, ttl = 24 * 60 * 60 * 1000) { |  | ||||||
|     const pubKey = number; |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       // TODO: Make NUM_CONCURRENT_CONNECTIONS a global constant
 |  | ||||||
|       const options = { |  | ||||||
|         numConnections: NUM_SEND_CONNECTIONS, |  | ||||||
|       }; |  | ||||||
|       options.isPublic = this.isPublic; |  | ||||||
|       if (this.isPublic) { |  | ||||||
|         options.publicSendData = this.publicSendData; |  | ||||||
|       } |  | ||||||
|       await lokiMessageAPI.sendMessage(pubKey, data, timestamp, ttl, options); |  | ||||||
|     } catch (e) { |  | ||||||
|       if (e.name === 'HTTPError' && e.code !== 409 && e.code !== 410) { |  | ||||||
|         throw new textsecure.SendMessageNetworkError(number, '', e, timestamp); |  | ||||||
|       } else if (e.name === 'TimedOutError') { |  | ||||||
|         throw new textsecure.PoWError(number, e); |  | ||||||
|       } |  | ||||||
|       throw e; |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
| 
 |  | ||||||
|   async buildMessage(devicePubKey) { |  | ||||||
|     const updatedDevices = await getStaleDeviceIdsForNumber(devicePubKey); |  | ||||||
|     const keysFound = await this.getKeysForNumber(devicePubKey, updatedDevices); |  | ||||||
| 
 |  | ||||||
|     // Check if we need to attach the preKeys
 |  | ||||||
|     const enableFallBackEncryption = !keysFound; |  | ||||||
|     const flags = this.message.dataMessage |  | ||||||
|       ? this.message.dataMessage.get_flags() |  | ||||||
|       : null; |  | ||||||
|     // END_SESSION means Session reset message
 |  | ||||||
|     const isEndSession = |  | ||||||
|       flags === textsecure.protobuf.DataMessage.Flags.END_SESSION; |  | ||||||
|     const isSessionRequest = false; |  | ||||||
| 
 |  | ||||||
|     if (enableFallBackEncryption || isEndSession) { |  | ||||||
|       // Encrypt them with the fallback
 |  | ||||||
|       const pkb = await libloki.storage.getPreKeyBundleForContact(devicePubKey); |  | ||||||
|       this.message.preKeyBundleMessage = new textsecure.protobuf.PreKeyBundleMessage( |  | ||||||
|         pkb |  | ||||||
|       ); |  | ||||||
|       window.log.info('attaching prekeys to outgoing message'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const messageBuffer = this.message.toArrayBuffer(); |  | ||||||
|     const logDetails = { |  | ||||||
|       message: this.message, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     const ourPubKey = textsecure.storage.user.getNumber(); |  | ||||||
|     const ourPrimaryPubkey = window.storage.get('primaryDevicePubKey'); |  | ||||||
|     const secondaryPubKeys = |  | ||||||
|       (await window.libsession.Protocols.MultiDeviceProtocol.getSecondaryDevices( |  | ||||||
|         ourPubKey |  | ||||||
|       )) || []; |  | ||||||
|     let aliasedPubkey = devicePubKey; |  | ||||||
|     if (devicePubKey === ourPubKey) { |  | ||||||
|       aliasedPubkey = 'OUR_PUBKEY'; // should not happen
 |  | ||||||
|     } else if (devicePubKey === ourPrimaryPubkey) { |  | ||||||
|       aliasedPubkey = 'OUR_PRIMARY_PUBKEY'; |  | ||||||
|     } else if (secondaryPubKeys.some(device => device.key === devicePubKey)) { |  | ||||||
|       aliasedPubkey = 'OUR SECONDARY PUBKEY'; |  | ||||||
|     } |  | ||||||
|     libloki.api.debug.logSessionMessageSending( |  | ||||||
|       `Sending :${this.messageType} message to ${aliasedPubkey} details:`, |  | ||||||
|       logDetails |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     const plaintext = _getPlaintext(messageBuffer); |  | ||||||
| 
 |  | ||||||
|     // No limit on message keys if we're communicating with our other devices
 |  | ||||||
|     // FIXME options not used at all; if (ourPubkey === number) {
 |  | ||||||
|     //   options.messageKeysLimit = false;
 |  | ||||||
|     // }
 |  | ||||||
|     const ttl = getTTLForType(this.messageType); |  | ||||||
|     const ourKey = textsecure.storage.user.getNumber(); |  | ||||||
| 
 |  | ||||||
|     return { |  | ||||||
|       ttl, |  | ||||||
|       ourKey, |  | ||||||
|       sourceDevice: 1, |  | ||||||
|       plaintext, |  | ||||||
|       pubKey: devicePubKey, |  | ||||||
|       isSessionRequest, |  | ||||||
|       enableFallBackEncryption, |  | ||||||
|     }; |  | ||||||
|   }, |  | ||||||
| 
 |  | ||||||
|   async encryptMessage(clearMessage) { |  | ||||||
|     if (clearMessage === null) { |  | ||||||
|       window.log.warn( |  | ||||||
|         'clearMessage is null on encryptMessage... Returning null' |  | ||||||
|       ); |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
|     const { |  | ||||||
|       ttl, |  | ||||||
|       ourKey, |  | ||||||
|       sourceDevice, |  | ||||||
|       plaintext, |  | ||||||
|       pubKey, |  | ||||||
|       isSessionRequest, |  | ||||||
|       enableFallBackEncryption, |  | ||||||
|     } = clearMessage; |  | ||||||
|     // Session doesn't use the deviceId scheme, it's always 1.
 |  | ||||||
|     // Instead, there are multiple device public keys.
 |  | ||||||
|     const deviceId = 1; |  | ||||||
| 
 |  | ||||||
|     const address = new libsignal.SignalProtocolAddress(pubKey, deviceId); |  | ||||||
| 
 |  | ||||||
|     let sessionCipher; |  | ||||||
| 
 |  | ||||||
|     if (enableFallBackEncryption) { |  | ||||||
|       sessionCipher = new libloki.crypto.FallBackSessionCipher(address); |  | ||||||
|     } else { |  | ||||||
|       sessionCipher = new libsignal.SessionCipher( |  | ||||||
|         textsecure.storage.protocol, |  | ||||||
|         address |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const innerCiphertext = await sessionCipher.encrypt(plaintext); |  | ||||||
| 
 |  | ||||||
|     const secretSessionCipher = new window.Signal.Metadata.SecretSessionCipher( |  | ||||||
|       textsecure.storage.protocol |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     const senderCert = new textsecure.protobuf.SenderCertificate(); |  | ||||||
| 
 |  | ||||||
|     senderCert.sender = ourKey; |  | ||||||
|     senderCert.senderDevice = deviceId; |  | ||||||
| 
 |  | ||||||
|     const ciphertext = await secretSessionCipher.encrypt( |  | ||||||
|       address.getName(), |  | ||||||
|       senderCert, |  | ||||||
|       innerCiphertext |  | ||||||
|     ); |  | ||||||
|     const type = textsecure.protobuf.Envelope.Type.UNIDENTIFIED_SENDER; |  | ||||||
|     const content = window.Signal.Crypto.arrayBufferToBase64(ciphertext); |  | ||||||
| 
 |  | ||||||
|     return { |  | ||||||
|       type, |  | ||||||
|       ttl, |  | ||||||
|       ourKey, |  | ||||||
|       sourceDevice, |  | ||||||
|       content, |  | ||||||
|       pubKey, |  | ||||||
|       isSessionRequest, |  | ||||||
|     }; |  | ||||||
|   }, |  | ||||||
|   // Send a message to a public group
 |  | ||||||
|   async sendPublicMessage(number) { |  | ||||||
|     await this.transmitMessage( |  | ||||||
|       number, |  | ||||||
|       this.message.dataMessage, |  | ||||||
|       this.timestamp, |  | ||||||
|       0 // ttl
 |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     this.successfulNumbers[this.successfulNumbers.length] = number; |  | ||||||
|     this.numberCompleted(); |  | ||||||
|   }, |  | ||||||
|   // Send a message to a private group member or a session chat (one to one)
 |  | ||||||
|   async sendSessionMessage(outgoingObjects) { |  | ||||||
|     // TODO: handle multiple devices/messages per transmit
 |  | ||||||
|     const promises = outgoingObjects.map(async outgoingObject => { |  | ||||||
|       if (!outgoingObject) { |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       const { pubKey: destination, ttl } = outgoingObject; |  | ||||||
| 
 |  | ||||||
|       try { |  | ||||||
|         const socketMessage = wrapInWebsocketMessage( |  | ||||||
|           outgoingObject, |  | ||||||
|           this.timestamp |  | ||||||
|         ); |  | ||||||
|         await this.transmitMessage( |  | ||||||
|           destination, |  | ||||||
|           socketMessage, |  | ||||||
|           this.timestamp, |  | ||||||
|           ttl |  | ||||||
|         ); |  | ||||||
|         this.successfulNumbers.push(destination); |  | ||||||
|       } catch (e) { |  | ||||||
|         e.number = destination; |  | ||||||
|         this.errors.push(e); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     await Promise.all(promises); |  | ||||||
| 
 |  | ||||||
|     this.numbersCompleted += this.successfulNumbers.length; |  | ||||||
|     this.numberCompleted(); |  | ||||||
|   }, |  | ||||||
|   async buildAndEncrypt(devicePubKey) { |  | ||||||
|     const clearMessage = await this.buildMessage(devicePubKey); |  | ||||||
|     return this.encryptMessage(clearMessage); |  | ||||||
|   }, |  | ||||||
|   // eslint-disable-next-line no-unused-vars
 |  | ||||||
|   async doSendMessage(primaryPubKey, devicesPubKeys) { |  | ||||||
|     if (this.isPublic) { |  | ||||||
|       await this.sendPublicMessage(primaryPubKey); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     this.numbers = devicesPubKeys; |  | ||||||
| 
 |  | ||||||
|     if (this.isMediumGroup) { |  | ||||||
|       await this.sendMediumGroupMessage(primaryPubKey); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const outgoingObjects = await Promise.all( |  | ||||||
|       devicesPubKeys.map(pk => this.buildAndEncrypt(pk, primaryPubKey)) |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     this.sendSessionMessage(outgoingObjects); |  | ||||||
|   }, |  | ||||||
| 
 |  | ||||||
|   sendToNumber(number, multiDevice = true) { |  | ||||||
|     return this.reloadDevicesAndSend(number, multiDevice).catch(error => { |  | ||||||
|       if (error.message === 'Identity key changed') { |  | ||||||
|         // eslint-disable-next-line no-param-reassign
 |  | ||||||
|         error = new textsecure.OutgoingIdentityKeyError( |  | ||||||
|           number, |  | ||||||
|           error.originalMessage, |  | ||||||
|           error.timestamp, |  | ||||||
|           error.identityKey |  | ||||||
|         ); |  | ||||||
|         this.registerError(number, 'Identity key changed', error); |  | ||||||
|       } else { |  | ||||||
|         this.registerError( |  | ||||||
|           number, |  | ||||||
|           `Failed to retrieve new device keys for number ${number}`, |  | ||||||
|           error |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| window.textsecure = window.textsecure || {}; |  | ||||||
| window.textsecure.OutgoingMessage = OutgoingMessage; |  | ||||||
					Loading…
					
					
				
		Reference in New Issue