| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  | // Copyright 2021 Signal Messenger, LLC
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-only
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | import { isNumber } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2021-07-19 18:10:09 -07:00
										 |  |  | import { CallbackResultType } from '../textsecure/Types.d'; | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | import dataInterface from '../sql/Client'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { insertSentProto } = dataInterface; | 
					
						
							| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-25 15:40:04 -07:00
										 |  |  | export const SEALED_SENDER = { | 
					
						
							| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  |   UNKNOWN: 0, | 
					
						
							|  |  |  |   ENABLED: 1, | 
					
						
							|  |  |  |   DISABLED: 2, | 
					
						
							|  |  |  |   UNRESTRICTED: 3, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | export type SendTypesType = | 
					
						
							|  |  |  |   | 'callingMessage' // excluded from send log
 | 
					
						
							|  |  |  |   | 'deleteForEveryone' | 
					
						
							|  |  |  |   | 'deliveryReceipt' | 
					
						
							|  |  |  |   | 'expirationTimerUpdate' | 
					
						
							|  |  |  |   | 'groupChange' | 
					
						
							|  |  |  |   | 'legacyGroupChange' | 
					
						
							|  |  |  |   | 'message' | 
					
						
							|  |  |  |   | 'messageRetry' | 
					
						
							|  |  |  |   | 'nullMessage' // excluded from send log
 | 
					
						
							|  |  |  |   | 'otherSync' | 
					
						
							|  |  |  |   | 'profileKeyUpdate' | 
					
						
							|  |  |  |   | 'reaction' | 
					
						
							|  |  |  |   | 'readReceipt' | 
					
						
							|  |  |  |   | 'readSync' | 
					
						
							|  |  |  |   | 'resendFromLog' // excluded from send log
 | 
					
						
							|  |  |  |   | 'resetSession' | 
					
						
							|  |  |  |   | 'retryRequest' // excluded from send log
 | 
					
						
							|  |  |  |   | 'senderKeyDistributionMessage' | 
					
						
							|  |  |  |   | 'sentSync' | 
					
						
							|  |  |  |   | 'typing' // excluded from send log
 | 
					
						
							|  |  |  |   | 'verificationSync' | 
					
						
							| 
									
										
										
										
											2021-08-12 13:15:55 -05:00
										 |  |  |   | 'viewOnceSync' | 
					
						
							| 
									
										
										
										
											2021-08-17 10:43:26 -05:00
										 |  |  |   | 'viewSync' | 
					
						
							|  |  |  |   | 'viewedReceipt'; | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function shouldSaveProto(sendType: SendTypesType): boolean { | 
					
						
							|  |  |  |   if (sendType === 'callingMessage') { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sendType === 'nullMessage') { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sendType === 'resendFromLog') { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sendType === 'retryRequest') { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sendType === 'typing') { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  | export async function handleMessageSend( | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  |   promise: Promise<CallbackResultType>, | 
					
						
							|  |  |  |   options: { | 
					
						
							|  |  |  |     messageIds: Array<string>; | 
					
						
							|  |  |  |     sendType: SendTypesType; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ): Promise<CallbackResultType> { | 
					
						
							| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  |   try { | 
					
						
							|  |  |  |     const result = await promise; | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     await maybeSaveToSendLog(result, options); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await handleMessageSendResult( | 
					
						
							|  |  |  |       result.failoverIdentifiers, | 
					
						
							|  |  |  |       result.unidentifiedDeliveries | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 18:15:25 -07:00
										 |  |  |     return result; | 
					
						
							|  |  |  |   } catch (err) { | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |       await handleMessageSendResult( | 
					
						
							|  |  |  |         err.failoverIdentifiers, | 
					
						
							|  |  |  |         err.unidentifiedDeliveries | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     throw err; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function handleMessageSendResult( | 
					
						
							|  |  |  |   failoverIdentifiers: Array<string> | undefined, | 
					
						
							|  |  |  |   unidentifiedDeliveries: Array<string> | undefined | 
					
						
							|  |  |  | ): Promise<void> { | 
					
						
							|  |  |  |   await Promise.all( | 
					
						
							|  |  |  |     (failoverIdentifiers || []).map(async identifier => { | 
					
						
							|  |  |  |       const conversation = window.ConversationController.get(identifier); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         conversation && | 
					
						
							|  |  |  |         conversation.get('sealedSender') !== SEALED_SENDER.DISABLED | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         window.log.info( | 
					
						
							|  |  |  |           `Setting sealedSender to DISABLED for conversation ${conversation.idForLogging()}` | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         conversation.set({ | 
					
						
							|  |  |  |           sealedSender: SEALED_SENDER.DISABLED, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         window.Signal.Data.updateConversation(conversation.attributes); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await Promise.all( | 
					
						
							|  |  |  |     (unidentifiedDeliveries || []).map(async identifier => { | 
					
						
							|  |  |  |       const conversation = window.ConversationController.get(identifier); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         conversation && | 
					
						
							|  |  |  |         conversation.get('sealedSender') === SEALED_SENDER.UNKNOWN | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         if (conversation.get('accessKey')) { | 
					
						
							|  |  |  |           window.log.info( | 
					
						
							|  |  |  |             `Setting sealedSender to ENABLED for conversation ${conversation.idForLogging()}` | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |           conversation.set({ | 
					
						
							|  |  |  |             sealedSender: SEALED_SENDER.ENABLED, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           window.log.info( | 
					
						
							|  |  |  |             `Setting sealedSender to UNRESTRICTED for conversation ${conversation.idForLogging()}` | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |           conversation.set({ | 
					
						
							|  |  |  |             sealedSender: SEALED_SENDER.UNRESTRICTED, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         window.Signal.Data.updateConversation(conversation.attributes); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-15 16:48:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | async function maybeSaveToSendLog( | 
					
						
							|  |  |  |   result: CallbackResultType, | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     messageIds, | 
					
						
							|  |  |  |     sendType, | 
					
						
							|  |  |  |   }: { | 
					
						
							|  |  |  |     messageIds: Array<string>; | 
					
						
							|  |  |  |     sendType: SendTypesType; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ): Promise<void> { | 
					
						
							|  |  |  |   const { contentHint, contentProto, recipients, timestamp } = result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!shouldSaveProto(sendType)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!isNumber(contentHint) || !contentProto || !recipients || !timestamp) { | 
					
						
							|  |  |  |     window.log.warn( | 
					
						
							|  |  |  |       `handleMessageSend: Missing necessary information to save to log for ${sendType} message ${timestamp}` | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const identifiers = Object.keys(recipients); | 
					
						
							|  |  |  |   if (identifiers.length === 0) { | 
					
						
							|  |  |  |     window.log.warn( | 
					
						
							|  |  |  |       `handleMessageSend: ${sendType} message ${timestamp} had no recipients` | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If the identifier count is greater than one, we've done the save elsewhere
 | 
					
						
							|  |  |  |   if (identifiers.length > 1) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await insertSentProto( | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       timestamp, | 
					
						
							|  |  |  |       proto: Buffer.from(contentProto), | 
					
						
							|  |  |  |       contentHint, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       messageIds, | 
					
						
							|  |  |  |       recipients, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } |