|  |  |  | @ -1,9 +1,21 @@ | 
		
	
		
			
				|  |  |  |  | import { createOrUpdateItem, getItemById } from '../../../ts/data/data'; | 
		
	
		
			
				|  |  |  |  | import { | 
		
	
		
			
				|  |  |  |  |   createOrUpdateItem, | 
		
	
		
			
				|  |  |  |  |   getItemById, | 
		
	
		
			
				|  |  |  |  |   getLatestClosedGroupEncryptionKeyPair, | 
		
	
		
			
				|  |  |  |  | } from '../../../ts/data/data'; | 
		
	
		
			
				|  |  |  |  | import { getMessageQueue } from '..'; | 
		
	
		
			
				|  |  |  |  | import { ConversationController } from '../conversations'; | 
		
	
		
			
				|  |  |  |  | import { getCurrentConfigurationMessage } from './Messages'; | 
		
	
		
			
				|  |  |  |  | import { RawMessage } from '../types'; | 
		
	
		
			
				|  |  |  |  | import { DAYS } from './Number'; | 
		
	
		
			
				|  |  |  |  | import uuid from 'uuid'; | 
		
	
		
			
				|  |  |  |  | import { UserUtils } from '.'; | 
		
	
		
			
				|  |  |  |  | import { ECKeyPair } from '../../receiver/keypairs'; | 
		
	
		
			
				|  |  |  |  | import { | 
		
	
		
			
				|  |  |  |  |   ConfigurationMessage, | 
		
	
		
			
				|  |  |  |  |   ConfigurationMessageClosedGroup, | 
		
	
		
			
				|  |  |  |  |   ConfigurationMessageContact, | 
		
	
		
			
				|  |  |  |  | } from '../messages/outgoing/content/ConfigurationMessage'; | 
		
	
		
			
				|  |  |  |  | import { ConversationModel } from '../../models/conversation'; | 
		
	
		
			
				|  |  |  |  | import { fromHexToArray } from './String'; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const ITEM_ID_LAST_SYNC_TIMESTAMP = 'lastSyncedTimestamp'; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -42,37 +54,130 @@ export const syncConfigurationIfNeeded = async () => { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | export const forceSyncConfigurationNowIfNeeded = async ( | 
		
	
		
			
				|  |  |  |  |   waitForMessageSent = false | 
		
	
		
			
				|  |  |  |  | ) => { | 
		
	
		
			
				|  |  |  |  |   const allConvos = ConversationController.getInstance().getConversations(); | 
		
	
		
			
				|  |  |  |  |   const configMessage = await getCurrentConfigurationMessage(allConvos); | 
		
	
		
			
				|  |  |  |  | ) => | 
		
	
		
			
				|  |  |  |  |   new Promise(resolve => { | 
		
	
		
			
				|  |  |  |  |     const allConvos = ConversationController.getInstance().getConversations(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   async function waitForMessageSentEvent(message: RawMessage) { | 
		
	
		
			
				|  |  |  |  |     return new Promise(resolve => { | 
		
	
		
			
				|  |  |  |  |       if (message.identifier === configMessage.identifier) { | 
		
	
		
			
				|  |  |  |  |         // might have fail in fact
 | 
		
	
		
			
				|  |  |  |  |         debugger; | 
		
	
		
			
				|  |  |  |  |         resolve(true); | 
		
	
		
			
				|  |  |  |  |     void getCurrentConfigurationMessage(allConvos).then(configMessage => { | 
		
	
		
			
				|  |  |  |  |       // console.warn('forceSyncConfigurationNowIfNeeded with', configMessage);
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       try { | 
		
	
		
			
				|  |  |  |  |         // this just adds the message to the sending queue.
 | 
		
	
		
			
				|  |  |  |  |         // if waitForMessageSent is set, we need to effectively wait until then
 | 
		
	
		
			
				|  |  |  |  |         // tslint:disable-next-line: no-void-expression
 | 
		
	
		
			
				|  |  |  |  |         const callback = waitForMessageSent | 
		
	
		
			
				|  |  |  |  |           ? () => { | 
		
	
		
			
				|  |  |  |  |               resolve(true); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |           : undefined; | 
		
	
		
			
				|  |  |  |  |         void getMessageQueue().sendSyncMessage(configMessage, callback as any); | 
		
	
		
			
				|  |  |  |  |         // either we resolve from the callback if we need to wait for it,
 | 
		
	
		
			
				|  |  |  |  |         // or we don't want to wait, we resolve it here.
 | 
		
	
		
			
				|  |  |  |  |         if (!waitForMessageSent) { | 
		
	
		
			
				|  |  |  |  |           resolve(true); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |       } catch (e) { | 
		
	
		
			
				|  |  |  |  |         window.log.warn( | 
		
	
		
			
				|  |  |  |  |           'Caught an error while sending our ConfigurationMessage:', | 
		
	
		
			
				|  |  |  |  |           e | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |         resolve(false); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   }); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   try { | 
		
	
		
			
				|  |  |  |  |     // passing the callback like that
 | 
		
	
		
			
				|  |  |  |  |     if (waitForMessageSent) { | 
		
	
		
			
				|  |  |  |  |       await getMessageQueue().sendSyncMessage( | 
		
	
		
			
				|  |  |  |  |         configMessage, | 
		
	
		
			
				|  |  |  |  |         waitForMessageSentEvent as any | 
		
	
		
			
				|  |  |  |  | export const getCurrentConfigurationMessage = async ( | 
		
	
		
			
				|  |  |  |  |   convos: Array<ConversationModel> | 
		
	
		
			
				|  |  |  |  | ) => { | 
		
	
		
			
				|  |  |  |  |   const ourPubKey = UserUtils.getOurPubKeyStrFromCache(); | 
		
	
		
			
				|  |  |  |  |   const ourConvo = convos.find(convo => convo.id === ourPubKey); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Filter open groups
 | 
		
	
		
			
				|  |  |  |  |   const openGroupsIds = convos | 
		
	
		
			
				|  |  |  |  |     .filter(c => !!c.get('active_at') && c.isPublic() && !c.get('left')) | 
		
	
		
			
				|  |  |  |  |     .map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array< | 
		
	
		
			
				|  |  |  |  |     string | 
		
	
		
			
				|  |  |  |  |   >; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Filter Closed/Medium groups
 | 
		
	
		
			
				|  |  |  |  |   const closedGroupModels = convos.filter( | 
		
	
		
			
				|  |  |  |  |     c => | 
		
	
		
			
				|  |  |  |  |       !!c.get('active_at') && | 
		
	
		
			
				|  |  |  |  |       c.isMediumGroup() && | 
		
	
		
			
				|  |  |  |  |       c.get('members').includes(ourPubKey) && | 
		
	
		
			
				|  |  |  |  |       !c.get('left') && | 
		
	
		
			
				|  |  |  |  |       !c.get('isKickedFromGroup') && | 
		
	
		
			
				|  |  |  |  |       !c.isBlocked() && | 
		
	
		
			
				|  |  |  |  |       c.get('name') | 
		
	
		
			
				|  |  |  |  |   ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   const closedGroups = await Promise.all( | 
		
	
		
			
				|  |  |  |  |     closedGroupModels.map(async c => { | 
		
	
		
			
				|  |  |  |  |       const groupPubKey = c.get('id'); | 
		
	
		
			
				|  |  |  |  |       const fetchEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair( | 
		
	
		
			
				|  |  |  |  |         groupPubKey | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |       return waitForMessageSentEvent; | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       await getMessageQueue().sendSyncMessage(configMessage); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } catch (e) { | 
		
	
		
			
				|  |  |  |  |     window.log.warn( | 
		
	
		
			
				|  |  |  |  |       'Caught an error while sending our ConfigurationMessage:', | 
		
	
		
			
				|  |  |  |  |       e | 
		
	
		
			
				|  |  |  |  |       if (!fetchEncryptionKeyPair) { | 
		
	
		
			
				|  |  |  |  |         return null; | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       return new ConfigurationMessageClosedGroup({ | 
		
	
		
			
				|  |  |  |  |         publicKey: groupPubKey, | 
		
	
		
			
				|  |  |  |  |         name: c.get('name') || '', | 
		
	
		
			
				|  |  |  |  |         members: c.get('members') || [], | 
		
	
		
			
				|  |  |  |  |         admins: c.get('groupAdmins') || [], | 
		
	
		
			
				|  |  |  |  |         encryptionKeyPair: ECKeyPair.fromHexKeyPair(fetchEncryptionKeyPair), | 
		
	
		
			
				|  |  |  |  |       }); | 
		
	
		
			
				|  |  |  |  |     }) | 
		
	
		
			
				|  |  |  |  |   ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   const onlyValidClosedGroup = closedGroups.filter(m => m !== null) as Array< | 
		
	
		
			
				|  |  |  |  |     ConfigurationMessageClosedGroup | 
		
	
		
			
				|  |  |  |  |   >; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Filter contacts
 | 
		
	
		
			
				|  |  |  |  |   const contactsModels = convos.filter( | 
		
	
		
			
				|  |  |  |  |     c => | 
		
	
		
			
				|  |  |  |  |       !!c.get('active_at') && | 
		
	
		
			
				|  |  |  |  |       c.getLokiProfile()?.displayName && | 
		
	
		
			
				|  |  |  |  |       c.isPrivate() && | 
		
	
		
			
				|  |  |  |  |       !c.isBlocked() | 
		
	
		
			
				|  |  |  |  |   ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   const contacts = contactsModels.map(c => { | 
		
	
		
			
				|  |  |  |  |     const profileKeyForContact = c.get('profileKey') | 
		
	
		
			
				|  |  |  |  |       ? fromHexToArray(c.get('profileKey') as string) | 
		
	
		
			
				|  |  |  |  |       : undefined; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return new ConfigurationMessageContact({ | 
		
	
		
			
				|  |  |  |  |       publicKey: c.id, | 
		
	
		
			
				|  |  |  |  |       displayName: c.getLokiProfile()?.displayName, | 
		
	
		
			
				|  |  |  |  |       profilePictureURL: c.get('avatarPointer'), | 
		
	
		
			
				|  |  |  |  |       profileKey: profileKeyForContact, | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  |   }); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if (!ourConvo) { | 
		
	
		
			
				|  |  |  |  |     window.log.error( | 
		
	
		
			
				|  |  |  |  |       'Could not find our convo while building a configuration message.' | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   const profileKeyFromStorage = window.storage.get('profileKey'); | 
		
	
		
			
				|  |  |  |  |   const profileKey = profileKeyFromStorage | 
		
	
		
			
				|  |  |  |  |     ? new Uint8Array(profileKeyFromStorage) | 
		
	
		
			
				|  |  |  |  |     : undefined; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   const profilePicture = ourConvo?.get('avatarPointer') || undefined; | 
		
	
		
			
				|  |  |  |  |   const displayName = ourConvo?.getLokiProfile()?.displayName || undefined; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return Promise.resolve(); | 
		
	
		
			
				|  |  |  |  |   return new ConfigurationMessage({ | 
		
	
		
			
				|  |  |  |  |     identifier: uuid(), | 
		
	
		
			
				|  |  |  |  |     timestamp: Date.now(), | 
		
	
		
			
				|  |  |  |  |     activeOpenGroups: openGroupsIds, | 
		
	
		
			
				|  |  |  |  |     activeClosedGroups: onlyValidClosedGroup, | 
		
	
		
			
				|  |  |  |  |     displayName, | 
		
	
		
			
				|  |  |  |  |     profilePicture, | 
		
	
		
			
				|  |  |  |  |     profileKey, | 
		
	
		
			
				|  |  |  |  |     contacts, | 
		
	
		
			
				|  |  |  |  |   }); | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
	
		
			
				
					|  |  |  | 
 |