Keep UI settings on heartbeat expiration
This commit is contained in:
parent
dcf29078f4
commit
798533a417
8 changed files with 84 additions and 12 deletions
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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');"
|
||||||
);
|
);
|
||||||
|
|
7
ts/types/RemoveAllConfiguration.ts
Normal file
7
ts/types/RemoveAllConfiguration.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
export enum RemoveAllConfiguration {
|
||||||
|
Full = 'Full',
|
||||||
|
Soft = 'Soft',
|
||||||
|
}
|
2
ts/types/Storage.d.ts
vendored
2
ts/types/Storage.d.ts
vendored
|
@ -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
30
ts/types/StorageUIKeys.ts
Normal 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',
|
||||||
|
];
|
Loading…
Add table
Add a link
Reference in a new issue