Keep UI settings on heartbeat expiration

This commit is contained in:
Fedor Indutny 2021-08-30 14:39:57 -07:00 committed by GitHub
parent dcf29078f4
commit 798533a417
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 12 deletions

View file

@ -45,6 +45,7 @@ import {
UnprocessedUpdateType, UnprocessedUpdateType,
} from './textsecure/Types.d'; } from './textsecure/Types.d';
import { getSendOptions } from './util/getSendOptions'; import { getSendOptions } from './util/getSendOptions';
import type { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
const TIMESTAMP_THRESHOLD = 5 * 1000; // 5 seconds const TIMESTAMP_THRESHOLD = 5 * 1000; // 5 seconds
@ -1949,8 +1950,8 @@ export class SignalProtocolStore extends EventsMixin {
await window.ConversationController.load(); await window.ConversationController.load();
} }
async removeAllConfiguration(): Promise<void> { async removeAllConfiguration(mode: RemoveAllConfiguration): Promise<void> {
await window.Signal.Data.removeAllConfiguration(); await window.Signal.Data.removeAllConfiguration(mode);
await this.hydrateCaches(); await this.hydrateCaches();
window.storage.reset(); window.storage.reset();

View file

@ -94,6 +94,7 @@ import { SignalService as Proto } from './protobuf';
import { onRetryRequest, onDecryptionError } from './util/handleRetry'; import { onRetryRequest, onDecryptionError } from './util/handleRetry';
import { themeChanged } from './shims/themeChanged'; import { themeChanged } from './shims/themeChanged';
import { createIPCEvents } from './util/createIPCEvents'; import { createIPCEvents } from './util/createIPCEvents';
import { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000; const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
@ -658,7 +659,7 @@ export async function startApp(): Promise<void> {
window.log.warn( window.log.warn(
`This instance has not been used for 30 days. Last heartbeat: ${lastHeartbeat}. Last startup: ${previousLastStartup}.` `This instance has not been used for 30 days. Last heartbeat: ${lastHeartbeat}. Last startup: ${previousLastStartup}.`
); );
await unlinkAndDisconnect(); await unlinkAndDisconnect(RemoveAllConfiguration.Soft);
} }
// Start heartbeat timer // Start heartbeat timer
@ -3336,7 +3337,9 @@ export async function startApp(): Promise<void> {
return false; return false;
} }
async function unlinkAndDisconnect() { async function unlinkAndDisconnect(
mode: RemoveAllConfiguration
): Promise<void> {
window.Whisper.events.trigger('unauthorized'); window.Whisper.events.trigger('unauthorized');
if (messageReceiver) { if (messageReceiver) {
@ -3369,7 +3372,7 @@ export async function startApp(): Promise<void> {
); );
try { try {
await window.textsecure.storage.protocol.removeAllConfiguration(); await window.textsecure.storage.protocol.removeAllConfiguration(mode);
// This was already done in the database with removeAllConfiguration; this does it // This was already done in the database with removeAllConfiguration; this does it
// for all the conversation models in memory. // for all the conversation models in memory.
@ -3423,7 +3426,7 @@ export async function startApp(): Promise<void> {
error.name === 'HTTPError' && error.name === 'HTTPError' &&
(error.code === 401 || error.code === 403) (error.code === 401 || error.code === 403)
) { ) {
unlinkAndDisconnect(); unlinkAndDisconnect(RemoveAllConfiguration.Full);
return; return;
} }

View file

@ -33,6 +33,7 @@ import { cleanDataForIpc } from './cleanDataForIpc';
import { ReactionType } from '../types/Reactions'; import { ReactionType } from '../types/Reactions';
import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ConversationColorType, CustomColorType } from '../types/Colors';
import type { ProcessGroupCallRingRequestResult } from '../types/Calling'; import type { ProcessGroupCallRingRequestResult } from '../types/Calling';
import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
import { import {
ConversationModelCollectionType, ConversationModelCollectionType,
@ -1527,8 +1528,8 @@ async function removeAll() {
await channels.removeAll(); await channels.removeAll();
} }
async function removeAllConfiguration() { async function removeAllConfiguration(type?: RemoveAllConfiguration) {
await channels.removeAllConfiguration(); await channels.removeAllConfiguration(type);
} }
async function cleanupOrphanedAttachments() { async function cleanupOrphanedAttachments() {

View file

@ -19,6 +19,7 @@ import type { ProcessGroupCallRingRequestResult } from '../types/Calling';
import { StorageAccessType } from '../types/Storage.d'; import { StorageAccessType } from '../types/Storage.d';
import type { AttachmentType } from '../types/Attachment'; import type { AttachmentType } from '../types/Attachment';
import { BodyRangesType } from '../types/Util'; import { BodyRangesType } from '../types/Util';
import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
export type AttachmentDownloadJobTypeType = export type AttachmentDownloadJobTypeType =
| 'long-message' | 'long-message'
@ -416,7 +417,7 @@ export type DataInterface = {
getRecentEmojis: (limit?: number) => Promise<Array<EmojiType>>; getRecentEmojis: (limit?: number) => Promise<Array<EmojiType>>;
removeAll: () => Promise<void>; removeAll: () => Promise<void>;
removeAllConfiguration: () => Promise<void>; removeAllConfiguration: (type?: RemoveAllConfiguration) => Promise<void>;
getMessagesNeedingUpgrade: ( getMessagesNeedingUpgrade: (
limit: number, limit: number,

View file

@ -32,17 +32,20 @@ import {
import { ReadStatus } from '../messages/MessageReadStatus'; import { ReadStatus } from '../messages/MessageReadStatus';
import { GroupV2MemberType } from '../model-types.d'; import { GroupV2MemberType } from '../model-types.d';
import { ReactionType } from '../types/Reactions'; import { ReactionType } from '../types/Reactions';
import { STORAGE_UI_KEYS } from '../types/StorageUIKeys';
import { StoredJob } from '../jobs/types'; import { StoredJob } from '../jobs/types';
import { assert } from '../util/assert'; import { assert } from '../util/assert';
import { combineNames } from '../util/combineNames'; import { combineNames } from '../util/combineNames';
import { dropNull } from '../util/dropNull'; import { dropNull } from '../util/dropNull';
import { isNormalNumber } from '../util/isNormalNumber'; import { isNormalNumber } from '../util/isNormalNumber';
import { isNotNil } from '../util/isNotNil'; import { isNotNil } from '../util/isNotNil';
import { missingCaseError } from '../util/missingCaseError';
import { parseIntOrThrow } from '../util/parseIntOrThrow'; import { parseIntOrThrow } from '../util/parseIntOrThrow';
import * as durations from '../util/durations'; import * as durations from '../util/durations';
import { formatCountForLogging } from '../logging/formatCountForLogging'; import { formatCountForLogging } from '../logging/formatCountForLogging';
import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ConversationColorType, CustomColorType } from '../types/Colors';
import { ProcessGroupCallRingRequestResult } from '../types/Calling'; import { ProcessGroupCallRingRequestResult } from '../types/Calling';
import { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
import { import {
AllItemsType, AllItemsType,
@ -5427,22 +5430,46 @@ async function removeAll(): Promise<void> {
} }
// Anything that isn't user-visible data // Anything that isn't user-visible data
async function removeAllConfiguration(): Promise<void> { async function removeAllConfiguration(
mode = RemoveAllConfiguration.Full
): Promise<void> {
const db = getInstance(); const db = getInstance();
db.transaction(() => { db.transaction(() => {
db.exec( db.exec(
` `
DELETE FROM identityKeys; DELETE FROM identityKeys;
DELETE FROM items;
DELETE FROM preKeys; DELETE FROM preKeys;
DELETE FROM senderKeys; DELETE FROM senderKeys;
DELETE FROM sessions; DELETE FROM sessions;
DELETE FROM signedPreKeys; DELETE FROM signedPreKeys;
DELETE FROM unprocessed; DELETE FROM unprocessed;
DELETE FROM jobs; DELETE FROM jobs;
` `
); );
if (mode === RemoveAllConfiguration.Full) {
db.exec(
`
DELETE FROM items;
`
);
} else if (mode === RemoveAllConfiguration.Soft) {
const itemIds: ReadonlyArray<string> = db
.prepare<EmptyQuery>('SELECT id FROM items')
.pluck(true)
.all();
const allowedSet = new Set<string>(STORAGE_UI_KEYS);
for (const id of itemIds) {
if (!allowedSet.has(id)) {
removeById('items', id);
}
}
} else {
throw missingCaseError(mode);
}
db.exec( db.exec(
"UPDATE conversations SET json = json_remove(json, '$.senderKeyInfo');" "UPDATE conversations SET json = json_remove(json, '$.senderKeyInfo');"
); );

View file

@ -0,0 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export enum RemoveAllConfiguration {
Full = 'Full',
Soft = 'Soft',
}

View file

@ -30,6 +30,8 @@ export type ThemeSettingType = 'system' | 'light' | 'dark';
export type NotificationSettingType = 'message' | 'name' | 'count' | 'off'; export type NotificationSettingType = 'message' | 'name' | 'count' | 'off';
// This should be in sync with `UI_CONFIGURATION_KEYS` in
// `ts/textsecure/Storage.ts`.
export type StorageAccessType = { export type StorageAccessType = {
'always-relay-calls': boolean; 'always-relay-calls': boolean;
'audio-notification': boolean; 'audio-notification': boolean;

30
ts/types/StorageUIKeys.ts Normal file
View file

@ -0,0 +1,30 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { StorageAccessType } from './Storage.d';
// Configuration keys that only affect UI
export const STORAGE_UI_KEYS: ReadonlyArray<keyof StorageAccessType> = [
'always-relay-calls',
'audio-notification',
'auto-download-update',
'badge-count-muted-conversations',
'call-ringtone-notification',
'call-system-notification',
'hide-menu-bar',
'system-tray-setting',
'incoming-call-notification',
'notification-draw-attention',
'notification-setting',
'spell-check',
'theme-setting',
'defaultConversationColor',
'customColors',
'showStickerPickerHint',
'showStickersIntroduction',
'preferred-video-input-device',
'preferred-audio-input-device',
'preferred-audio-output-device',
'skinTone',
'zoomFactor',
];