diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4b0be27e..7ea294858 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -194,7 +194,7 @@ jobs: uses: actions/checkout@v4 with: repository: 'signalapp/Signal-Message-Backup-Tests' - ref: 'a920df75ba02e011f6c56c59c6bb20571162a961' + ref: 'afa66e77fe2b437024ec0914cd14c02c95e7cbed' path: 'backup-integration-tests' - run: xvfb-run --auto-servernum npm run test-electron diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 504c06c8c..0f895c0a7 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -6044,7 +6044,7 @@ third-party/chromium/LICENSE. ``` -## windows-core 0.52.0, windows-sys 0.45.0, windows-sys 0.52.0, windows-sys 0.59.0, windows-targets 0.42.2, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.52.6 +## windows-core 0.52.0, windows-sys 0.45.0, windows-sys 0.52.0, windows-sys 0.59.0, windows-targets 0.42.2, windows-targets 0.48.5, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.48.5, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.48.5, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.48.5, windows_x86_64_msvc 0.52.6 ``` MIT License @@ -6254,7 +6254,7 @@ DEALINGS IN THE SOFTWARE. ``` -## idna 0.5.0, percent-encoding 2.3.1, url 2.5.2 +## idna 1.0.3, percent-encoding 2.3.1, url 2.5.4 ``` Copyright (c) 2013-2022 The rust-url developers @@ -6834,7 +6834,7 @@ DEALINGS IN THE SOFTWARE. ``` -## gimli 0.31.0, heck 0.5.0, unicode-bidi 0.3.15, unicode-normalization 0.1.23 +## gimli 0.31.0, heck 0.5.0 ``` Copyright (c) 2015 The Rust Project Developers @@ -7181,7 +7181,7 @@ THE SOFTWARE. ``` -## futures-channel 0.3.30, futures-core 0.3.30, futures-executor 0.3.30, futures-io 0.3.30, futures-macro 0.3.30, futures-sink 0.3.30, futures-task 0.3.30, futures-util 0.3.30, futures 0.3.30 +## futures-channel 0.3.31, futures-core 0.3.31, futures-executor 0.3.30, futures-io 0.3.31, futures-macro 0.3.31, futures-sink 0.3.31, futures-task 0.3.31, futures-util 0.3.31, futures 0.3.30 ``` Copyright (c) 2016 Alex Crichton @@ -7275,7 +7275,7 @@ DEALINGS IN THE SOFTWARE. ``` -## intmap 2.0.0 +## intmap 3.0.0 ``` Copyright (c) 2016 Jesper Axelsson @@ -7349,7 +7349,7 @@ DEALINGS IN THE SOFTWARE. ``` -## rustls-native-certs 0.7.3, rustls-pemfile 2.1.3, rustls 0.22.4, rustls 0.23.13 +## rustls-native-certs 0.7.3, rustls-pemfile 2.1.3, rustls 0.22.4, rustls 0.23.20 ``` Copyright (c) 2016 Joseph Birr-Pixton @@ -7945,6 +7945,36 @@ DEALINGS IN THE SOFTWARE. ``` +## stable_deref_trait 1.2.0 + +``` +Copyright (c) 2017 Robert Grosse + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +``` + ## foreign-types-macros 0.2.3, foreign-types-shared 0.3.1, foreign-types 0.5.0 ``` @@ -9328,7 +9358,7 @@ SOFTWARE. ``` -## rustls-pki-types 1.8.0 +## rustls-pki-types 1.10.1 ``` Copyright (c) 2023 Dirkjan Ochtman @@ -9496,6 +9526,37 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` +## idna_adapter 1.2.0 + +``` +Copyright (c) The rust-url developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +``` + ## arrayvec 0.7.6 ``` @@ -9527,6 +9588,19 @@ DEALINGS IN THE SOFTWARE. ``` +## synstructure 0.13.1 + +``` +Copyright 2016 Nika Layzell + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` + ## rand 0.8.5, rand_chacha 0.3.1, rand_core 0.6.4 ``` @@ -9604,7 +9678,7 @@ DEALINGS IN THE SOFTWARE. ``` -## encoding_rs 0.8.34 +## encoding_rs 0.8.34, utf16_iter 1.0.5, utf8_iter 1.0.4, write16 1.0.0 ``` Copyright Mozilla Foundation @@ -10121,33 +10195,6 @@ SOFTWARE. ``` -## tinyvec_macros 0.1.1 - -``` -MIT License - -Copyright (c) 2020 Soveu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -``` - ## snow 0.9.6 ``` @@ -10229,7 +10276,7 @@ SOFTWARE. ``` -## rustls-platform-verifier-android 0.1.1, rustls-platform-verifier 0.3.4 +## rustls-platform-verifier-android 0.1.1, rustls-platform-verifier 0.4.0 ``` MIT License @@ -10430,17 +10477,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` -## tinyvec 1.8.0 - -``` -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -``` - ## android_system_properties 0.1.5 ``` @@ -11185,6 +11221,51 @@ SOFTWARE. */ ``` +## icu_collections 1.5.0, icu_locid 1.5.0, icu_locid_transform 1.5.0, icu_locid_transform_data 1.5.0, icu_normalizer 1.5.0, icu_normalizer_data 1.5.0, icu_properties 1.5.1, icu_properties_data 1.5.0, icu_provider 1.5.0, icu_provider_macros 1.5.0, litemap 0.7.4, tinystr 0.7.6, writeable 0.5.5, yoke-derive 0.7.5, yoke 0.7.5, zerofrom-derive 0.1.5, zerofrom 0.1.5, zerovec-derive 0.10.3, zerovec 0.10.4 + +``` +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2023 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +``` + ## unicode-ident 1.0.13 ``` diff --git a/package-lock.json b/package-lock.json index 35f3809b0..f110c2e99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@react-aria/utils": "3.25.3", "@react-spring/web": "9.7.5", "@signalapp/better-sqlite3": "9.0.9", - "@signalapp/libsignal-client": "0.64.1", + "@signalapp/libsignal-client": "0.65.0", "@signalapp/ringrtc": "2.49.2", "@types/fabric": "4.5.3", "backbone": "1.6.0", @@ -6468,10 +6468,11 @@ } }, "node_modules/@signalapp/libsignal-client": { - "version": "0.64.1", - "resolved": "https://registry.npmjs.org/@signalapp/libsignal-client/-/libsignal-client-0.64.1.tgz", - "integrity": "sha512-ex45KXdmPtTW9q4DkF/VM/K0XnuuXzsqFFkanEeUE07kEzjGfx1x9tVhQ5h2+lokVjEVLM1Oq6lVysCpk3iwcg==", + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@signalapp/libsignal-client/-/libsignal-client-0.65.0.tgz", + "integrity": "sha512-6bb+454/ZoOu6EhHdKHSFVoNKRhka1FhqfiDL/FYLf79g+Nz4kXNxCMRJwYO3hzPAgjjs/6Q7S1mXr9CfS7Kkg==", "hasInstallScript": true, + "license": "AGPL-3.0-only", "dependencies": { "node-gyp-build": "^4.8.0", "type-fest": "^4.26.0", diff --git a/package.json b/package.json index b32abdce1..dd4e7aab3 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "@react-aria/utils": "3.25.3", "@react-spring/web": "9.7.5", "@signalapp/better-sqlite3": "9.0.9", - "@signalapp/libsignal-client": "0.64.1", + "@signalapp/libsignal-client": "0.65.0", "@signalapp/ringrtc": "2.49.2", "@types/fabric": "4.5.3", "backbone": "1.6.0", diff --git a/protos/Backups.proto b/protos/Backups.proto index c873d7280..591be6587 100644 --- a/protos/Backups.proto +++ b/protos/Backups.proto @@ -21,7 +21,7 @@ message BackupInfo { // e.g. a Recipient must come before any Chat referencing it. // 3. All ChatItems must appear in global Chat rendering order. // (The order in which they were received by the client.) -// 4. ChatFolders must appear in render order (e.g., left to right for +// 4. ChatFolders must appear in render order (e.g., left to right for // LTR locales), but can appear anywhere relative to other frames respecting // rule 2 (after Recipients and Chats). // @@ -137,7 +137,7 @@ message Contact { UNVERIFIED = 2; } - message Registered { } + message Registered {} message NotRegistered { uint64 unregisteredTimestamp = 1; } @@ -148,6 +148,11 @@ message Contact { HIDDEN_MESSAGE_REQUEST = 2; } + message Name { + string given = 1; + string family = 2; + } + optional bytes aci = 1; // should be 16 bytes optional bytes pni = 2; // should be 16 bytes optional string username = 3; @@ -167,6 +172,7 @@ message Contact { bool hideStory = 13; optional bytes identityKey = 14; IdentityState identityState = 15; + Name nickname = 16; // absent iff both `given` and `family` are empty } message Group { @@ -206,7 +212,7 @@ message Group { message GroupAttributeBlob { oneof content { string title = 1; - bytes avatar = 2; + bytes avatar = 2; uint32 disappearingMessagesDuration = 3; string descriptionText = 4; } @@ -438,7 +444,7 @@ message StandardMessage { } message ContactMessage { - repeated ContactAttachment contact = 1; + ContactAttachment contact = 1; repeated Reaction reactions = 2; } @@ -467,14 +473,14 @@ message PaymentNotification { Status status = 1; // This identification is used to map the payment table to the ledger - // and is likely required otherwise we may have issues reconciling with + // and is likely required otherwise we may have issues reconciling with // the ledger MobileCoinTxoIdentification mobileCoinIdentification = 2; optional uint64 timestamp = 3; optional uint64 blockIndex = 4; optional uint64 blockTimestamp = 5; - optional bytes transaction = 6; // mobile coin blobs - optional bytes receipt = 7; // mobile coin blobs + optional bytes transaction = 6; // mobile coin blobs + optional bytes receipt = 7; // mobile coin blobs } oneof payment { @@ -482,12 +488,11 @@ message PaymentNotification { FailedTransaction failedTransaction = 2; } } - + optional string amountMob = 1; // stored as a decimal string, e.g. 1.00001 optional string feeMob = 2; // stored as a decimal string, e.g. 1.00001 optional string note = 3; TransactionDetails transactionDetails = 4; - } message GiftBadge { @@ -510,12 +515,12 @@ message ViewOnceMessage { message ContactAttachment { message Name { - optional string givenName = 1; - optional string familyName = 2; - optional string prefix = 3; - optional string suffix = 4; - optional string middleName = 5; - optional string nickname = 6; + string givenName = 1; + string familyName = 2; + string prefix = 3; + string suffix = 4; + string middleName = 5; + string nickname = 6; } message Phone { @@ -527,9 +532,9 @@ message ContactAttachment { CUSTOM = 4; } - optional string value = 1; - optional Type type = 2; - optional string label = 3; + string value = 1; + Type type = 2; + string label = 3; } message Email { @@ -541,9 +546,9 @@ message ContactAttachment { CUSTOM = 4; } - optional string value = 1; - optional Type type = 2; - optional string label = 3; + string value = 1; + Type type = 2; + string label = 3; } message PostalAddress { @@ -554,15 +559,15 @@ message ContactAttachment { CUSTOM = 3; } - optional Type type = 1; - optional string label = 2; - optional string street = 3; - optional string pobox = 4; - optional string neighborhood = 5; - optional string city = 6; - optional string region = 7; - optional string postcode = 8; - optional string country = 9; + Type type = 1; + string label = 2; + string street = 3; + string pobox = 4; + string neighborhood = 5; + string city = 6; + string region = 7; + string postcode = 8; + string country = 9; } optional Name name = 1; @@ -570,7 +575,7 @@ message ContactAttachment { repeated Email email = 4; repeated PostalAddress address = 5; optional FilePointer avatar = 6; - optional string organization = 7; + string organization = 7; } message StickerMessage { @@ -652,7 +657,7 @@ message FilePointer { } // References attachments that are invalid in such a way where download - // cannot be attempted. Could range from missing digests to missing + // cannot be attempted. Could range from missing digests to missing // CDN keys or anything else that makes download attempts impossible. // This serves as a 'tombstone' so that the UX can show that an attachment // did exist, but for whatever reason it's not retrievable. @@ -661,7 +666,7 @@ message FilePointer { oneof locator { BackupLocator backupLocator = 1; - AttachmentLocator attachmentLocator= 2; + AttachmentLocator attachmentLocator = 2; InvalidAttachmentLocator invalidAttachmentLocator = 3; } @@ -798,7 +803,7 @@ message GroupCall { optional uint64 ringerRecipientId = 3; optional uint64 startedCallRecipientId = 4; uint64 startedCallTimestamp = 5; - optional uint64 endedCallTimestamp = 6; // The time the call ended. + optional uint64 endedCallTimestamp = 6; // The time the call ended. bool read = 7; } @@ -1072,7 +1077,7 @@ message GroupMemberJoinedByLinkUpdate { } // A gv1->gv2 migration occurred. -message GroupV2MigrationUpdate {} +message GroupV2MigrationUpdate {} // Another user migrated gv1->gv2 but was unable to add // the local user and invited them instead. @@ -1236,4 +1241,4 @@ message ChatFolder { FolderType folderType = 6; repeated uint64 includedRecipientIds = 7; // generated recipient id of groups, contacts, and/or note to self repeated uint64 excludedRecipientIds = 8; // generated recipient id of groups, contacts, and/or note to self -} \ No newline at end of file +} diff --git a/ts/services/backups/export.ts b/ts/services/backups/export.ts index 35d540ac9..359c834fb 100644 --- a/ts/services/backups/export.ts +++ b/ts/services/backups/export.ts @@ -212,7 +212,7 @@ export class BackupExportStream extends Readable { private readonly roomIdToRecipientId = new Map(); private attachmentBackupJobs: Array = []; private buffers = new Array(); - private nextRecipientId = 0; + private nextRecipientId = 1; private flushResolve: (() => void) | undefined; // Map from custom color uuid to an index in accountSettings.customColors @@ -836,6 +836,8 @@ export class BackupExportStream extends Readable { identityKey = identityKeysById.get(convo.serviceId); } + const { nicknameGivenName, nicknameFamilyName } = convo; + res.contact = { aci: convo.serviceId && convo.serviceId !== convo.pni @@ -872,6 +874,13 @@ export class BackupExportStream extends Readable { // Integer values match so we can use it as is identityState: identityKey?.verified ?? 0, + nickname: + nicknameGivenName || nicknameFamilyName + ? { + given: nicknameGivenName, + family: nicknameFamilyName, + } + : null, }; } else if (isGroupV2(convo) && convo.masterKey) { let storySendMode: Backups.Group.StorySendMode; @@ -1123,32 +1132,31 @@ export class BackupExportStream extends Readable { throw missingCaseError(payment); } } else if (contact && contact[0]) { + const [contactDetails] = contact; const contactMessage = new Backups.ContactMessage(); - contactMessage.contact = await Promise.all( - contact.map(async contactDetails => ({ - ...contactDetails, - number: contactDetails.number?.map(number => ({ - ...number, - type: numberToPhoneType(number.type), - })), - email: contactDetails.email?.map(email => ({ - ...email, - type: numberToPhoneType(email.type), - })), - address: contactDetails.address?.map(address => ({ - ...address, - type: numberToAddressType(address.type), - })), - avatar: contactDetails.avatar?.avatar - ? await this.processAttachment({ - attachment: contactDetails.avatar.avatar, - backupLevel, - messageReceivedAt: message.received_at, - }) - : undefined, - })) - ); + contactMessage.contact = { + ...contactDetails, + number: contactDetails.number?.map(number => ({ + ...number, + type: numberToPhoneType(number.type), + })), + email: contactDetails.email?.map(email => ({ + ...email, + type: numberToPhoneType(email.type), + })), + address: contactDetails.address?.map(address => ({ + ...address, + type: numberToAddressType(address.type), + })), + avatar: contactDetails.avatar?.avatar + ? await this.processAttachment({ + attachment: contactDetails.avatar.avatar, + backupLevel, + messageReceivedAt: message.received_at, + }) + : undefined, + }; const reactions = this.getMessageReactions(message); if (reactions != null) { diff --git a/ts/services/backups/import.ts b/ts/services/backups/import.ts index 3b5f796be..ad2471a76 100644 --- a/ts/services/backups/import.ts +++ b/ts/services/backups/import.ts @@ -895,6 +895,8 @@ export class BackupImportStream extends Writable { hideStory: contact.hideStory === true, username: dropNull(contact.username), expireTimerVersion: 1, + nicknameGivenName: dropNull(contact.nickname?.given), + nicknameFamilyName: dropNull(contact.nickname?.family), }; if (serviceId != null && Bytes.isNotEmpty(contact.identityKey)) { @@ -1908,21 +1910,23 @@ export class BackupImportStream extends Writable { throw new Error(`${logId}: Got chat item with standardMessage set!`); } if (chatItem.contactMessage) { + const { contact: details } = chatItem.contactMessage; + strictAssert(details != null, 'contactMessage must have a contact'); + + const { avatar, name, number, email, address, organization } = details; + return { message: { - contact: (chatItem.contactMessage.contact ?? []).map(details => { - const { avatar, name, number, email, address, organization } = - details; - - return { + contact: [ + { name: name ? { - givenName: dropNull(name.givenName), - familyName: dropNull(name.familyName), - prefix: dropNull(name.prefix), - suffix: dropNull(name.suffix), - middleName: dropNull(name.middleName), - nickname: dropNull(name.nickname), + givenName: name.givenName || undefined, + familyName: name.familyName || undefined, + prefix: name.prefix || undefined, + suffix: name.suffix || undefined, + middleName: name.middleName || undefined, + nickname: name.nickname || undefined, } : undefined, number: number?.length @@ -1935,7 +1939,7 @@ export class BackupImportStream extends Writable { return { value, type: phoneToContactFormType(type), - label: dropNull(label), + label: label || undefined, }; }) .filter(isNotNil) @@ -1950,7 +1954,7 @@ export class BackupImportStream extends Writable { return { value, type: emailToContactFormType(type), - label: dropNull(label), + label: label || undefined, }; }) .filter(isNotNil) @@ -1971,26 +1975,26 @@ export class BackupImportStream extends Writable { return { type: addressToContactAddressType(type), - label: dropNull(label), - street: dropNull(street), - pobox: dropNull(pobox), - neighborhood: dropNull(neighborhood), - city: dropNull(city), - region: dropNull(region), - postcode: dropNull(postcode), - country: dropNull(country), + label: label || undefined, + street: street || undefined, + pobox: pobox || undefined, + neighborhood: neighborhood || undefined, + city: city || undefined, + region: region || undefined, + postcode: postcode || undefined, + country: country || undefined, }; }) : undefined, - organization: dropNull(organization), + organization: organization || undefined, avatar: avatar ? { avatar: convertFilePointerToAttachment(avatar), isProfile: false, } : undefined, - }; - }), + }, + ], reactions: this.fromReactions(chatItem.contactMessage.reactions), }, additionalMessages: [], diff --git a/ts/test-electron/backup/attachments_test.ts b/ts/test-electron/backup/attachments_test.ts index ae5cffb3b..a03bd68ac 100644 --- a/ts/test-electron/backup/attachments_test.ts +++ b/ts/test-electron/backup/attachments_test.ts @@ -364,12 +364,14 @@ describe('backup/attachments', () => { await asymmetricRoundtripHarness( [ composeMessage(1, { + body: 'url', preview: [{ url: 'url', date: 1, image: attachment }], }), ], // path & iv will not be roundtripped [ composeMessage(1, { + body: 'url', preview: [ { url: 'url', @@ -389,6 +391,7 @@ describe('backup/attachments', () => { await asymmetricRoundtripHarness( [ composeMessage(1, { + body: 'url', preview: [ { url: 'url', @@ -402,6 +405,7 @@ describe('backup/attachments', () => { ], [ composeMessage(1, { + body: 'url', preview: [ { url: 'url', @@ -501,12 +505,14 @@ describe('backup/attachments', () => { await asymmetricRoundtripHarness( [ composeMessage(1, { + body: '123', quote: quotedMessage, }), ], // path & iv will not be roundtripped [ composeMessage(1, { + body: '123', quote: { ...quotedMessage, attachments: [ @@ -537,11 +543,13 @@ describe('backup/attachments', () => { await asymmetricRoundtripHarness( [ composeMessage(1, { + body: '123', quote: quotedMessage, }), ], [ composeMessage(1, { + body: '123', quote: { ...quotedMessage, attachments: [ @@ -566,6 +574,7 @@ describe('backup/attachments', () => { const existingAttachment = composeAttachment(1); const existingMessageTimestamp = Date.now(); const existingMessage = composeMessage(existingMessageTimestamp, { + body: '123', attachments: [existingAttachment], }); @@ -584,6 +593,7 @@ describe('backup/attachments', () => { }; const quoteMessage = composeMessage(existingMessageTimestamp + 1, { + body: 'quote', quote: quotedMessage, }); @@ -635,7 +645,9 @@ describe('backup/attachments', () => { }); it('handles quotes which have been copied over from the original (and lack all encryption info)', async () => { - const originalMessage = composeMessage(1); + const originalMessage = composeMessage(1, { + body: 'original', + }); const quotedMessage: QuotedMessageType = { authorAci: originalMessage.sourceServiceId as AciString, isViewOnce: false, @@ -655,6 +667,7 @@ describe('backup/attachments', () => { }; const quoteMessage = composeMessage(originalMessage.timestamp + 1, { + body: 'quote', quote: quotedMessage, }); diff --git a/ts/test-electron/backup/bubble_test.ts b/ts/test-electron/backup/bubble_test.ts index 66deafb53..7d0720b55 100644 --- a/ts/test-electron/backup/bubble_test.ts +++ b/ts/test-electron/backup/bubble_test.ts @@ -264,6 +264,7 @@ describe('backup/bubble messages', () => { seenStatus: SeenStatus.Unseen, unidentifiedDeliveryReceived: true, timestamp: 4, + body: '123', quote: { authorAci: CONTACT_A, attachments: [], @@ -289,6 +290,7 @@ describe('backup/bubble messages', () => { seenStatus: SeenStatus.Unseen, unidentifiedDeliveryReceived: true, timestamp: 3, + body: '123', quote: { authorAci: CONTACT_A, attachments: [], @@ -314,6 +316,7 @@ describe('backup/bubble messages', () => { seenStatus: SeenStatus.Unseen, unidentifiedDeliveryReceived: true, timestamp: 3, + body: '123', quote: { authorAci: CONTACT_A, attachments: [], @@ -353,6 +356,7 @@ describe('backup/bubble messages', () => { seenStatus: SeenStatus.Unseen, unidentifiedDeliveryReceived: true, timestamp: 3, + body: '123', quote: { authorAci: CONTACT_A, attachments: [], diff --git a/ts/test-node/types/EmbeddedContact_test.ts b/ts/test-node/types/EmbeddedContact_test.ts index 471336069..56222563f 100644 --- a/ts/test-node/types/EmbeddedContact_test.ts +++ b/ts/test-node/types/EmbeddedContact_test.ts @@ -652,21 +652,5 @@ describe('Contact', () => { const result = _validate(contact, { messageId }); assert.deepEqual(result?.message, expected); }); - - it('logs if no values remain in contact', async () => { - const messageId = 'the-message-id'; - const contact = { - name: { - nickname: 'Someone Somewhere', - }, - number: [], - email: [], - }; - const expected = - 'Message the-message-id: Contact had no included numbers, email or addresses'; - - const result = _validate(contact, { messageId }); - assert.deepEqual(result?.message, expected); - }); }); }); diff --git a/ts/types/EmbeddedContact.ts b/ts/types/EmbeddedContact.ts index 04ec48b2c..f2a9413e3 100644 --- a/ts/types/EmbeddedContact.ts +++ b/ts/types/EmbeddedContact.ts @@ -306,7 +306,7 @@ export function _validate( contact: EmbeddedContactType, { messageId }: { messageId: string } ): Error | undefined { - const { number, email, address, organization } = contact; + const { organization } = contact; if (!getDisplayName(contact) && !organization) { return new Error( @@ -314,16 +314,6 @@ export function _validate( ); } - if ( - (!number || !number.length) && - (!email || !email.length) && - (!address || !address.length) - ) { - return new Error( - `Message ${messageId}: Contact had no included numbers, email or addresses` - ); - } - return undefined; }