diff --git a/js/background.js b/js/background.js index 9b6aa63d4d..85c8d77818 100644 --- a/js/background.js +++ b/js/background.js @@ -539,6 +539,13 @@ window.Events.setThemeSetting(newThemeSetting); } + if ( + window.isBeforeVersion(lastVersion, 'v1.35.0-beta.11') && + window.isAfterVersion(lastVersion, 'v1.35.0-beta.1') + ) { + await window.Signal.Util.eraseAllStorageServiceState(); + } + // This one should always be last - it could restart the app if (window.isBeforeVersion(lastVersion, 'v1.15.0-beta.5')) { await window.Signal.Logs.deleteAll(); diff --git a/js/models/conversations.js b/js/models/conversations.js index b864154982..00fdbee59e 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -614,8 +614,9 @@ if (response === this.messageRequestEnum.ACCEPT) { this.unblock(); this.enableProfileSharing(); - this.sendProfileKeyUpdate(); + if (!fromSync) { + this.sendProfileKeyUpdate(); // Locally accepted await this.handleReadAndDownloadAttachments(); } @@ -945,14 +946,14 @@ return true; } - const fromContact = this.getIsAddedByContact(); + const isFromOrAddedByTrustedContact = this.isFromOrAddedByTrustedContact(); const hasSentMessages = this.getSentMessageCount() > 0; const hasMessagesBeforeMessageRequests = (this.get('messageCountBeforeMessageRequests') || 0) > 0; const hasNoMessages = (this.get('messageCount') || 0) === 0; return ( - fromContact || + isFromOrAddedByTrustedContact || hasSentMessages || hasMessagesBeforeMessageRequests || // an empty conversation is the scenario where we need to rely on @@ -1183,10 +1184,17 @@ return [this.getSendTarget()]; } const me = ConversationController.getOurConversationId(); - return _.without(this.get('members'), me).map(memberId => { - const c = ConversationController.get(memberId); - return c.getSendTarget(); - }); + + // The list of members might not always be conversationIds for old groups. + return _.compact( + this.get('members').map(memberId => { + const c = ConversationController.get(memberId); + if (c.id === me) { + return null; + } + return c.getSendTarget(); + }) + ); }, async getQuoteAttachment(attachments, preview, sticker) { @@ -1793,17 +1801,12 @@ }; }, - getIsContact() { + // Is this someone who is a contact, or are we sharing our profile with them? + // Or is the person who added us to this group a contact or are we sharing profile + // with them? + isFromOrAddedByTrustedContact() { if (this.isPrivate()) { - return Boolean(this.get('name')); - } - - return false; - }, - - getIsAddedByContact() { - if (this.isPrivate()) { - return this.getIsContact(); + return Boolean(this.get('name')) || this.get('profileSharing'); } const addedBy = this.get('addedBy'); @@ -1816,7 +1819,7 @@ return false; } - return conv.getIsContact(); + return Boolean(conv.get('name')) || conv.get('profileSharing'); }, async updateLastMessage() { diff --git a/preload.js b/preload.js index 98e9b4bbfd..1c7f3d7c1e 100644 --- a/preload.js +++ b/preload.js @@ -63,6 +63,17 @@ try { return true; } }; + window.isAfterVersion = (toCheck, baseVersion) => { + try { + return semver.gt(toCheck, baseVersion); + } catch (error) { + window.log.error( + `isBeforeVersion error: toCheck: ${toCheck}, baseVersion: ${baseVersion}`, + error && error.stack ? error.stack : error + ); + return true; + } + }; const ipc = electron.ipcRenderer; const localeMessages = ipc.sendSync('locale-data'); diff --git a/ts/shims/storage.ts b/ts/shims/storage.ts index 7b35f21995..1e72f52bd1 100644 --- a/ts/shims/storage.ts +++ b/ts/shims/storage.ts @@ -2,6 +2,6 @@ export function put(key: string, value: any) { window.storage.put(key, value); } -export function remove(key: string) { - window.storage.remove(key); +export async function remove(key: string) { + await window.storage.remove(key); } diff --git a/ts/sql/Client.ts b/ts/sql/Client.ts index 6e16c5b528..f9be5258a2 100644 --- a/ts/sql/Client.ts +++ b/ts/sql/Client.ts @@ -129,6 +129,7 @@ const dataInterface: ClientInterface = { updateConversations, removeConversation, + eraseStorageIdFromConversations, getAllConversations, getAllConversationIds, getAllPrivateConversations, @@ -770,6 +771,10 @@ async function _removeConversations(ids: Array) { await channels.removeConversation(ids); } +async function eraseStorageIdFromConversations() { + await channels.eraseStorageIdFromConversations(); +} + async function getAllConversations({ ConversationCollection, }: { diff --git a/ts/sql/Interface.ts b/ts/sql/Interface.ts index be64a7c708..e028e67324 100644 --- a/ts/sql/Interface.ts +++ b/ts/sql/Interface.ts @@ -67,6 +67,7 @@ export interface DataInterface { removeAllSessions: () => Promise; getAllSessions: () => Promise>; + eraseStorageIdFromConversations: () => Promise; getConversationCount: () => Promise; saveConversation: (data: ConversationType) => Promise; saveConversations: (array: Array) => Promise; diff --git a/ts/sql/Server.ts b/ts/sql/Server.ts index ca7c9902a6..3e4610911f 100644 --- a/ts/sql/Server.ts +++ b/ts/sql/Server.ts @@ -104,6 +104,7 @@ const dataInterface: ServerInterface = { updateConversation, updateConversations, removeConversation, + eraseStorageIdFromConversations, getAllConversations, getAllConversationIds, getAllPrivateConversations, @@ -2240,6 +2241,16 @@ async function getConversationById(id: string) { return jsonToObject(row.json); } +async function eraseStorageIdFromConversations() { + const db = getInstance(); + + await db.run( + `UPDATE conversations SET + json = json_remove(json, '$.storageID'); + ` + ); +} + async function getAllConversations() { const db = getInstance(); const rows = await db.all('SELECT json FROM conversations ORDER BY id ASC;'); diff --git a/ts/state/ducks/items.ts b/ts/state/ducks/items.ts index 6348bff169..11a436f1e2 100644 --- a/ts/state/ducks/items.ts +++ b/ts/state/ducks/items.ts @@ -80,6 +80,7 @@ function putItemExternal(key: string, value: any): ItemPutExternalAction { } function removeItem(key: string): ItemRemoveAction { + // tslint:disable-next-line no-floating-promises storageShim.remove(key); return { diff --git a/ts/util/index.ts b/ts/util/index.ts index 93fc170dab..4aa86ed5f8 100644 --- a/ts/util/index.ts +++ b/ts/util/index.ts @@ -15,7 +15,10 @@ import { isFileDangerous } from './isFileDangerous'; import { makeLookup } from './makeLookup'; import { migrateColor } from './migrateColor'; import { missingCaseError } from './missingCaseError'; -import { runStorageServiceSyncJob } from './storageService'; +import { + eraseAllStorageServiceState, + runStorageServiceSyncJob, +} from './storageService'; import * as zkgroup from './zkgroup'; export { @@ -25,6 +28,7 @@ export { createWaitBatcher, deleteForEveryone, downloadAttachment, + eraseAllStorageServiceState, generateSecurityNumber, getSafetyNumberPlaceholder, GoogleChrome, diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 13dddf54fe..f28d1eb140 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -207,7 +207,7 @@ "rule": "jQuery-wrap(", "path": "js/models/conversations.js", "line": " await wrap(", - "lineNumber": 663, + "lineNumber": 664, "reasonCategory": "falseMatch", "updated": "2020-06-09T20:26:46.515Z" }, diff --git a/ts/util/registration.ts b/ts/util/registration.ts index 07eb8b9832..d529b41016 100644 --- a/ts/util/registration.ts +++ b/ts/util/registration.ts @@ -8,8 +8,8 @@ export function markDone() { window.storage.put('chromiumRegistrationDone', ''); } -export function remove() { - window.storage.remove('chromiumRegistrationDone'); +export async function remove() { + await window.storage.remove('chromiumRegistrationDone'); } export function isDone() { diff --git a/ts/util/storageService.ts b/ts/util/storageService.ts index 5fe33f9cce..e1fc784f66 100644 --- a/ts/util/storageService.ts +++ b/ts/util/storageService.ts @@ -10,6 +10,8 @@ import { deriveStorageItemKey, deriveStorageManifestKey, } from '../Crypto'; +import dataInterface from '../sql/Client'; +const { eraseStorageIdFromConversations, updateConversation } = dataInterface; import { AccountRecordClass, ContactRecordClass, @@ -143,7 +145,7 @@ async function mergeGroupV1Record( applyMessageRequestState(groupV1Record, conversation); - window.Signal.Data.updateConversation(conversation.attributes); + updateConversation(conversation.attributes); window.log.info(`storageService.mergeGroupV1Record: merged ${storageID}`); } @@ -223,7 +225,7 @@ async function mergeContactRecord( ); } - window.Signal.Data.updateConversation(conversation.attributes); + updateConversation(conversation.attributes); window.log.info(`storageService.mergeContactRecord: merged ${storageID}`); } @@ -284,7 +286,7 @@ async function mergeAccountRecord( storageID, }); - window.Signal.Data.updateConversation(conversation.attributes); + updateConversation(conversation.attributes); window.log.info( `storageService.mergeAccountRecord: merged profile ${storageID}` @@ -411,6 +413,12 @@ async function processManifest( } export async function runStorageServiceSyncJob() { + if (!window.storage.get('storageKey')) { + throw new Error('runStorageServiceSyncJob: Cannot start; no storage key!'); + } + + window.log.info('runStorageServiceSyncJob: starting...'); + const localManifestVersion = window.storage.get('manifestVersion') || 0; let manifest; @@ -419,6 +427,7 @@ export async function runStorageServiceSyncJob() { // Guarding against no manifests being returned, everything should be ok if (!manifest) { + window.log.info('runStorageServiceSyncJob: no manifest, returning early'); return; } } catch (err) { @@ -442,4 +451,14 @@ export async function runStorageServiceSyncJob() { if (shouldUpdateVersion) { window.storage.put('manifestVersion', version); } + window.log.info('runStorageServiceSyncJob: complete'); +} + +// Note: this function is meant to be called before ConversationController is hydrated. +// It goes directly to the database, so in-memory conversations will be out of date. +export async function eraseAllStorageServiceState() { + window.log.info('eraseAllStorageServiceState: starting...'); + await window.storage.remove('manifestVersion'); + await eraseStorageIdFromConversations(); + window.log.info('eraseAllStorageServiceState: complete'); } diff --git a/ts/window.d.ts b/ts/window.d.ts index 79c6a5e992..67185e1b53 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -62,7 +62,7 @@ declare global { setBadgeCount: (count: number) => void; storage: { put: (key: string, value: any) => void; - remove: (key: string) => void; + remove: (key: string) => Promise; get: (key: string) => T | undefined; addBlockedNumber: (number: string) => void; isBlocked: (number: string) => boolean;