diff --git a/protos/SignalStorage.proto b/protos/SignalStorage.proto index 8f282dffc..9fc49d2b8 100644 --- a/protos/SignalStorage.proto +++ b/protos/SignalStorage.proto @@ -93,6 +93,12 @@ message GroupV2Record { } message AccountRecord { + enum PhoneNumberSharingMode { + EVERYBODY = 0; + CONTACTS_ONLY = 1; + NOBODY = 2; + } + message PinnedConversation { message Contact { optional string uuid = 1; @@ -106,16 +112,18 @@ message AccountRecord { } } - optional bytes profileKey = 1; - optional string givenName = 2; - optional string familyName = 3; - optional string avatarUrl = 4; - optional bool noteToSelfArchived = 5; - optional bool readReceipts = 6; - optional bool sealedSenderIndicators = 7; - optional bool typingIndicators = 8; - optional bool proxiedLinkPreviews = 9; - optional bool noteToSelfMarkedUnread = 10; - optional bool linkPreviews = 11; - repeated PinnedConversation pinnedConversations = 14; + optional bytes profileKey = 1; + optional string givenName = 2; + optional string familyName = 3; + optional string avatarUrl = 4; + optional bool noteToSelfArchived = 5; + optional bool readReceipts = 6; + optional bool sealedSenderIndicators = 7; + optional bool typingIndicators = 8; + optional bool proxiedLinkPreviews = 9; + optional bool noteToSelfMarkedUnread = 10; + optional bool linkPreviews = 11; + optional PhoneNumberSharingMode phoneNumberSharingMode = 12; + optional bool notDiscoverableByPhoneNumber = 13; + repeated PinnedConversation pinnedConversations = 14; } diff --git a/ts/services/storageRecordOps.ts b/ts/services/storageRecordOps.ts index e336bfef2..50e760a92 100644 --- a/ts/services/storageRecordOps.ts +++ b/ts/services/storageRecordOps.ts @@ -1,4 +1,4 @@ -// Copyright 2020 Signal Messenger, LLC +// Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { isNumber } from 'lodash'; @@ -22,6 +22,16 @@ import { waitThenMaybeUpdateGroup, waitThenRespondToGroupV2Migration, } from '../groups'; +import { assert } from '../util/assert'; +import { missingCaseError } from '../util/missingCaseError'; +import { + PhoneNumberSharingMode, + parsePhoneNumberSharingMode, +} from '../util/phoneNumberSharingMode'; +import { + PhoneNumberDiscoverability, + parsePhoneNumberDiscoverability, +} from '../util/phoneNumberDiscoverability'; import { ConversationModel } from '../models/conversations'; import { ConversationAttributesTypeType } from '../model-types.d'; @@ -158,6 +168,43 @@ export async function toAccountRecord( window.storage.get('typingIndicators') ); accountRecord.linkPreviews = Boolean(window.storage.get('linkPreviews')); + + const PHONE_NUMBER_SHARING_MODE_ENUM = + window.textsecure.protobuf.AccountRecord.PhoneNumberSharingMode; + const phoneNumberSharingMode = parsePhoneNumberSharingMode( + window.storage.get('phoneNumberSharingMode') + ); + switch (phoneNumberSharingMode) { + case PhoneNumberSharingMode.Everybody: + accountRecord.phoneNumberSharingMode = + PHONE_NUMBER_SHARING_MODE_ENUM.EVERYBODY; + break; + case PhoneNumberSharingMode.ContactsOnly: + accountRecord.phoneNumberSharingMode = + PHONE_NUMBER_SHARING_MODE_ENUM.CONTACTS_ONLY; + break; + case PhoneNumberSharingMode.Nobody: + accountRecord.phoneNumberSharingMode = + PHONE_NUMBER_SHARING_MODE_ENUM.NOBODY; + break; + default: + throw missingCaseError(phoneNumberSharingMode); + } + + const phoneNumberDiscoverability = parsePhoneNumberDiscoverability( + window.storage.get('phoneNumberDiscoverability') + ); + switch (phoneNumberDiscoverability) { + case PhoneNumberDiscoverability.Discoverable: + accountRecord.notDiscoverableByPhoneNumber = false; + break; + case PhoneNumberDiscoverability.NotDiscoverable: + accountRecord.notDiscoverableByPhoneNumber = true; + break; + default: + throw missingCaseError(phoneNumberDiscoverability); + } + const pinnedConversations = window.storage .get>('pinnedConversationIds', []) .map(id => { @@ -655,8 +702,10 @@ export async function mergeAccountRecord( const { avatarUrl, linkPreviews, + notDiscoverableByPhoneNumber, noteToSelfArchived, noteToSelfMarkedUnread, + phoneNumberSharingMode, pinnedConversations: remotelyPinnedConversationClasses, profileKey, readReceipts, @@ -678,6 +727,36 @@ export async function mergeAccountRecord( window.storage.put('linkPreviews', linkPreviews); } + const PHONE_NUMBER_SHARING_MODE_ENUM = + window.textsecure.protobuf.AccountRecord.PhoneNumberSharingMode; + let phoneNumberSharingModeToStore: PhoneNumberSharingMode; + switch (phoneNumberSharingMode) { + case undefined: + case null: + case PHONE_NUMBER_SHARING_MODE_ENUM.EVERYBODY: + phoneNumberSharingModeToStore = PhoneNumberSharingMode.Everybody; + break; + case PHONE_NUMBER_SHARING_MODE_ENUM.CONTACTS_ONLY: + phoneNumberSharingModeToStore = PhoneNumberSharingMode.ContactsOnly; + break; + case PHONE_NUMBER_SHARING_MODE_ENUM.NOBODY: + phoneNumberSharingModeToStore = PhoneNumberSharingMode.Nobody; + break; + default: + assert( + false, + `storageService.mergeAccountRecord: Got an unexpected phone number sharing mode: ${phoneNumberSharingMode}. Falling back to default` + ); + phoneNumberSharingModeToStore = PhoneNumberSharingMode.Everybody; + break; + } + window.storage.put('phoneNumberSharingMode', phoneNumberSharingModeToStore); + + const discoverability = notDiscoverableByPhoneNumber + ? PhoneNumberDiscoverability.NotDiscoverable + : PhoneNumberDiscoverability.Discoverable; + window.storage.put('phoneNumberDiscoverability', discoverability); + if (profileKey) { window.storage.put('profileKey', profileKey.toArrayBuffer()); } diff --git a/ts/textsecure.d.ts b/ts/textsecure.d.ts index 3a846968a..68f2b1475 100644 --- a/ts/textsecure.d.ts +++ b/ts/textsecure.d.ts @@ -1107,8 +1107,16 @@ export declare class PinnedConversationClass { groupMasterKey?: ProtoBinaryType; } +declare enum AccountRecordPhoneNumberSharingMode { + EVERYBODY = 0, + CONTACTS_ONLY = 1, + NOBODY = 2, +} + export declare class AccountRecordClass { + static PhoneNumberSharingMode: typeof AccountRecordPhoneNumberSharingMode; static PinnedConversation: typeof PinnedConversationClass; + static decode: ( data: ArrayBuffer | ByteBufferClass, encoding?: string @@ -1124,6 +1132,8 @@ export declare class AccountRecordClass { sealedSenderIndicators?: boolean | null; typingIndicators?: boolean | null; linkPreviews?: boolean | null; + phoneNumberSharingMode?: AccountRecordPhoneNumberSharingMode; + notDiscoverableByPhoneNumber?: boolean; pinnedConversations?: PinnedConversationClass[]; noteToSelfMarkedUnread?: boolean; diff --git a/ts/util/phoneNumberDiscoverability.ts b/ts/util/phoneNumberDiscoverability.ts new file mode 100644 index 000000000..1a14edd55 --- /dev/null +++ b/ts/util/phoneNumberDiscoverability.ts @@ -0,0 +1,15 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { makeEnumParser } from './enum'; + +// These strings are saved to disk, so be careful when changing them. +export enum PhoneNumberDiscoverability { + Discoverable = 'Discoverable', + NotDiscoverable = 'NotDiscoverable', +} + +export const parsePhoneNumberDiscoverability = makeEnumParser( + PhoneNumberDiscoverability, + PhoneNumberDiscoverability.Discoverable +); diff --git a/ts/util/phoneNumberSharingMode.ts b/ts/util/phoneNumberSharingMode.ts new file mode 100644 index 000000000..eef62b278 --- /dev/null +++ b/ts/util/phoneNumberSharingMode.ts @@ -0,0 +1,16 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { makeEnumParser } from './enum'; + +// These strings are saved to disk, so be careful when changing them. +export enum PhoneNumberSharingMode { + Everybody = 'Everybody', + ContactsOnly = 'ContactsOnly', + Nobody = 'Nobody', +} + +export const parsePhoneNumberSharingMode = makeEnumParser( + PhoneNumberSharingMode, + PhoneNumberSharingMode.Everybody +);