mirror of
https://github.com/signalapp/Signal-iOS.git
synced 2025-12-05 01:10:41 +00:00
Replace Wire with Swift-Protobuf for Backups
This commit is contained in:
1
Podfile
1
Podfile
@@ -47,7 +47,6 @@ pod 'libwebp', podspec: './ThirdParty/libwebp.podspec.json'
|
||||
# third party pods
|
||||
####
|
||||
|
||||
pod 'Wire'
|
||||
pod 'Reachability', :inhibit_warnings => true
|
||||
|
||||
def ui_pods
|
||||
|
||||
@@ -40,7 +40,6 @@ PODS:
|
||||
- SQLCipher/common
|
||||
- SSZipArchive (2.5.2)
|
||||
- SwiftProtobuf (1.26.0)
|
||||
- Wire (4.9.4)
|
||||
- YYImage (1.0.4):
|
||||
- YYImage/Core (= 1.0.4)
|
||||
- YYImage/Core (1.0.4)
|
||||
@@ -67,7 +66,6 @@ DEPENDENCIES:
|
||||
- SQLCipher (from `https://github.com/signalapp/sqlcipher.git`, tag `v4.6.0-f_barrierfsync`)
|
||||
- SSZipArchive (from `ThirdParty/SSZipArchive.podspec`)
|
||||
- SwiftProtobuf (>= 1.14.0)
|
||||
- Wire
|
||||
- YYImage (from `https://github.com/signalapp/YYImage`)
|
||||
- YYImage/libwebp (from `https://github.com/signalapp/YYImage`)
|
||||
|
||||
@@ -81,7 +79,6 @@ SPEC REPOS:
|
||||
- PureLayout
|
||||
- Reachability
|
||||
- SwiftProtobuf
|
||||
- Wire
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
blurhash:
|
||||
@@ -164,9 +161,8 @@ SPEC CHECKSUMS:
|
||||
SQLCipher: 30a8e81afa6128e600b17ffa77d0f92fa05ed208
|
||||
SSZipArchive: 8c3485528a87fa6f90afdbfc33682eb61d985ae5
|
||||
SwiftProtobuf: 5e8349171e7c2f88f5b9e683cb3cb79d1dc780b3
|
||||
Wire: f5fe13fcad476bfd248f23a45a2004167c0ebae2
|
||||
YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331
|
||||
|
||||
PODFILE CHECKSUM: 1cb467dcd01717f6a5002669fd1ddda483686dc9
|
||||
PODFILE CHECKSUM: c8e79c1306b6cc192435ee4f514f6e9702e4ca10
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
||||
2
Pods
2
Pods
Submodule Pods updated: 57050a96b2...04f42f2c37
@@ -1,65 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
WIRE_COMPILER_VERSION="4.9.4"
|
||||
WIRE_COMPILER_CHECKSUM="4134b15e77fa0725ac499d8aded607a1c5b34e7cd9581b18385d868ffb0bfcdd"
|
||||
|
||||
WIRE_COMPILER_JAR="$REPO_ROOT/Scripts/protos/WireCompiler-$WIRE_COMPILER_VERSION.jar"
|
||||
|
||||
# ------ #
|
||||
|
||||
if ! command -v sha256sum > /dev/null; then
|
||||
echo "Error: missing sha256sum!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v java > /dev/null; then
|
||||
echo "Error: Java must be installed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------ #
|
||||
|
||||
if ! [[ -f "$WIRE_COMPILER_JAR" ]]; then
|
||||
echo "Downloading Wire compiler..."
|
||||
|
||||
REMOTE_JAR_URL="https://repo.maven.apache.org/maven2/com/squareup/wire/wire-compiler/$WIRE_COMPILER_VERSION/wire-compiler-$WIRE_COMPILER_VERSION-jar-with-dependencies.jar"
|
||||
curl "$REMOTE_JAR_URL" --output "$WIRE_COMPILER_JAR"
|
||||
fi
|
||||
|
||||
# ------ #
|
||||
|
||||
echo "Checking Wire compiler checksum..."
|
||||
|
||||
echo "$WIRE_COMPILER_CHECKSUM" "$WIRE_COMPILER_JAR" | sha256sum --check > /dev/null
|
||||
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "Error: JAR file checksum failed to validate!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------ #
|
||||
|
||||
echo "Running Wire compiler..."
|
||||
|
||||
BACKUP_PROTOS_DIR="$REPO_ROOT/SignalServiceKit/protobuf/Backups"
|
||||
|
||||
java \
|
||||
-jar "$WIRE_COMPILER_JAR" \
|
||||
--proto_path="$BACKUP_PROTOS_DIR" \
|
||||
--swift_out="$BACKUP_PROTOS_DIR" \
|
||||
> /dev/null
|
||||
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "Error: failed to compile protos!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------ #
|
||||
|
||||
echo "Adding license header to generated files..."
|
||||
|
||||
BACKUP_PROTO_FILES=$(find "$BACKUP_PROTOS_DIR" -name "*.swift")
|
||||
|
||||
"$REPO_ROOT"/Scripts/lint/lint-license-headers --fix $BACKUP_PROTO_FILES
|
||||
@@ -1775,7 +1775,6 @@
|
||||
D221A0E8169DFFC500537ABF /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D221A0E7169DFFC500537ABF /* AVFoundation.framework */; };
|
||||
D24B5BD5169F568C00681372 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D24B5BD4169F568C00681372 /* AudioToolbox.framework */; };
|
||||
D2AEACDC16C426DA00C364C0 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AEACDB16C426DA00C364C0 /* CFNetwork.framework */; };
|
||||
D90D4D7C2BBB45880097C573 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = D90D4D6D2BBB45870097C573 /* README.md */; };
|
||||
D90D4D842BBB61680097C573 /* MessageBackupEmptyFrameId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D90D4D832BBB61680097C573 /* MessageBackupEmptyFrameId.swift */; };
|
||||
D9106DFF2AC1FEFD007ABFE6 /* EmptyForCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9106DFE2AC1FEFD007ABFE6 /* EmptyForCodable.swift */; };
|
||||
D9106E022AC20066007ABFE6 /* EmptyForCodableTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9106E002AC20061007ABFE6 /* EmptyForCodableTest.swift */; };
|
||||
@@ -1857,12 +1856,14 @@
|
||||
D962346B2C0E937500DAF6CB /* InterleavingCompositeCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D931080A2B338CE5006A034E /* InterleavingCompositeCursor.swift */; };
|
||||
D962346D2C0E957800DAF6CB /* DeleteForMeMostRecentAddressableMessageCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D962346C2C0E957800DAF6CB /* DeleteForMeMostRecentAddressableMessageCursor.swift */; };
|
||||
D96234702C0E99DE00DAF6CB /* DeleteForMeMostRecentAddressableMessageCursorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D962346F2C0E99DE00DAF6CB /* DeleteForMeMostRecentAddressableMessageCursorTest.swift */; };
|
||||
D96269D92C58407400152314 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = D96269D82C58407400152314 /* README.md */; };
|
||||
D968F71B2C3355AB00AB318B /* simple-chat-update-message.binproto in Resources */ = {isa = PBXBuildFile; fileRef = D968F7192C3355AA00AB318B /* simple-chat-update-message.binproto */; };
|
||||
D968F71C2C3355AB00AB318B /* simple-chat-update-message.jsonproto in Resources */ = {isa = PBXBuildFile; fileRef = D968F71A2C3355AB00AB318B /* simple-chat-update-message.jsonproto */; };
|
||||
D968F71E2C34884B00AB318B /* MessageBackupReleaseNotesRecipientArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D968F71D2C34884B00AB318B /* MessageBackupReleaseNotesRecipientArchiver.swift */; };
|
||||
D96A94A72954E57F004EA434 /* DonateViewController+MonthlyPaypalDonation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D96A94A62954E57F004EA434 /* DonateViewController+MonthlyPaypalDonation.swift */; };
|
||||
D96BE42E292EF04200E4FE1A /* PaypalButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D96BE42D292EF04200E4FE1A /* PaypalButton.swift */; };
|
||||
D9708B5C29E4CCCB004306FA /* OWSDeviceManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9708B5B29E4CCCB004306FA /* OWSDeviceManagerTest.swift */; };
|
||||
D972E2FF2C542BCD001D7337 /* Backup.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D972E2FE2C542BCD001D7337 /* Backup.pb.swift */; };
|
||||
D97411BB28D277C900BB1865 /* GroupManager+GenericGroupUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97411BA28D277C900BB1865 /* GroupManager+GenericGroupUpdates.swift */; };
|
||||
D979CC262AD3933B006AAC49 /* IndividualCallRecordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D979CC1F2AD3933B006AAC49 /* IndividualCallRecordManager.swift */; };
|
||||
D979CC282AD3933B006AAC49 /* ThreadStore+CallRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = D979CC212AD3933B006AAC49 /* ThreadStore+CallRecord.swift */; };
|
||||
@@ -1955,7 +1956,6 @@
|
||||
D9C0AE672BD7162300FCB05E /* InactiveLinkedDeviceFinderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C0AE612BD7102500FCB05E /* InactiveLinkedDeviceFinderTest.swift */; };
|
||||
D9C0AE692BD82DBC00FCB05E /* InactiveLinkedDeviceReminderMegaphone.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C0AE682BD82DBC00FCB05E /* InactiveLinkedDeviceReminderMegaphone.swift */; };
|
||||
D9C0AE6B2BDB212F00FCB05E /* MessageBackupLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C0AE6A2BDB212F00FCB05E /* MessageBackupLogger.swift */; };
|
||||
D9C0AE6D2BDC520000FCB05E /* BackupProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C0AE6C2BDC520000FCB05E /* BackupProto.swift */; };
|
||||
D9C0AE6F2BDC6B3800FCB05E /* MessageBackupIndividualCallArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C0AE6E2BDC6B3800FCB05E /* MessageBackupIndividualCallArchiver.swift */; };
|
||||
D9C2D77E299D750200D79715 /* UsernameEducationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C2D77D299D750200D79715 /* UsernameEducationManager.swift */; };
|
||||
D9C2D780299EC11400D79715 /* CreateUsernameMegaphone.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C2D77F299EC11400D79715 /* CreateUsernameMegaphone.swift */; };
|
||||
@@ -4833,7 +4833,6 @@
|
||||
D24B5BD4169F568C00681372 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = ../../../../../../System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<group>"; };
|
||||
D2AEACDB16C426DA00C364C0 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
|
||||
D90D4C822BB633560097C573 /* Backup.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = Backup.proto; sourceTree = "<group>"; };
|
||||
D90D4D6D2BBB45870097C573 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
D90D4D832BBB61680097C573 /* MessageBackupEmptyFrameId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBackupEmptyFrameId.swift; sourceTree = "<group>"; };
|
||||
D9106DFE2AC1FEFD007ABFE6 /* EmptyForCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyForCodable.swift; sourceTree = "<group>"; };
|
||||
D9106E002AC20061007ABFE6 /* EmptyForCodableTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyForCodableTest.swift; sourceTree = "<group>"; };
|
||||
@@ -4918,6 +4917,7 @@
|
||||
D95DA7EC28B560D1003996BA /* ConversationViewController+SystemMessageItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConversationViewController+SystemMessageItems.swift"; sourceTree = "<group>"; };
|
||||
D962346C2C0E957800DAF6CB /* DeleteForMeMostRecentAddressableMessageCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteForMeMostRecentAddressableMessageCursor.swift; sourceTree = "<group>"; };
|
||||
D962346F2C0E99DE00DAF6CB /* DeleteForMeMostRecentAddressableMessageCursorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteForMeMostRecentAddressableMessageCursorTest.swift; sourceTree = "<group>"; };
|
||||
D96269D82C58407400152314 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
D9668B34291B088200665298 /* SignalMessagingJobQueues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalMessagingJobQueues.swift; sourceTree = "<group>"; };
|
||||
D968F7192C3355AA00AB318B /* simple-chat-update-message.binproto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "simple-chat-update-message.binproto"; path = "Signal-Message-Backup-Tests/test-cases/simple-chat-update-message.binproto"; sourceTree = "<group>"; };
|
||||
D968F71A2C3355AB00AB318B /* simple-chat-update-message.jsonproto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "simple-chat-update-message.jsonproto"; path = "Signal-Message-Backup-Tests/test-cases/simple-chat-update-message.jsonproto"; sourceTree = "<group>"; };
|
||||
@@ -4926,6 +4926,7 @@
|
||||
D96A94A82955270D004EA434 /* Stripe+Subscriptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stripe+Subscriptions.swift"; sourceTree = "<group>"; };
|
||||
D96BE42D292EF04200E4FE1A /* PaypalButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaypalButton.swift; sourceTree = "<group>"; };
|
||||
D9708B5B29E4CCCB004306FA /* OWSDeviceManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSDeviceManagerTest.swift; sourceTree = "<group>"; };
|
||||
D972E2FE2C542BCD001D7337 /* Backup.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Backup.pb.swift; sourceTree = "<group>"; };
|
||||
D97411BA28D277C900BB1865 /* GroupManager+GenericGroupUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GroupManager+GenericGroupUpdates.swift"; sourceTree = "<group>"; };
|
||||
D979CC1F2AD3933B006AAC49 /* IndividualCallRecordManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndividualCallRecordManager.swift; sourceTree = "<group>"; };
|
||||
D979CC202AD3933B006AAC49 /* IncomingCallEventSyncMessageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncomingCallEventSyncMessageManager.swift; sourceTree = "<group>"; };
|
||||
@@ -5022,7 +5023,6 @@
|
||||
D9C0AE642BD7103100FCB05E /* InactiveLinkedDeviceFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InactiveLinkedDeviceFinder.swift; sourceTree = "<group>"; };
|
||||
D9C0AE682BD82DBC00FCB05E /* InactiveLinkedDeviceReminderMegaphone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InactiveLinkedDeviceReminderMegaphone.swift; sourceTree = "<group>"; };
|
||||
D9C0AE6A2BDB212F00FCB05E /* MessageBackupLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBackupLogger.swift; sourceTree = "<group>"; };
|
||||
D9C0AE6C2BDC520000FCB05E /* BackupProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupProto.swift; sourceTree = "<group>"; };
|
||||
D9C0AE6E2BDC6B3800FCB05E /* MessageBackupIndividualCallArchiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBackupIndividualCallArchiver.swift; sourceTree = "<group>"; };
|
||||
D9C2D777299B07D300D79715 /* Usernames+BetterIdentifierChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Usernames+BetterIdentifierChecker.swift"; sourceTree = "<group>"; };
|
||||
D9C2D77D299D750200D79715 /* UsernameEducationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameEducationManager.swift; sourceTree = "<group>"; };
|
||||
@@ -9845,9 +9845,9 @@
|
||||
D90D4C4C2BB633560097C573 /* Backups */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D972E2FE2C542BCD001D7337 /* Backup.pb.swift */,
|
||||
D90D4C822BB633560097C573 /* Backup.proto */,
|
||||
D9C0AE6C2BDC520000FCB05E /* BackupProto.swift */,
|
||||
D90D4D6D2BBB45870097C573 /* README.md */,
|
||||
D96269D82C58407400152314 /* README.md */,
|
||||
);
|
||||
name = Backups;
|
||||
path = SignalServiceKit/protobuf/Backups;
|
||||
@@ -12678,7 +12678,7 @@
|
||||
F9B0DC5C28948656004E07B7 /* GTSR3.crt in Resources */,
|
||||
F9B0DC5F28948656004E07B7 /* GTSR4.crt in Resources */,
|
||||
F9B0DC5328948656004E07B7 /* isrgrootx1.der in Resources */,
|
||||
D90D4D7C2BBB45880097C573 /* README.md in Resources */,
|
||||
D96269D92C58407400152314 /* README.md in Resources */,
|
||||
F9B0DC4F28948656004E07B7 /* schema.sql in Resources */,
|
||||
F9B0DC5928948656004E07B7 /* signal-messenger.cer in Resources */,
|
||||
);
|
||||
@@ -12789,7 +12789,6 @@
|
||||
"${BUILT_PRODUCTS_DIR}/SQLCipher/SQLCipher.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SignalRingRTC/SignalRingRTC.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Wire/Wire.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/blurhash/blurhash.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/libPhoneNumber-iOS/libPhoneNumber_iOS.framework",
|
||||
@@ -12813,7 +12812,6 @@
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLCipher.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalRingRTC.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Wire.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/blurhash.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libPhoneNumber_iOS.framework",
|
||||
@@ -12869,7 +12867,6 @@
|
||||
"${BUILT_PRODUCTS_DIR}/SQLCipher/SQLCipher.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SignalRingRTC/SignalRingRTC.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Wire/Wire.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/blurhash/blurhash.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/libPhoneNumber-iOS/libPhoneNumber_iOS.framework",
|
||||
@@ -12886,7 +12883,6 @@
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLCipher.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalRingRTC.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Wire.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/blurhash.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libPhoneNumber_iOS.framework",
|
||||
@@ -14160,7 +14156,7 @@
|
||||
7254651E2BA012BD00EABFD2 /* AvatarBuilder.swift in Sources */,
|
||||
720547F22B9C8F9900E2CF2F /* AvatarModel.swift in Sources */,
|
||||
502C69722B06F07900012867 /* AwaitableAsyncBlockOperation.swift in Sources */,
|
||||
D9C0AE6D2BDC520000FCB05E /* BackupProto.swift in Sources */,
|
||||
D972E2FF2C542BCD001D7337 /* Backup.pb.swift in Sources */,
|
||||
F9C5CE3A289453B400548EEE /* BadgeAssets.swift in Sources */,
|
||||
D979DA162B8D1FDD000EEAB8 /* BadgeCountFetcher.swift in Sources */,
|
||||
F9C5CE37289453B400548EEE /* BadgeStore.swift in Sources */,
|
||||
|
||||
@@ -1548,42 +1548,6 @@ limitations under the License.
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2014 Alex Crichton
|
||||
Copyright (c) 2020 Ivan Nikulin <ifaaan@gmail.com>
|
||||
|
||||
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.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>boring-sys 4.6.0</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2015-2016 the fiat-crypto authors (see
|
||||
@@ -1635,6 +1599,42 @@ SOFTWARE.</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2014 Alex Crichton
|
||||
Copyright (c) 2020 Ivan Nikulin <ifaaan@gmail.com>
|
||||
|
||||
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.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>boring-sys 4.6.0</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>/* ====================================================================
|
||||
@@ -3035,42 +3035,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
|
||||
<key>License</key>
|
||||
<string>BSD 3-Clause "New" or "Revised" License</string>
|
||||
<key>Title</key>
|
||||
<string>curve25519-dalek 4.1.3</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2016-2021 isis agora lovecruft. All rights reserved.
|
||||
@@ -3101,6 +3065,42 @@ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
|
||||
<key>License</key>
|
||||
<string>BSD 3-Clause "New" or "Revised" License</string>
|
||||
<key>Title</key>
|
||||
<string>curve25519-dalek 4.1.3</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
|
||||
<key>License</key>
|
||||
<string>BSD 3-Clause "New" or "Revised" License</string>
|
||||
@@ -13126,218 +13126,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>apache2</string>
|
||||
<key>Title</key>
|
||||
<string>Wire</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2017-2021 isis agora lovecruft. All rights reserved.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
extension MessageBackup {
|
||||
/// An identifier for the ``BackupProto.AccountData`` backup frame.
|
||||
/// An identifier for the ``BackupProto_AccountData`` backup frame.
|
||||
///
|
||||
/// Uses a singleton pattern, as there is only ever one account data frame
|
||||
/// in a backup.
|
||||
@@ -15,7 +15,7 @@ extension MessageBackup {
|
||||
|
||||
// MARK: MessageBackupLoggableId
|
||||
|
||||
public var typeLogString: String { "BackupProto.AccountData" }
|
||||
public var typeLogString: String { "BackupProto_AccountData" }
|
||||
public var idLogString: String { "localUser" }
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ extension MessageBackup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Archives the ``BackupProto.AccountData`` frame
|
||||
* Archives the ``BackupProto_AccountData`` frame
|
||||
*/
|
||||
public protocol MessageBackupAccountDataArchiver: MessageBackupProtoArchiver {
|
||||
func archiveAccountData(
|
||||
@@ -33,7 +33,7 @@ public protocol MessageBackupAccountDataArchiver: MessageBackupProtoArchiver {
|
||||
) -> MessageBackup.ArchiveAccountDataResult
|
||||
|
||||
func restore(
|
||||
_ accountData: BackupProto.AccountData,
|
||||
_ accountData: BackupProto_AccountData,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreAccountDataResult
|
||||
}
|
||||
@@ -102,18 +102,19 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
return .failure(.archiveFrameError(.missingLocalProfileKey, .localUser))
|
||||
}
|
||||
|
||||
var accountData = BackupProto.AccountData(
|
||||
profileKey: profileKeyData,
|
||||
givenName: localProfile.givenName ?? "",
|
||||
familyName: localProfile.familyName ?? "",
|
||||
avatarUrlPath: localProfile.avatarUrlPath ?? ""
|
||||
)
|
||||
var accountData = BackupProto_AccountData()
|
||||
accountData.profileKey = profileKeyData
|
||||
accountData.givenName = localProfile.givenName ?? ""
|
||||
accountData.familyName = localProfile.familyName ?? ""
|
||||
accountData.avatarURLPath = localProfile.avatarUrlPath ?? ""
|
||||
|
||||
if let donationSubscriberId = subscriptionManager.getSubscriberID(tx: tx) {
|
||||
accountData.donationSubscriberData = BackupProto.AccountData.SubscriberData(
|
||||
subscriberId: donationSubscriberId,
|
||||
currencyCode: subscriptionManager.getSubscriberCurrencyCode(tx: tx) ?? "",
|
||||
manuallyCancelled: subscriptionManager.userManuallyCancelledSubscription(tx: tx)
|
||||
)
|
||||
var donationSubscriberData = BackupProto_AccountData.SubscriberData()
|
||||
donationSubscriberData.subscriberID = donationSubscriberId
|
||||
donationSubscriberData.currencyCode = subscriptionManager.getSubscriberCurrencyCode(tx: tx) ?? ""
|
||||
donationSubscriberData.manuallyCancelled = subscriptionManager.userManuallyCancelledSubscription(tx: tx)
|
||||
|
||||
accountData.donationSubscriberData = donationSubscriberData
|
||||
}
|
||||
|
||||
if let result = buildUsernameLinkProto(tx: tx) {
|
||||
@@ -124,7 +125,7 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
accountData.accountSettings = buildAccountSettingsProto(tx: tx)
|
||||
|
||||
let error = Self.writeFrameToStream(stream, objectId: MessageBackup.AccountDataId.localUser) {
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .account(accountData)
|
||||
return frame
|
||||
}
|
||||
@@ -136,20 +137,21 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
}
|
||||
}
|
||||
|
||||
private func buildUsernameLinkProto(tx: DBReadTransaction) -> (username: String, usernameLink: BackupProto.AccountData.UsernameLink)? {
|
||||
private func buildUsernameLinkProto(tx: DBReadTransaction) -> (username: String, usernameLink: BackupProto_AccountData.UsernameLink)? {
|
||||
switch self.localUsernameManager.usernameState(tx: tx) {
|
||||
case .unset, .linkCorrupted, .usernameAndLinkCorrupted:
|
||||
return nil
|
||||
case .available(let username, let usernameLink):
|
||||
return (username, BackupProto.AccountData.UsernameLink(
|
||||
entropy: usernameLink.entropy,
|
||||
serverId: usernameLink.handle.data,
|
||||
color: localUsernameManager.usernameLinkQRCodeColor(tx: tx).backupProtoColor
|
||||
))
|
||||
var usernameLinkProto = BackupProto_AccountData.UsernameLink()
|
||||
usernameLinkProto.entropy = usernameLink.entropy
|
||||
usernameLinkProto.serverID = usernameLink.handle.data
|
||||
usernameLinkProto.color = localUsernameManager.usernameLinkQRCodeColor(tx: tx).backupProtoColor
|
||||
|
||||
return (username, usernameLinkProto)
|
||||
}
|
||||
}
|
||||
|
||||
private func buildAccountSettingsProto(tx: DBReadTransaction) -> BackupProto.AccountData.AccountSettings {
|
||||
private func buildAccountSettingsProto(tx: DBReadTransaction) -> BackupProto_AccountData.AccountSettings {
|
||||
|
||||
// Fetch all the account settings
|
||||
let readReceipts = receiptManager.areReadReceiptsEnabled(tx: tx)
|
||||
@@ -169,30 +171,29 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
let storiesDisabled = storyManager.areStoriesEnabled(tx: tx).negated
|
||||
let hasSeenGroupStoryEducationSheet = systemStoryManager.hasSeenGroupStoryEducationSheet(tx: tx)
|
||||
let hasCompletedUsernameOnboarding = usernameEducationManager.shouldShowUsernameEducation(tx: tx).negated
|
||||
let phoneNumberSharingMode: BackupProto.AccountData.PhoneNumberSharingMode = switch udManager.phoneNumberSharingMode(tx: tx) {
|
||||
case .everybody: .EVERYBODY
|
||||
case .nobody: .NOBODY
|
||||
case .none: .UNKNOWN
|
||||
let phoneNumberSharingMode: BackupProto_AccountData.PhoneNumberSharingMode = switch udManager.phoneNumberSharingMode(tx: tx) {
|
||||
case .everybody: .everybody
|
||||
case .nobody: .nobody
|
||||
case .none: .unknown
|
||||
}
|
||||
|
||||
// Populate the proto with the settings
|
||||
var accountSettings = BackupProto.AccountData.AccountSettings(
|
||||
readReceipts: readReceipts,
|
||||
sealedSenderIndicators: sealedSenderIndicators,
|
||||
typingIndicators: typingIndicatorsEnabled,
|
||||
linkPreviews: linkPreviews,
|
||||
notDiscoverableByPhoneNumber: notDiscoverableByPhoneNumber,
|
||||
preferContactAvatars: preferContactAvatars,
|
||||
universalExpireTimerSeconds: universalExpireTimerSeconds,
|
||||
displayBadgesOnProfile: displayBadgesOnProfile,
|
||||
keepMutedChatsArchived: keepMutedChatsArchived,
|
||||
hasSetMyStoriesPrivacy: hasSetMyStoriesPrivacy,
|
||||
hasViewedOnboardingStory: hasViewedOnboardingStory,
|
||||
storiesDisabled: storiesDisabled,
|
||||
hasSeenGroupStoryEducationSheet: hasSeenGroupStoryEducationSheet,
|
||||
hasCompletedUsernameOnboarding: hasCompletedUsernameOnboarding,
|
||||
phoneNumberSharingMode: phoneNumberSharingMode
|
||||
)
|
||||
var accountSettings = BackupProto_AccountData.AccountSettings()
|
||||
accountSettings.readReceipts = readReceipts
|
||||
accountSettings.sealedSenderIndicators = sealedSenderIndicators
|
||||
accountSettings.typingIndicators = typingIndicatorsEnabled
|
||||
accountSettings.linkPreviews = linkPreviews
|
||||
accountSettings.notDiscoverableByPhoneNumber = notDiscoverableByPhoneNumber
|
||||
accountSettings.preferContactAvatars = preferContactAvatars
|
||||
accountSettings.universalExpireTimerSeconds = universalExpireTimerSeconds
|
||||
accountSettings.displayBadgesOnProfile = displayBadgesOnProfile
|
||||
accountSettings.keepMutedChatsArchived = keepMutedChatsArchived
|
||||
accountSettings.hasSetMyStoriesPrivacy_p = hasSetMyStoriesPrivacy
|
||||
accountSettings.hasViewedOnboardingStory_p = hasViewedOnboardingStory
|
||||
accountSettings.storiesDisabled = storiesDisabled
|
||||
accountSettings.hasSeenGroupStoryEducationSheet_p = hasSeenGroupStoryEducationSheet
|
||||
accountSettings.hasCompletedUsernameOnboarding_p = hasCompletedUsernameOnboarding
|
||||
accountSettings.phoneNumberSharingMode = phoneNumberSharingMode
|
||||
accountSettings.preferredReactionEmoji = reactionManager.customEmojiSet(tx: tx) ?? []
|
||||
accountSettings.storyViewReceiptsEnabled = storyManager.areViewReceiptsEnabled(tx: tx)
|
||||
// TODO: [Backups] Archive default chat style
|
||||
@@ -202,7 +203,7 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
}
|
||||
|
||||
public func restore(
|
||||
_ accountData: BackupProto.AccountData,
|
||||
_ accountData: BackupProto_AccountData,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreAccountDataResult {
|
||||
guard let profileKey = OWSAES256Key(data: accountData.profileKey) else {
|
||||
@@ -217,20 +218,22 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
profileManager.insertLocalUserProfile(
|
||||
givenName: accountData.givenName,
|
||||
familyName: accountData.familyName.nilIfEmpty,
|
||||
avatarUrlPath: accountData.avatarUrlPath.nilIfEmpty,
|
||||
avatarUrlPath: accountData.avatarURLPath.nilIfEmpty,
|
||||
profileKey: profileKey,
|
||||
tx: tx
|
||||
)
|
||||
|
||||
// Restore donation subscription data, if present.
|
||||
if let donationSubscriberData = accountData.donationSubscriberData {
|
||||
subscriptionManager.setSubscriberID(subscriberID: donationSubscriberData.subscriberId, tx: tx)
|
||||
if accountData.hasDonationSubscriberData {
|
||||
let donationSubscriberData = accountData.donationSubscriberData
|
||||
subscriptionManager.setSubscriberID(subscriberID: donationSubscriberData.subscriberID, tx: tx)
|
||||
subscriptionManager.setSubscriberCurrencyCode(currencyCode: donationSubscriberData.currencyCode, tx: tx)
|
||||
subscriptionManager.setUserManuallyCancelledSubscription(value: donationSubscriberData.manuallyCancelled, tx: tx)
|
||||
}
|
||||
|
||||
// Restore local settings
|
||||
if let settings = accountData.accountSettings {
|
||||
if accountData.hasAccountSettings {
|
||||
let settings = accountData.accountSettings
|
||||
receiptManager.setAreReadReceiptsEnabled(value: settings.readReceipts, tx: tx)
|
||||
preferences.setShouldShowUnidentifiedDeliveryIndicators(value: settings.sealedSenderIndicators, tx: tx)
|
||||
typingIndicators.setTypingIndicatorsEnabled(value: settings.typingIndicators, tx: tx)
|
||||
@@ -256,22 +259,22 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
}
|
||||
subscriptionManager.setDisplayBadgesOnProfile(value: settings.displayBadgesOnProfile, tx: tx)
|
||||
sskPreferences.setShouldKeepMutedChatsArchived(value: settings.keepMutedChatsArchived, tx: tx)
|
||||
storyManager.setHasSetMyStoriesPrivacy(value: settings.hasSetMyStoriesPrivacy, tx: tx)
|
||||
systemStoryManager.setHasViewedOnboardingStory(value: settings.hasViewedOnboardingStory, tx: tx)
|
||||
storyManager.setHasSetMyStoriesPrivacy(value: settings.hasSetMyStoriesPrivacy_p, tx: tx)
|
||||
systemStoryManager.setHasViewedOnboardingStory(value: settings.hasViewedOnboardingStory_p, tx: tx)
|
||||
storyManager.setAreStoriesEnabled(value: settings.storiesDisabled.negated, tx: tx)
|
||||
if let storyViewReceiptsEnabled = settings.storyViewReceiptsEnabled {
|
||||
storyManager.setAreViewReceiptsEnabled(value: storyViewReceiptsEnabled, tx: tx)
|
||||
if settings.hasStoryViewReceiptsEnabled {
|
||||
storyManager.setAreViewReceiptsEnabled(value: settings.storyViewReceiptsEnabled, tx: tx)
|
||||
}
|
||||
systemStoryManager.setHasSeenGroupStoryEducationSheet(value: settings.hasSeenGroupStoryEducationSheet, tx: tx)
|
||||
usernameEducationManager.setShouldShowUsernameEducation(settings.hasCompletedUsernameOnboarding.negated, tx: tx)
|
||||
systemStoryManager.setHasSeenGroupStoryEducationSheet(value: settings.hasSeenGroupStoryEducationSheet_p, tx: tx)
|
||||
usernameEducationManager.setShouldShowUsernameEducation(settings.hasCompletedUsernameOnboarding_p.negated, tx: tx)
|
||||
udManager.setPhoneNumberSharingMode(
|
||||
mode: { () -> PhoneNumberSharingMode in
|
||||
switch settings.phoneNumberSharingMode {
|
||||
case .UNKNOWN:
|
||||
case .unknown, .UNRECOGNIZED:
|
||||
return .defaultValue
|
||||
case .EVERYBODY:
|
||||
case .everybody:
|
||||
return .everybody
|
||||
case .NOBODY:
|
||||
case .nobody:
|
||||
return .nobody
|
||||
}
|
||||
}(),
|
||||
@@ -282,19 +285,20 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
}
|
||||
|
||||
// Restore username details (username, link, QR color)
|
||||
if let username = accountData.username, let usernameLink = accountData.usernameLink {
|
||||
if accountData.hasUsername, accountData.hasUsernameLink {
|
||||
let username = accountData.username
|
||||
let usernameLink = accountData.usernameLink
|
||||
|
||||
if
|
||||
let handle = UUID(data: usernameLink.serverId),
|
||||
let handle = UUID(data: usernameLink.serverID),
|
||||
let linkData = Usernames.UsernameLink(handle: handle, entropy: usernameLink.entropy)
|
||||
{
|
||||
localUsernameManager.setLocalUsername(username: username, usernameLink: linkData, tx: tx)
|
||||
} else {
|
||||
return .failure([.restoreFrameError(.invalidProtoData(.invalidLocalUsernameLink), .localUser)])
|
||||
}
|
||||
}
|
||||
|
||||
if let color = accountData.usernameLink?.color {
|
||||
localUsernameManager.setUsernameLinkQRCodeColor(color: color.qrCodeColor, tx: tx)
|
||||
localUsernameManager.setUsernameLinkQRCodeColor(color: usernameLink.color.qrCodeColor, tx: tx)
|
||||
}
|
||||
|
||||
return .success
|
||||
@@ -302,32 +306,32 @@ public class MessageBackupAccountDataArchiverImpl: MessageBackupAccountDataArchi
|
||||
}
|
||||
|
||||
private extension Usernames.QRCodeColor {
|
||||
var backupProtoColor: BackupProto.AccountData.UsernameLink.Color {
|
||||
var backupProtoColor: BackupProto_AccountData.UsernameLink.Color {
|
||||
switch self {
|
||||
case .blue: return .BLUE
|
||||
case .white: return .WHITE
|
||||
case .grey: return .GREY
|
||||
case .olive: return .OLIVE
|
||||
case .green: return .GREEN
|
||||
case .orange: return .ORANGE
|
||||
case .pink: return .PINK
|
||||
case .purple: return .PURPLE
|
||||
case .blue: return .blue
|
||||
case .white: return .white
|
||||
case .grey: return .grey
|
||||
case .olive: return .olive
|
||||
case .green: return .green
|
||||
case .orange: return .orange
|
||||
case .pink: return .pink
|
||||
case .purple: return .purple
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension BackupProto.AccountData.UsernameLink.Color {
|
||||
private extension BackupProto_AccountData.UsernameLink.Color {
|
||||
var qrCodeColor: Usernames.QRCodeColor {
|
||||
switch self {
|
||||
case .BLUE: return .blue
|
||||
case .WHITE: return .white
|
||||
case .GREY: return .grey
|
||||
case .OLIVE: return .olive
|
||||
case .GREEN: return .green
|
||||
case .ORANGE: return .orange
|
||||
case .PINK: return .pink
|
||||
case .PURPLE: return .purple
|
||||
case .UNKNOWN: return .unknown
|
||||
case .blue: return .blue
|
||||
case .white: return .white
|
||||
case .grey: return .grey
|
||||
case .olive: return .olive
|
||||
case .green: return .green
|
||||
case .orange: return .orange
|
||||
case .pink: return .pink
|
||||
case .purple: return .purple
|
||||
case .unknown, .UNRECOGNIZED: return .unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ extension MessageBackup {
|
||||
|
||||
// MARK: MessageBackupLoggableId
|
||||
|
||||
public var typeLogString: String { "BackupProto.CallLink" }
|
||||
public var typeLogString: String { "BackupProto_CallLink" }
|
||||
public var idLogString: String {
|
||||
/// Since call IDs are a cross-client identifier, we don't want to
|
||||
/// log them directly.
|
||||
|
||||
@@ -15,17 +15,17 @@ extension MessageBackup {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init(chat: BackupProto.Chat) {
|
||||
fileprivate init(chat: BackupProto_Chat) {
|
||||
self.init(value: chat.id)
|
||||
}
|
||||
|
||||
fileprivate init(chatItem: BackupProto.ChatItem) {
|
||||
self.init(value: chatItem.chatId)
|
||||
fileprivate init(chatItem: BackupProto_ChatItem) {
|
||||
self.init(value: chatItem.chatID)
|
||||
}
|
||||
|
||||
// MARK: MessageBackupLoggableId
|
||||
|
||||
public var typeLogString: String { "BackupProto.Chat" }
|
||||
public var typeLogString: String { "BackupProto_Chat" }
|
||||
public var idLogString: String { "\(value)" }
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ extension MessageBackup {
|
||||
* to the ID addressing system of the backup protos.
|
||||
*
|
||||
* For example, we will assign a ``MessageBackup/ChatId`` to each ``TSThread`` as we
|
||||
* insert them. Later, when we create the ``BackupProto.ChatItem`` corresponding to the ``TSThread``,
|
||||
* insert them. Later, when we create the ``BackupProto_ChatItem`` corresponding to the ``TSThread``,
|
||||
* we will need to add the corresponding ``MessageBackup/ChatId``, which we look up using the thread id
|
||||
* this context keeps.
|
||||
*/
|
||||
@@ -157,14 +157,14 @@ extension MessageBackup {
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.Chat {
|
||||
extension BackupProto_Chat {
|
||||
|
||||
public var chatId: MessageBackup.ChatId {
|
||||
return MessageBackup.ChatId(chat: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.ChatItem {
|
||||
extension BackupProto_ChatItem {
|
||||
|
||||
public var typedChatId: MessageBackup.ChatId {
|
||||
return MessageBackup.ChatId(chatItem: self)
|
||||
|
||||
@@ -14,7 +14,7 @@ public protocol MessageBackupChatArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
typealias RestoreFrameResult = MessageBackup.RestoreFrameResult<ChatId>
|
||||
|
||||
/// Archive all ``TSThread``s (they map to ``BackupProto.Chat``).
|
||||
/// Archive all ``TSThread``s (they map to ``BackupProto_Chat``).
|
||||
///
|
||||
/// - Returns: ``ArchiveMultiFrameResult.success`` if all frames were written without error, or either
|
||||
/// partial or complete failure otherwise.
|
||||
@@ -28,13 +28,13 @@ public protocol MessageBackupChatArchiver: MessageBackupProtoArchiver {
|
||||
tx: DBReadTransaction
|
||||
) -> ArchiveMultiFrameResult
|
||||
|
||||
/// Restore a single ``BackupProto.Chat`` frame.
|
||||
/// Restore a single ``BackupProto_Chat`` frame.
|
||||
///
|
||||
/// - Returns: ``RestoreFrameResult.success`` if all frames were read without error.
|
||||
/// How to handle ``RestoreFrameResult.failure`` is up to the caller,
|
||||
/// but typically an error will be shown to the user, but the restore will be allowed to proceed.
|
||||
func restore(
|
||||
_ chat: BackupProto.Chat,
|
||||
_ chat: BackupProto_Chat,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult
|
||||
@@ -237,22 +237,21 @@ public class MessageBackupChatArchiverImpl: MessageBackupChatArchiver {
|
||||
dontNotifyForMentionsIfMuted = true
|
||||
}
|
||||
|
||||
let chat = BackupProto.Chat(
|
||||
id: chatId.value,
|
||||
recipientId: recipientId.value,
|
||||
archived: threadAssociatedData.isArchived,
|
||||
pinnedOrder: thisThreadPinnedOrder,
|
||||
expirationTimerMs: UInt64(expirationTimerSeconds * 1000),
|
||||
muteUntilMs: threadAssociatedData.mutedUntilTimestamp,
|
||||
markedUnread: threadAssociatedData.isMarkedUnread,
|
||||
dontNotifyForMentionsIfMuted: dontNotifyForMentionsIfMuted
|
||||
)
|
||||
var chat = BackupProto_Chat()
|
||||
chat.id = chatId.value
|
||||
chat.recipientID = recipientId.value
|
||||
chat.archived = threadAssociatedData.isArchived
|
||||
chat.pinnedOrder = thisThreadPinnedOrder
|
||||
chat.expirationTimerMs = UInt64(expirationTimerSeconds * 1000)
|
||||
chat.muteUntilMs = threadAssociatedData.mutedUntilTimestamp
|
||||
chat.markedUnread = threadAssociatedData.isMarkedUnread
|
||||
chat.dontNotifyForMentionsIfMuted = dontNotifyForMentionsIfMuted
|
||||
|
||||
let error = Self.writeFrameToStream(
|
||||
stream,
|
||||
objectId: thread.uniqueThreadIdentifier
|
||||
) {
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .chat(chat)
|
||||
return frame
|
||||
}
|
||||
@@ -266,7 +265,7 @@ public class MessageBackupChatArchiverImpl: MessageBackupChatArchiver {
|
||||
// MARK: - Restoring
|
||||
|
||||
public func restore(
|
||||
_ chat: BackupProto.Chat,
|
||||
_ chat: BackupProto_Chat,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
|
||||
@@ -34,19 +34,19 @@ final class MessageBackupGroupCallArchiver {
|
||||
tx: tx
|
||||
)
|
||||
|
||||
let groupCallState: BackupProto.GroupCall.State
|
||||
let groupCallState: BackupProto_GroupCall.State
|
||||
if let associatedCallRecord {
|
||||
switch associatedCallRecord.callStatus {
|
||||
case .group(.generic): groupCallState = .GENERIC
|
||||
case .group(.joined): groupCallState = .JOINED
|
||||
case .group(.ringing): groupCallState = .RINGING
|
||||
case .group(.generic): groupCallState = .generic
|
||||
case .group(.joined): groupCallState = .joined
|
||||
case .group(.ringing): groupCallState = .ringing
|
||||
case .group(.ringingAccepted):
|
||||
switch associatedCallRecord.callDirection {
|
||||
case .incoming: groupCallState = .ACCEPTED
|
||||
case .outgoing: groupCallState = .OUTGOING_RING
|
||||
case .incoming: groupCallState = .accepted
|
||||
case .outgoing: groupCallState = .outgoingRing
|
||||
}
|
||||
case .group(.ringingDeclined): groupCallState = .DECLINED
|
||||
case .group(.ringingMissed): groupCallState = .MISSED
|
||||
case .group(.ringingDeclined): groupCallState = .declined
|
||||
case .group(.ringingMissed): groupCallState = .missed
|
||||
case .individual:
|
||||
return .messageFailure([.archiveFrameError(
|
||||
.groupCallRecordHadIndividualCallStatus,
|
||||
@@ -55,7 +55,7 @@ final class MessageBackupGroupCallArchiver {
|
||||
}
|
||||
} else {
|
||||
// This call predates the introduction of call records.
|
||||
groupCallState = .GENERIC
|
||||
groupCallState = .generic
|
||||
}
|
||||
|
||||
/// The call record will store the best record of when the call began,
|
||||
@@ -67,17 +67,18 @@ final class MessageBackupGroupCallArchiver {
|
||||
/// iOS doesn't currently track this, so we'll default-populate it.
|
||||
let endedCallTimestamp: UInt64 = 0
|
||||
|
||||
var groupCallUpdate = BackupProto.GroupCall(
|
||||
state: groupCallState,
|
||||
startedCallTimestamp: startedCallTimestamp,
|
||||
endedCallTimestamp: endedCallTimestamp
|
||||
)
|
||||
groupCallUpdate.callId = associatedCallRecord?.callId
|
||||
var groupCallUpdate = BackupProto_GroupCall()
|
||||
groupCallUpdate.state = groupCallState
|
||||
groupCallUpdate.startedCallTimestamp = startedCallTimestamp
|
||||
groupCallUpdate.endedCallTimestamp = endedCallTimestamp
|
||||
if let associatedCallRecord {
|
||||
groupCallUpdate.callID = associatedCallRecord.callId
|
||||
}
|
||||
|
||||
if let ringerAci = associatedCallRecord?.groupCallRingerAci {
|
||||
switch context.recipientContext.getRecipientId(aci: ringerAci, forInteraction: groupCallInteraction) {
|
||||
case .found(let recipientId):
|
||||
groupCallUpdate.ringerRecipientId = recipientId.value
|
||||
groupCallUpdate.ringerRecipientID = recipientId.value
|
||||
case .missing(let archiveFrameError):
|
||||
return .messageFailure([archiveFrameError])
|
||||
}
|
||||
@@ -86,18 +87,18 @@ final class MessageBackupGroupCallArchiver {
|
||||
if let creatorAci = groupCallInteraction.creatorUuid.flatMap({ Aci.parseFrom(aciString: $0) }) {
|
||||
switch context.recipientContext.getRecipientId(aci: creatorAci, forInteraction: groupCallInteraction) {
|
||||
case .found(let recipientId):
|
||||
groupCallUpdate.startedCallRecipientId = recipientId.value
|
||||
groupCallUpdate.startedCallRecipientID = recipientId.value
|
||||
case .missing(let archiveFrameError):
|
||||
return .messageFailure([archiveFrameError])
|
||||
}
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .groupCall(groupCallUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: context.recipientContext.localRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -108,8 +109,8 @@ final class MessageBackupGroupCallArchiver {
|
||||
}
|
||||
|
||||
func restoreGroupCall(
|
||||
_ groupCall: BackupProto.GroupCall,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ groupCall: BackupProto_GroupCall,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
@@ -126,9 +127,9 @@ final class MessageBackupGroupCallArchiver {
|
||||
}
|
||||
|
||||
let startedCallAci: Aci?
|
||||
if let startedCallRecipientId = groupCall.startedCallRecipientId {
|
||||
if groupCall.hasStartedCallRecipientID {
|
||||
switch context.recipientContext.getAci(
|
||||
recipientId: MessageBackup.RecipientId(value: startedCallRecipientId),
|
||||
recipientId: MessageBackup.RecipientId(value: groupCall.startedCallRecipientID),
|
||||
forChatItemId: chatItem.id
|
||||
) {
|
||||
case .found(let aci): startedCallAci = aci
|
||||
@@ -146,39 +147,39 @@ final class MessageBackupGroupCallArchiver {
|
||||
)
|
||||
interactionStore.insertInteraction(groupCallInteraction, tx: tx)
|
||||
|
||||
if let callId = groupCall.callId {
|
||||
if groupCall.hasCallID {
|
||||
let callDirection: CallRecord.CallDirection
|
||||
let callStatus: CallRecord.CallStatus.GroupCallStatus
|
||||
switch groupCall.state {
|
||||
case .UNKNOWN_STATE:
|
||||
case .unknownState, .UNRECOGNIZED:
|
||||
return .messageFailure([.restoreFrameError(.invalidProtoData(.groupCallUnrecognizedState), chatItem.id)])
|
||||
case .GENERIC:
|
||||
case .generic:
|
||||
callDirection = .incoming
|
||||
callStatus = .generic
|
||||
case .JOINED:
|
||||
case .joined:
|
||||
callDirection = .incoming
|
||||
callStatus = .joined
|
||||
case .RINGING:
|
||||
case .ringing:
|
||||
callDirection = .incoming
|
||||
callStatus = .ringing
|
||||
case .ACCEPTED:
|
||||
case .accepted:
|
||||
callDirection = .incoming
|
||||
callStatus = .ringingAccepted
|
||||
case .DECLINED:
|
||||
case .declined:
|
||||
callDirection = .incoming
|
||||
callStatus = .ringingDeclined
|
||||
case .MISSED, .MISSED_NOTIFICATION_PROFILE:
|
||||
case .missed, .missedNotificationProfile:
|
||||
callDirection = .incoming
|
||||
callStatus = .ringingMissed
|
||||
case .OUTGOING_RING:
|
||||
case .outgoingRing:
|
||||
callDirection = .outgoing
|
||||
callStatus = .ringingAccepted
|
||||
}
|
||||
|
||||
let groupCallRingerAci: Aci?
|
||||
if let ringerRecipientId = groupCall.ringerRecipientId {
|
||||
if groupCall.hasRingerRecipientID {
|
||||
switch context.recipientContext.getAci(
|
||||
recipientId: MessageBackup.RecipientId(value: ringerRecipientId),
|
||||
recipientId: MessageBackup.RecipientId(value: groupCall.ringerRecipientID),
|
||||
forChatItemId: chatItem.id
|
||||
) {
|
||||
case .found(let aci): groupCallRingerAci = aci
|
||||
@@ -189,7 +190,7 @@ final class MessageBackupGroupCallArchiver {
|
||||
}
|
||||
|
||||
_ = groupCallRecordManager.createGroupCallRecord(
|
||||
callId: callId,
|
||||
callId: groupCall.callID,
|
||||
groupCallInteraction: groupCallInteraction,
|
||||
groupCallInteractionRowId: groupCallInteraction.sqliteRowId!,
|
||||
groupThread: groupThread,
|
||||
|
||||
@@ -32,67 +32,68 @@ final class MessageBackupIndividualCallArchiver {
|
||||
tx: tx
|
||||
)
|
||||
|
||||
var individualCallUpdate = BackupProto.IndividualCall(
|
||||
type: { () -> BackupProto.IndividualCall.Type_ in
|
||||
switch individualCallInteraction.offerType {
|
||||
case .audio: return .AUDIO_CALL
|
||||
case .video: return .VIDEO_CALL
|
||||
}
|
||||
}(),
|
||||
direction: { () -> BackupProto.IndividualCall.Direction in
|
||||
switch individualCallInteraction.callType {
|
||||
case
|
||||
.incoming,
|
||||
.incomingIncomplete,
|
||||
.incomingMissed,
|
||||
.incomingMissedBecauseOfChangedIdentity,
|
||||
.incomingMissedBecauseOfDoNotDisturb,
|
||||
.incomingMissedBecauseBlockedSystemContact,
|
||||
.incomingDeclined,
|
||||
.incomingDeclinedElsewhere,
|
||||
.incomingAnsweredElsewhere,
|
||||
.incomingBusyElsewhere:
|
||||
return .INCOMING
|
||||
case .outgoing, .outgoingIncomplete, .outgoingMissed:
|
||||
return .OUTGOING
|
||||
@unknown default:
|
||||
return .UNKNOWN_DIRECTION
|
||||
}
|
||||
}(),
|
||||
state: { () -> BackupProto.IndividualCall.State in
|
||||
switch individualCallInteraction.callType {
|
||||
case .incoming, .outgoing:
|
||||
return .ACCEPTED
|
||||
case
|
||||
.outgoingIncomplete,
|
||||
.incomingIncomplete,
|
||||
.incomingDeclined,
|
||||
.incomingDeclinedElsewhere,
|
||||
.incomingAnsweredElsewhere,
|
||||
.incomingBusyElsewhere:
|
||||
return .NOT_ACCEPTED
|
||||
case
|
||||
.incomingMissed,
|
||||
.incomingMissedBecauseOfChangedIdentity,
|
||||
.incomingMissedBecauseBlockedSystemContact,
|
||||
.outgoingMissed:
|
||||
return .MISSED
|
||||
case .incomingMissedBecauseOfDoNotDisturb:
|
||||
return .MISSED_NOTIFICATION_PROFILE
|
||||
@unknown default:
|
||||
return .UNKNOWN_STATE
|
||||
}
|
||||
}(),
|
||||
startedCallTimestamp: individualCallInteraction.timestamp
|
||||
)
|
||||
individualCallUpdate.callId = associatedCallRecord?.callId
|
||||
var individualCallUpdate = BackupProto_IndividualCall()
|
||||
individualCallUpdate.type = { () -> BackupProto_IndividualCall.TypeEnum in
|
||||
switch individualCallInteraction.offerType {
|
||||
case .audio: return .audioCall
|
||||
case .video: return .videoCall
|
||||
}
|
||||
}()
|
||||
individualCallUpdate.direction = { () -> BackupProto_IndividualCall.Direction in
|
||||
switch individualCallInteraction.callType {
|
||||
case
|
||||
.incoming,
|
||||
.incomingIncomplete,
|
||||
.incomingMissed,
|
||||
.incomingMissedBecauseOfChangedIdentity,
|
||||
.incomingMissedBecauseOfDoNotDisturb,
|
||||
.incomingMissedBecauseBlockedSystemContact,
|
||||
.incomingDeclined,
|
||||
.incomingDeclinedElsewhere,
|
||||
.incomingAnsweredElsewhere,
|
||||
.incomingBusyElsewhere:
|
||||
return .incoming
|
||||
case .outgoing, .outgoingIncomplete, .outgoingMissed:
|
||||
return .outgoing
|
||||
@unknown default:
|
||||
return .unknownDirection
|
||||
}
|
||||
}()
|
||||
individualCallUpdate.state = { () -> BackupProto_IndividualCall.State in
|
||||
switch individualCallInteraction.callType {
|
||||
case .incoming, .outgoing:
|
||||
return .accepted
|
||||
case
|
||||
.outgoingIncomplete,
|
||||
.incomingIncomplete,
|
||||
.incomingDeclined,
|
||||
.incomingDeclinedElsewhere,
|
||||
.incomingAnsweredElsewhere,
|
||||
.incomingBusyElsewhere:
|
||||
return .notAccepted
|
||||
case
|
||||
.incomingMissed,
|
||||
.incomingMissedBecauseOfChangedIdentity,
|
||||
.incomingMissedBecauseBlockedSystemContact,
|
||||
.outgoingMissed:
|
||||
return .missed
|
||||
case .incomingMissedBecauseOfDoNotDisturb:
|
||||
return .missedNotificationProfile
|
||||
@unknown default:
|
||||
return .unknownState
|
||||
}
|
||||
}()
|
||||
individualCallUpdate.startedCallTimestamp = individualCallInteraction.timestamp
|
||||
if let associatedCallRecord {
|
||||
individualCallUpdate.callID = associatedCallRecord.callId
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .individualCall(individualCallUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: context.recipientContext.localRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -103,8 +104,8 @@ final class MessageBackupIndividualCallArchiver {
|
||||
}
|
||||
|
||||
func restoreIndividualCall(
|
||||
_ individualCall: BackupProto.IndividualCall,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ individualCall: BackupProto_IndividualCall,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
@@ -124,35 +125,35 @@ final class MessageBackupIndividualCallArchiver {
|
||||
let callRecordDirection: CallRecord.CallDirection
|
||||
let callRecordStatus: CallRecord.CallStatus.IndividualCallStatus
|
||||
switch (individualCall.direction, individualCall.state) {
|
||||
case (.UNKNOWN_DIRECTION, _):
|
||||
case (.unknownDirection, _), (.UNRECOGNIZED, _):
|
||||
return .messageFailure([.restoreFrameError(.invalidProtoData(.individualCallUnrecognizedDirection), chatItem.id)])
|
||||
case (_, .UNKNOWN_STATE):
|
||||
case (_, .unknownState), (_, .UNRECOGNIZED):
|
||||
return .messageFailure([.restoreFrameError(.invalidProtoData(.individualCallUnrecognizedState), chatItem.id)])
|
||||
case (.INCOMING, .ACCEPTED):
|
||||
case (.incoming, .accepted):
|
||||
callInteractionType = .incoming
|
||||
callRecordDirection = .incoming
|
||||
callRecordStatus = .accepted
|
||||
case (.INCOMING, .NOT_ACCEPTED):
|
||||
case (.incoming, .notAccepted):
|
||||
callInteractionType = .incomingDeclined
|
||||
callRecordDirection = .incoming
|
||||
callRecordStatus = .notAccepted
|
||||
case (.INCOMING, .MISSED):
|
||||
case (.incoming, .missed):
|
||||
callInteractionType = .incomingMissed
|
||||
callRecordDirection = .incoming
|
||||
callRecordStatus = .incomingMissed
|
||||
case (.INCOMING, .MISSED_NOTIFICATION_PROFILE):
|
||||
case (.incoming, .missedNotificationProfile):
|
||||
callInteractionType = .incomingMissedBecauseOfDoNotDisturb
|
||||
callRecordDirection = .incoming
|
||||
callRecordStatus = .incomingMissed
|
||||
case (.OUTGOING, .ACCEPTED):
|
||||
case (.outgoing, .accepted):
|
||||
callInteractionType = .outgoing
|
||||
callRecordDirection = .outgoing
|
||||
callRecordStatus = .accepted
|
||||
case (.OUTGOING, .NOT_ACCEPTED):
|
||||
case (.outgoing, .notAccepted):
|
||||
callInteractionType = .outgoingIncomplete
|
||||
callRecordDirection = .outgoing
|
||||
callRecordStatus = .notAccepted
|
||||
case (.OUTGOING, .MISSED), (.OUTGOING, .MISSED_NOTIFICATION_PROFILE):
|
||||
case (.outgoing, .missed), (.outgoing, .missedNotificationProfile):
|
||||
callInteractionType = .outgoingMissed
|
||||
callRecordDirection = .outgoing
|
||||
callRecordStatus = .notAccepted
|
||||
@@ -161,13 +162,13 @@ final class MessageBackupIndividualCallArchiver {
|
||||
let callInteractionOfferType: TSRecentCallOfferType
|
||||
let callRecordType: CallRecord.CallType
|
||||
switch individualCall.type {
|
||||
case .AUDIO_CALL:
|
||||
case .audioCall:
|
||||
callInteractionOfferType = .audio
|
||||
callRecordType = .audioCall
|
||||
case .VIDEO_CALL:
|
||||
case .videoCall:
|
||||
callInteractionOfferType = .video
|
||||
callRecordType = .videoCall
|
||||
case .UNKNOWN_TYPE:
|
||||
case .unknownType, .UNRECOGNIZED:
|
||||
return .messageFailure([.restoreFrameError(.invalidProtoData(.individualCallUnrecognizedType), chatItem.id)])
|
||||
}
|
||||
|
||||
@@ -179,13 +180,13 @@ final class MessageBackupIndividualCallArchiver {
|
||||
)
|
||||
interactionStore.insertInteraction(individualCallInteraction, tx: tx)
|
||||
|
||||
if let callId = individualCall.callId {
|
||||
if individualCall.hasCallID {
|
||||
individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: individualCallInteraction,
|
||||
individualCallInteractionRowId: individualCallInteraction.sqliteRowId!,
|
||||
contactThread: contactThread,
|
||||
contactThreadRowId: chatThread.threadRowId,
|
||||
callId: callId,
|
||||
callId: individualCall.callID,
|
||||
callType: callRecordType,
|
||||
callDirection: callRecordDirection,
|
||||
individualCallStatus: callRecordStatus,
|
||||
|
||||
@@ -74,7 +74,7 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
localIdentifiers: context.recipientContext.localIdentifiers,
|
||||
partialErrors: &partialErrors
|
||||
)
|
||||
let groupChange: BackupProto.GroupChangeChatUpdate
|
||||
let groupChange: BackupProto_GroupChangeChatUpdate
|
||||
switch contentsResult.bubbleUp(Details.self, partialErrors: &partialErrors) {
|
||||
case .continue(let groupUpdate):
|
||||
groupChange = groupUpdate
|
||||
@@ -82,10 +82,10 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
return errorResult
|
||||
}
|
||||
|
||||
var chatUpdate = BackupProto.ChatUpdateMessage()
|
||||
var chatUpdate = BackupProto_ChatUpdateMessage()
|
||||
chatUpdate.update = .groupChange(groupChange)
|
||||
|
||||
let directionlessDetails = BackupProto.ChatItem.DirectionlessMessageDetails()
|
||||
let directionlessDetails = BackupProto_ChatItem.DirectionlessMessageDetails()
|
||||
|
||||
let details = Details(
|
||||
author: context.recipientContext.localRecipientId,
|
||||
@@ -108,8 +108,8 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
interactionId: MessageBackup.InteractionUniqueId,
|
||||
localIdentifiers: LocalIdentifiers,
|
||||
partialErrors: inout [ArchiveFrameError]
|
||||
) -> MessageBackup.ArchiveInteractionResult<BackupProto.GroupChangeChatUpdate> {
|
||||
var updates = [BackupProto.GroupChangeChatUpdate.Update]()
|
||||
) -> MessageBackup.ArchiveInteractionResult<BackupProto_GroupChangeChatUpdate> {
|
||||
var updates = [BackupProto_GroupChangeChatUpdate.Update]()
|
||||
|
||||
var skipCount = 0
|
||||
var latestSkipError: MessageBackup.SkippableChatUpdate.SkippableGroupUpdate?
|
||||
@@ -121,7 +121,7 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
interactionId: interactionId
|
||||
)
|
||||
switch result.bubbleUp(
|
||||
BackupProto.GroupChangeChatUpdate.self,
|
||||
BackupProto_GroupChangeChatUpdate.self,
|
||||
partialErrors: &partialErrors
|
||||
) {
|
||||
case .continue(let update):
|
||||
@@ -146,7 +146,7 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
return .messageFailure(partialErrors + [.archiveFrameError(.emptyGroupUpdate, interactionId)])
|
||||
}
|
||||
|
||||
var groupChangeChatUpdate = BackupProto.GroupChangeChatUpdate()
|
||||
var groupChangeChatUpdate = BackupProto_GroupChangeChatUpdate()
|
||||
groupChangeChatUpdate.updates = updates
|
||||
|
||||
if partialErrors.isEmpty {
|
||||
@@ -157,8 +157,8 @@ final class MessageBackupGroupUpdateMessageArchiver {
|
||||
}
|
||||
|
||||
func restoreGroupUpdate(
|
||||
_ groupUpdate: BackupProto.GroupChangeChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ groupUpdate: BackupProto_GroupChangeChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
import Foundation
|
||||
import LibSignalClient
|
||||
|
||||
internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
|
||||
private init() {}
|
||||
|
||||
typealias PersistableGroupUpdateItem = TSInfoMessage.PersistableGroupUpdateItem
|
||||
|
||||
internal static func restoreGroupUpdates(
|
||||
groupUpdates: [BackupProto.GroupChangeChatUpdate.Update],
|
||||
static func restoreGroupUpdates(
|
||||
groupUpdates: [BackupProto_GroupChangeChatUpdate.Update],
|
||||
// We should never be comparing our pni as it can change,
|
||||
// we only ever want to compare our unchanging aci.
|
||||
localUserAci: Aci,
|
||||
@@ -37,54 +37,58 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
|
||||
private static func restoreGroupUpdate(
|
||||
groupUpdate: BackupProto.GroupChangeChatUpdate.Update,
|
||||
groupUpdate: BackupProto_GroupChangeChatUpdate.Update,
|
||||
localUserAci: Aci,
|
||||
chatItemId: MessageBackup.ChatItemId
|
||||
) -> MessageBackup.RestoreInteractionResult<[PersistableGroupUpdateItem]> {
|
||||
enum UnwrappedAci {
|
||||
enum UnwrappedRequiredAci {
|
||||
case localUser
|
||||
case otherUser(AciUuid)
|
||||
case invalidAci(MessageBackup.RestoreFrameError<MessageBackup.ChatItemId>)
|
||||
}
|
||||
enum UnwrappedOptionalAci {
|
||||
case unknown
|
||||
case localUser
|
||||
case otherUser(AciUuid)
|
||||
case invalidAci(MessageBackup.RestoreFrameError<MessageBackup.ChatItemId>)
|
||||
}
|
||||
|
||||
func unwrapAci<Proto>(
|
||||
func unwrapRequiredAci<Proto>(
|
||||
_ proto: Proto,
|
||||
_ aciKeyPath: KeyPath<Proto, Data>
|
||||
) -> UnwrappedAci {
|
||||
) -> UnwrappedRequiredAci {
|
||||
let aciData = proto[keyPath: aciKeyPath]
|
||||
guard let aciUuid = UUID(data: aciData) else {
|
||||
|
||||
guard let aci = UUID(data: aciData).map({ Aci(fromUUID: $0) }) else {
|
||||
return .invalidAci(.restoreFrameError(
|
||||
.invalidProtoData(.invalidAci(protoClass: Proto.self)),
|
||||
chatItemId
|
||||
))
|
||||
}
|
||||
let aci = Aci(fromUUID: aciUuid)
|
||||
|
||||
if aci == localUserAci {
|
||||
return .localUser
|
||||
} else {
|
||||
return .otherUser(aci.codableUuid)
|
||||
}
|
||||
}
|
||||
func unwrapAci<Proto>(
|
||||
|
||||
enum UnwrappedOptionalAci {
|
||||
case unknown
|
||||
case localUser
|
||||
case otherUser(AciUuid)
|
||||
case invalidAci(MessageBackup.RestoreFrameError<MessageBackup.ChatItemId>)
|
||||
}
|
||||
func unwrapOptionalAci<Proto>(
|
||||
_ proto: Proto,
|
||||
_ aciKeyPath: KeyPath<Proto, Data?>
|
||||
_ aciKeyPath: KeyPath<Proto, Data>
|
||||
) -> UnwrappedOptionalAci {
|
||||
guard let aciData = proto[keyPath: aciKeyPath] else {
|
||||
let aciData = proto[keyPath: aciKeyPath]
|
||||
|
||||
guard !aciData.isEmpty else {
|
||||
return .unknown
|
||||
}
|
||||
guard let aciUuid = UUID(data: aciData) else {
|
||||
|
||||
guard let aci = UUID(data: aciData).map({ Aci(fromUUID: $0) }) else {
|
||||
return .invalidAci(.restoreFrameError(
|
||||
.invalidProtoData(.invalidAci(protoClass: Proto.self)),
|
||||
chatItemId
|
||||
))
|
||||
}
|
||||
let aci = Aci(fromUUID: aciUuid)
|
||||
|
||||
if aci == localUserAci {
|
||||
return .localUser
|
||||
} else {
|
||||
@@ -93,10 +97,10 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
|
||||
switch groupUpdate.update {
|
||||
case .none:
|
||||
case nil:
|
||||
return .messageFailure([.restoreFrameError(.invalidProtoData(.unrecognizedGroupUpdate), chatItemId)])
|
||||
case .genericGroupUpdate(let proto):
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.genericUpdateByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -107,7 +111,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupCreationUpdate(let proto):
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.genericUpdateByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -120,8 +124,9 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupNameUpdate(let proto):
|
||||
if let newName = proto.newGroupName {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
if proto.hasNewGroupName {
|
||||
let newName = proto.newGroupName
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.nameChangedByUnknownUser(newGroupName: newName)])
|
||||
case .localUser:
|
||||
@@ -132,7 +137,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.nameRemovedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -145,7 +150,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupAvatarUpdate(let proto):
|
||||
if proto.wasRemoved {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.avatarRemovedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -156,7 +161,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.avatarChangedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -168,8 +173,9 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupDescriptionUpdate(let proto):
|
||||
if let newDescription = proto.newDescription {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
if proto.hasNewDescription {
|
||||
let newDescription = proto.newDescription
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.descriptionChangedByUnknownUser(newDescription: newDescription)])
|
||||
case .localUser:
|
||||
@@ -180,7 +186,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.descriptionRemovedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -193,7 +199,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupMembershipAccessLevelChangeUpdate(let proto):
|
||||
let newAccess = proto.accessLevel.swiftAccessLevel
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.membersAccessChangedByUnknownUser(newAccess: newAccess)])
|
||||
case .localUser:
|
||||
@@ -205,7 +211,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupAttributesAccessLevelChangeUpdate(let proto):
|
||||
let newAccess = proto.accessLevel.swiftAccessLevel
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.attributesAccessChangedByUnknownUser(newAccess: newAccess)])
|
||||
case .localUser:
|
||||
@@ -217,7 +223,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupAnnouncementOnlyChangeUpdate(let proto):
|
||||
if proto.isAnnouncementOnly {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.announcementOnlyEnabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -228,7 +234,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.announcementOnlyDisabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -240,8 +246,8 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupAdminStatusUpdate(let proto):
|
||||
let updaterAci = unwrapAci(proto, \.updaterAci)
|
||||
let memberAci = unwrapAci(proto, \.memberAci)
|
||||
let updaterAci = unwrapOptionalAci(proto, \.updaterAci)
|
||||
let memberAci = unwrapRequiredAci(proto, \.memberAci)
|
||||
if proto.wasAdminStatusGranted {
|
||||
switch (updaterAci, memberAci) {
|
||||
case (.unknown, .localUser):
|
||||
@@ -278,7 +284,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupMemberLeftUpdate(let proto):
|
||||
switch unwrapAci(proto, \.aci) {
|
||||
switch unwrapRequiredAci(proto, \.aci) {
|
||||
case .localUser:
|
||||
return .success([.localUserLeft])
|
||||
case .otherUser(let aci):
|
||||
@@ -287,7 +293,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupMemberRemovedUpdate(let proto):
|
||||
switch (unwrapAci(proto, \.removerAci), unwrapAci(proto, \.removedAci)) {
|
||||
switch (unwrapOptionalAci(proto, \.removerAci), unwrapRequiredAci(proto, \.removedAci)) {
|
||||
case (.unknown, .localUser):
|
||||
return .success([.localUserRemovedByUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -304,7 +310,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .selfInvitedToGroupUpdate(let proto):
|
||||
switch unwrapAci(proto, \.inviterAci) {
|
||||
switch unwrapOptionalAci(proto, \.inviterAci) {
|
||||
case .unknown:
|
||||
return .success([.localUserWasInvitedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -315,18 +321,18 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .selfInvitedOtherUserToGroupUpdate(let proto):
|
||||
switch (try? ServiceId.parseFrom(serviceIdBinary: proto.inviteeServiceId)) {
|
||||
switch (try? ServiceId.parseFrom(serviceIdBinary: proto.inviteeServiceID)) {
|
||||
case .some(let serviceId):
|
||||
return .success([.otherUserWasInvitedByLocalUser(inviteeServiceId: serviceId.codableUppercaseString)])
|
||||
case .none:
|
||||
return .messageFailure([.restoreFrameError(
|
||||
.invalidProtoData(.invalidServiceId(protoClass: BackupProto.SelfInvitedOtherUserToGroupUpdate.self)),
|
||||
.invalidProtoData(.invalidServiceId(protoClass: BackupProto_SelfInvitedOtherUserToGroupUpdate.self)),
|
||||
chatItemId
|
||||
)])
|
||||
}
|
||||
case .groupUnknownInviteeUpdate(let proto):
|
||||
let count = UInt(proto.inviteeCount)
|
||||
switch unwrapAci(proto, \.inviterAci) {
|
||||
switch unwrapOptionalAci(proto, \.inviterAci) {
|
||||
case .unknown:
|
||||
return .success([.unnamedUsersWereInvitedByUnknownUser(count: count)])
|
||||
case .localUser:
|
||||
@@ -337,7 +343,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupInvitationAcceptedUpdate(let proto):
|
||||
switch (unwrapAci(proto, \.inviterAci), unwrapAci(proto, \.newMemberAci)) {
|
||||
switch (unwrapOptionalAci(proto, \.inviterAci), unwrapRequiredAci(proto, \.newMemberAci)) {
|
||||
case (.unknown, .localUser):
|
||||
return .success([.localUserAcceptedInviteFromUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -354,7 +360,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupInvitationDeclinedUpdate(let proto):
|
||||
switch (unwrapAci(proto, \.inviterAci), unwrapAci(proto, \.inviteeAci)) {
|
||||
switch (unwrapOptionalAci(proto, \.inviterAci), unwrapOptionalAci(proto, \.inviteeAci)) {
|
||||
case (.unknown, .localUser):
|
||||
return .success([.localUserDeclinedInviteFromUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -377,7 +383,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupMemberJoinedUpdate(let proto):
|
||||
switch unwrapAci(proto, \.newMemberAci) {
|
||||
switch unwrapRequiredAci(proto, \.newMemberAci) {
|
||||
case .localUser:
|
||||
return .success([.localUserJoined])
|
||||
case .otherUser(let aci):
|
||||
@@ -386,7 +392,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupMemberAddedUpdate(let proto):
|
||||
switch (unwrapAci(proto, \.inviterAci), unwrapAci(proto, \.newMemberAci)) {
|
||||
switch (unwrapOptionalAci(proto, \.inviterAci), unwrapRequiredAci(proto, \.newMemberAci)) {
|
||||
case (.unknown, .localUser):
|
||||
return .success([.localUserAddedByUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -403,7 +409,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupSelfInvitationRevokedUpdate(let proto):
|
||||
switch unwrapAci(proto, \.revokerAci) {
|
||||
switch unwrapOptionalAci(proto, \.revokerAci) {
|
||||
case .unknown:
|
||||
return .success([.localUserInviteRevokedByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -414,20 +420,20 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupInvitationRevokedUpdate(let proto):
|
||||
let updaterAci = unwrapAci(proto, \.updaterAci)
|
||||
let updaterAci = unwrapOptionalAci(proto, \.updaterAci)
|
||||
if
|
||||
case .localUser = updaterAci,
|
||||
proto.invitees.count == 1,
|
||||
let inviteeServiceId: ServiceId = {
|
||||
let invitee = proto.invitees[0]
|
||||
if
|
||||
let aciRaw = invitee.inviteeAci,
|
||||
let aciUuid = UUID(data: aciRaw)
|
||||
invitee.hasInviteeAci,
|
||||
let aciUuid = UUID(data: invitee.inviteeAci)
|
||||
{
|
||||
return Aci(fromUUID: aciUuid)
|
||||
} else if
|
||||
let pniRaw = invitee.inviteePni,
|
||||
let pniUuid = UUID(data: pniRaw)
|
||||
invitee.hasInviteePni,
|
||||
let pniUuid = UUID(data: invitee.inviteePni)
|
||||
{
|
||||
return Pni(fromUUID: pniUuid)
|
||||
} else {
|
||||
@@ -452,7 +458,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupJoinRequestUpdate(let proto):
|
||||
switch unwrapAci(proto, \.requestorAci) {
|
||||
switch unwrapRequiredAci(proto, \.requestorAci) {
|
||||
case .localUser:
|
||||
return .success([.localUserRequestedToJoin])
|
||||
case .otherUser(let aci):
|
||||
@@ -462,7 +468,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupJoinRequestApprovalUpdate(let proto):
|
||||
if proto.wasApproved {
|
||||
switch (unwrapAci(proto, \.requestorAci), unwrapAci(proto, \.updaterAci)) {
|
||||
switch (unwrapRequiredAci(proto, \.requestorAci), unwrapOptionalAci(proto, \.updaterAci)) {
|
||||
case (.localUser, .unknown):
|
||||
return .success([.localUserRequestApprovedByUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -479,7 +485,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch (unwrapAci(proto, \.requestorAci), unwrapAci(proto, \.updaterAci)) {
|
||||
switch (unwrapRequiredAci(proto, \.requestorAci), unwrapOptionalAci(proto, \.updaterAci)) {
|
||||
case (.localUser, .unknown):
|
||||
return .success([.localUserRequestRejectedByUnknownUser])
|
||||
case (.localUser, .localUser):
|
||||
@@ -498,7 +504,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupJoinRequestCanceledUpdate(let proto):
|
||||
switch unwrapAci(proto, \.requestorAci) {
|
||||
switch unwrapRequiredAci(proto, \.requestorAci) {
|
||||
case .localUser:
|
||||
return .success([.localUserRequestCanceledByLocalUser])
|
||||
case .otherUser(let aci):
|
||||
@@ -507,7 +513,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupInviteLinkResetUpdate(let proto):
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkResetByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -519,7 +525,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupInviteLinkEnabledUpdate(let proto):
|
||||
if proto.linkRequiresAdminApproval {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkEnabledWithApprovalByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -530,7 +536,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkEnabledWithoutApprovalByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -543,7 +549,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
case .groupInviteLinkAdminApprovalUpdate(let proto):
|
||||
if proto.linkRequiresAdminApproval {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkApprovalEnabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -554,7 +560,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkApprovalDisabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -566,7 +572,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
case .groupInviteLinkDisabledUpdate(let proto):
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.inviteLinkDisabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -577,7 +583,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
case .groupMemberJoinedByLinkUpdate(let proto):
|
||||
switch unwrapAci(proto, \.newMemberAci) {
|
||||
switch unwrapRequiredAci(proto, \.newMemberAci) {
|
||||
case .localUser:
|
||||
return .success([.localUserJoinedViaInviteLink])
|
||||
case .otherUser(let aci):
|
||||
@@ -594,7 +600,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
case .groupV2MigrationDroppedMembersUpdate(let proto):
|
||||
return .success([.otherUsersDroppedAfterMigration(count: UInt(proto.droppedMembersCount))])
|
||||
case .groupSequenceOfRequestsAndCancelsUpdate(let proto):
|
||||
switch unwrapAci(proto, \.requestorAci) {
|
||||
switch unwrapRequiredAci(proto, \.requestorAci) {
|
||||
case .localUser:
|
||||
return .messageFailure([.restoreFrameError(
|
||||
.invalidProtoData(.sequenceOfRequestsAndCancelsWithLocalAci),
|
||||
@@ -610,7 +616,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
case .groupExpirationTimerUpdate(let proto):
|
||||
let durationMs = proto.expiresInMs
|
||||
if durationMs > 0 {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.disappearingMessagesEnabledByUnknownUser(durationMs: durationMs)])
|
||||
case .localUser:
|
||||
@@ -621,7 +627,7 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
return .messageFailure([error])
|
||||
}
|
||||
} else {
|
||||
switch unwrapAci(proto, \.updaterAci) {
|
||||
switch unwrapOptionalAci(proto, \.updaterAci) {
|
||||
case .unknown:
|
||||
return .success([.disappearingMessagesDisabledByUnknownUser])
|
||||
case .localUser:
|
||||
@@ -636,19 +642,19 @@ internal final class MessageBackupGroupUpdateProtoToSwiftConverter {
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.GroupV2AccessLevel {
|
||||
extension BackupProto_GroupV2AccessLevel {
|
||||
|
||||
fileprivate var swiftAccessLevel: GroupV2Access {
|
||||
switch self {
|
||||
case .UNKNOWN:
|
||||
case .unknown, .UNRECOGNIZED:
|
||||
return .unknown
|
||||
case .ANY:
|
||||
case .any:
|
||||
return .any
|
||||
case .MEMBER:
|
||||
case .member:
|
||||
return .member
|
||||
case .ADMINISTRATOR:
|
||||
case .administrator:
|
||||
return .administrator
|
||||
case .UNSATISFIABLE:
|
||||
case .unsatisfiable:
|
||||
return .unsatisfiable
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -180,12 +180,12 @@ final class MessageBackupChatUpdateMessageArchiver: MessageBackupInteractionArch
|
||||
// MARK: -
|
||||
|
||||
func restoreChatItem(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
) -> RestoreChatUpdateMessageResult {
|
||||
let chatUpdateMessage: BackupProto.ChatUpdateMessage
|
||||
let chatUpdateMessage: BackupProto_ChatUpdateMessage
|
||||
do {
|
||||
switch chatItem.item {
|
||||
case .updateMessage(let updateMessage):
|
||||
|
||||
@@ -77,14 +77,15 @@ final class MessageBackupExpirationTimerChatUpdateArchiver {
|
||||
chatUpdateAuthorRecipientId = recipientId
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .expirationTimerChange(BackupProto.ExpirationTimerChatUpdate(
|
||||
expiresInMs: chatUpdateExpiresInMs
|
||||
))
|
||||
var expirationTimerChatUpdate = BackupProto_ExpirationTimerChatUpdate()
|
||||
expirationTimerChatUpdate.expiresInMs = chatUpdateExpiresInMs
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .expirationTimerChange(expirationTimerChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: chatUpdateAuthorRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -97,8 +98,8 @@ final class MessageBackupExpirationTimerChatUpdateArchiver {
|
||||
// MARK: -
|
||||
|
||||
func restoreExpirationTimerChatUpdate(
|
||||
_ expirationTimerChatUpdate: BackupProto.ExpirationTimerChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ expirationTimerChatUpdate: BackupProto_ExpirationTimerChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
|
||||
@@ -51,15 +51,16 @@ final class MessageBackupProfileChangeChatUpdateArchiver {
|
||||
return messageFailure(.profileChangeUpdateMissingNames)
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .profileChange(BackupProto.ProfileChangeChatUpdate(
|
||||
previousName: oldProfileName,
|
||||
newName: newProfileName
|
||||
))
|
||||
var profileChangeChatUpdate = BackupProto_ProfileChangeChatUpdate()
|
||||
profileChangeChatUpdate.previousName = oldProfileName
|
||||
profileChangeChatUpdate.newName = newProfileName
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .profileChange(profileChangeChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: profileRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -72,8 +73,8 @@ final class MessageBackupProfileChangeChatUpdateArchiver {
|
||||
// MARK: -
|
||||
|
||||
func restoreProfileChangeChatUpdate(
|
||||
_ profileChangeChatUpdateProto: BackupProto.ProfileChangeChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ profileChangeChatUpdateProto: BackupProto_ProfileChangeChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
|
||||
@@ -51,14 +51,15 @@ final class MessageBackupSessionSwitchoverChatUpdateArchiver {
|
||||
return messageFailure(.referencedRecipientIdMissing(.contact(switchedOverContactAddress)))
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .sessionSwitchover(BackupProto.SessionSwitchoverChatUpdate(
|
||||
e164: sessionSwitchoverPhoneNumber.uint64Value
|
||||
))
|
||||
var sessionSwitchoverChatUpdate = BackupProto_SessionSwitchoverChatUpdate()
|
||||
sessionSwitchoverChatUpdate.e164 = sessionSwitchoverPhoneNumber.uint64Value
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .sessionSwitchover(sessionSwitchoverChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: threadRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -71,8 +72,8 @@ final class MessageBackupSessionSwitchoverChatUpdateArchiver {
|
||||
// MARK: -
|
||||
|
||||
func restoreSessionSwitchoverChatUpdate(
|
||||
_ sessionSwitchoverUpdateProto: BackupProto.SessionSwitchoverChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ sessionSwitchoverUpdateProto: BackupProto_SessionSwitchoverChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
@@ -89,7 +90,7 @@ final class MessageBackupSessionSwitchoverChatUpdateArchiver {
|
||||
}
|
||||
|
||||
guard let e164 = E164(sessionSwitchoverUpdateProto.e164) else {
|
||||
return invalidProtoData(.invalidE164(protoClass: BackupProto.SessionSwitchoverChatUpdate.self))
|
||||
return invalidProtoData(.invalidE164(protoClass: BackupProto_SessionSwitchoverChatUpdate.self))
|
||||
}
|
||||
|
||||
guard case .contact(let switchedOverContactThread) = chatThread.threadType else {
|
||||
|
||||
@@ -53,7 +53,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
}
|
||||
|
||||
let updateAuthor: UpdateAuthor
|
||||
let updateType: BackupProto.SimpleChatUpdate.Type_
|
||||
let updateType: BackupProto_SimpleChatUpdate.TypeEnum
|
||||
|
||||
switch infoMessage.messageType {
|
||||
case
|
||||
@@ -99,9 +99,9 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
|
||||
switch verificationStateChangeMessage.verificationState {
|
||||
case .default, .defaultAcknowledged, .noLongerVerified:
|
||||
updateType = .IDENTITY_DEFAULT
|
||||
updateType = .identityDefault
|
||||
case .verified:
|
||||
updateType = .IDENTITY_VERIFIED
|
||||
updateType = .identityVerified
|
||||
}
|
||||
case .phoneNumberChange:
|
||||
guard let changedNumberUserAci = infoMessage.phoneNumberChangeInfo()?.aci else {
|
||||
@@ -114,7 +114,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
}
|
||||
|
||||
updateAuthor = .precomputedRecipientId(recipientId)
|
||||
updateType = .CHANGE_NUMBER
|
||||
updateType = .changeNumber
|
||||
case .paymentsActivationRequest:
|
||||
switch infoMessage.paymentsActivationRequestAuthor(localIdentifiers: context.recipientContext.localIdentifiers) {
|
||||
case nil:
|
||||
@@ -130,7 +130,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
updateAuthor = .precomputedRecipientId(authorRecipientId)
|
||||
}
|
||||
|
||||
updateType = .PAYMENT_ACTIVATION_REQUEST
|
||||
updateType = .paymentActivationRequest
|
||||
case .paymentsActivated:
|
||||
switch infoMessage.paymentsActivatedAuthor(localIdentifiers: context.recipientContext.localIdentifiers) {
|
||||
case nil:
|
||||
@@ -146,7 +146,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
updateAuthor = .precomputedRecipientId(authorRecipientId)
|
||||
}
|
||||
|
||||
updateType = .PAYMENTS_ACTIVATED
|
||||
updateType = .paymentsActivated
|
||||
case .unknownProtocolVersion:
|
||||
guard let unknownProtocolVersionMessage = infoMessage as? OWSUnknownProtocolVersionMessage else {
|
||||
return messageFailure(.unknownProtocolVersionNotExpectedSDSRecordType)
|
||||
@@ -167,21 +167,21 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
updateAuthor = .localUser
|
||||
}
|
||||
|
||||
updateType = .UNSUPPORTED_PROTOCOL_MESSAGE
|
||||
updateType = .unsupportedProtocolMessage
|
||||
case .typeSessionDidEnd:
|
||||
// Only inserted for 1:1 threads.
|
||||
updateAuthor = .containingContactThread
|
||||
updateType = .END_SESSION
|
||||
updateType = .endSession
|
||||
case .userJoinedSignal:
|
||||
// Only inserted for 1:1 threads.
|
||||
updateAuthor = .containingContactThread
|
||||
updateType = .JOINED_SIGNAL
|
||||
updateType = .joinedSignal
|
||||
case .reportedSpam:
|
||||
// The reported-spam info message doesn't contain any info as to
|
||||
// what message we reported spam. Regardless, we were the one to
|
||||
// take this action, so we're the author.
|
||||
updateAuthor = .localUser
|
||||
updateType = .REPORTED_SPAM
|
||||
updateType = .reportedSpam
|
||||
}
|
||||
|
||||
let updateAuthorRecipientId: MessageBackup.RecipientId
|
||||
@@ -204,12 +204,15 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
updateAuthorRecipientId = context.recipientContext.localRecipientId
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .simpleUpdate(BackupProto.SimpleChatUpdate(type: updateType))
|
||||
var simpleChatUpdate = BackupProto_SimpleChatUpdate()
|
||||
simpleChatUpdate.type = updateType
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .simpleUpdate(simpleChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: updateAuthorRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -237,7 +240,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
}
|
||||
|
||||
let updateAuthor: MessageBackup.ContactAddress
|
||||
let updateType: BackupProto.SimpleChatUpdate.Type_
|
||||
let updateType: BackupProto_SimpleChatUpdate.TypeEnum
|
||||
|
||||
switch errorMessage.errorType {
|
||||
case .noSession:
|
||||
@@ -265,7 +268,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
return messageFailure(.identityKeyChangeInteractionMissingAuthor)
|
||||
}
|
||||
|
||||
updateType = .IDENTITY_UPDATE
|
||||
updateType = .identityUpdate
|
||||
updateAuthor = recipientAddress
|
||||
case .sessionRefresh:
|
||||
/// These can only happen in contact threads, not group threads.
|
||||
@@ -278,7 +281,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
return messageFailure(.sessionRefreshInteractionMissingAuthor)
|
||||
}
|
||||
|
||||
updateType = .CHAT_SESSION_REFRESH
|
||||
updateType = .chatSessionRefresh
|
||||
updateAuthor = recipientAddress
|
||||
case .decryptionFailure:
|
||||
/// This type of error message historically put the person who sent
|
||||
@@ -287,7 +290,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
return messageFailure(.decryptionErrorInteractionMissingAuthor)
|
||||
}
|
||||
|
||||
updateType = .BAD_DECRYPT
|
||||
updateType = .badDecrypt
|
||||
updateAuthor = recipientAddress
|
||||
}
|
||||
|
||||
@@ -295,12 +298,15 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
return messageFailure(.referencedRecipientIdMissing(.contact(updateAuthor)))
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .simpleUpdate(BackupProto.SimpleChatUpdate(type: updateType))
|
||||
var simpleChatUpdate = BackupProto_SimpleChatUpdate()
|
||||
simpleChatUpdate.type = updateType
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .simpleUpdate(simpleChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: updateAuthorRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -313,8 +319,8 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
// MARK: -
|
||||
|
||||
func restoreSimpleChatUpdate(
|
||||
_ simpleChatUpdate: BackupProto.SimpleChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ simpleChatUpdate: BackupProto_SimpleChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
@@ -340,11 +346,11 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
let simpleChatUpdateInteraction: SimpleChatUpdateInteraction
|
||||
|
||||
switch simpleChatUpdate.type {
|
||||
case .UNKNOWN:
|
||||
case .unknown, .UNRECOGNIZED:
|
||||
return invalidProtoData(.unrecognizedSimpleChatUpdate)
|
||||
case .JOINED_SIGNAL:
|
||||
case .joinedSignal:
|
||||
simpleChatUpdateInteraction = .simpleInfoMessage(.userJoinedSignal)
|
||||
case .IDENTITY_UPDATE:
|
||||
case .identityUpdate:
|
||||
guard let verificationRecipient = context.recipientContext[chatItem.authorRecipientId] else {
|
||||
return invalidProtoData(.recipientIdNotFound(chatItem.authorRecipientId))
|
||||
}
|
||||
@@ -362,7 +368,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
// backup and it only affects the action shown for the message.
|
||||
wasIdentityVerified: false
|
||||
))
|
||||
case .IDENTITY_VERIFIED, .IDENTITY_DEFAULT:
|
||||
case .identityVerified, .identityDefault:
|
||||
guard let verificationRecipient = context.recipientContext[chatItem.authorRecipientId] else {
|
||||
return invalidProtoData(.recipientIdNotFound(chatItem.authorRecipientId))
|
||||
}
|
||||
@@ -371,8 +377,8 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
}
|
||||
|
||||
let verificationState: OWSVerificationState = switch simpleChatUpdate.type {
|
||||
case .IDENTITY_VERIFIED: .verified
|
||||
case .IDENTITY_DEFAULT: .default
|
||||
case .identityVerified: .verified
|
||||
case .identityDefault: .default
|
||||
default: owsFail("Impossible: checked above.")
|
||||
}
|
||||
|
||||
@@ -387,7 +393,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
// message is displayed.
|
||||
isLocalChange: true
|
||||
))
|
||||
case .CHANGE_NUMBER:
|
||||
case .changeNumber:
|
||||
guard let verificationRecipient = context.recipientContext[chatItem.authorRecipientId] else {
|
||||
return invalidProtoData(.recipientIdNotFound(chatItem.authorRecipientId))
|
||||
}
|
||||
@@ -402,17 +408,17 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
changeNumberInfoMessage.setPhoneNumberChangeInfo(aci: aci, oldNumber: nil, newNumber: nil)
|
||||
|
||||
simpleChatUpdateInteraction = .prebuiltInfoMessage(changeNumberInfoMessage)
|
||||
case .RELEASE_CHANNEL_DONATION_REQUEST:
|
||||
case .releaseChannelDonationRequest:
|
||||
// TODO: [Backups] Add support (and a test case!) for this once we've implemented the Release Notes channel.
|
||||
logger.warn("Encountered not-yet-supported release-channel-donation-request update")
|
||||
return .success(())
|
||||
case .END_SESSION:
|
||||
case .endSession:
|
||||
simpleChatUpdateInteraction = .simpleInfoMessage(.typeSessionDidEnd)
|
||||
case .CHAT_SESSION_REFRESH:
|
||||
case .chatSessionRefresh:
|
||||
simpleChatUpdateInteraction = .errorMessage(TSErrorMessage.sessionRefresh(
|
||||
in: thread
|
||||
))
|
||||
case .BAD_DECRYPT:
|
||||
case .badDecrypt:
|
||||
guard let senderRecipient = context.recipientContext[chatItem.authorRecipientId] else {
|
||||
return invalidProtoData(.recipientIdNotFound(chatItem.authorRecipientId))
|
||||
}
|
||||
@@ -425,7 +431,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
thread: thread,
|
||||
timestamp: chatItem.dateSent
|
||||
))
|
||||
case .PAYMENTS_ACTIVATED:
|
||||
case .paymentsActivated:
|
||||
let senderAci: Aci
|
||||
switch context.recipientContext[chatItem.authorRecipientId] {
|
||||
case nil:
|
||||
@@ -443,7 +449,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
thread: thread,
|
||||
senderAci: senderAci
|
||||
))
|
||||
case .PAYMENT_ACTIVATION_REQUEST:
|
||||
case .paymentActivationRequest:
|
||||
let senderAci: Aci
|
||||
switch context.recipientContext[chatItem.authorRecipientId] {
|
||||
case nil:
|
||||
@@ -461,7 +467,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
thread: thread,
|
||||
senderAci: senderAci
|
||||
))
|
||||
case .UNSUPPORTED_PROTOCOL_MESSAGE:
|
||||
case .unsupportedProtocolMessage:
|
||||
let senderAddress: SignalServiceAddress?
|
||||
switch context.recipientContext[chatItem.authorRecipientId] {
|
||||
case nil:
|
||||
@@ -483,7 +489,7 @@ final class MessageBackupSimpleChatUpdateArchiver {
|
||||
// will always show "unknown protocol version", but that's fine.
|
||||
protocolVersion: UInt(Int64.max)
|
||||
))
|
||||
case .REPORTED_SPAM:
|
||||
case .reportedSpam:
|
||||
simpleChatUpdateInteraction = .simpleInfoMessage(.reportedSpam)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,14 +51,15 @@ final class MessageBackupThreadMergeChatUpdateArchiver {
|
||||
return messageFailure(.referencedRecipientIdMissing(.contact(mergedContactAddress)))
|
||||
}
|
||||
|
||||
var chatUpdateMessage = BackupProto.ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .threadMerge(BackupProto.ThreadMergeChatUpdate(
|
||||
previousE164: threadMergePhoneNumber.uint64Value
|
||||
))
|
||||
var threadMergeChatUpdate = BackupProto_ThreadMergeChatUpdate()
|
||||
threadMergeChatUpdate.previousE164 = threadMergePhoneNumber.uint64Value
|
||||
|
||||
var chatUpdateMessage = BackupProto_ChatUpdateMessage()
|
||||
chatUpdateMessage.update = .threadMerge(threadMergeChatUpdate)
|
||||
|
||||
let interactionArchiveDetails = Details(
|
||||
author: threadRecipientId,
|
||||
directionalDetails: .directionless(BackupProto.ChatItem.DirectionlessMessageDetails()),
|
||||
directionalDetails: .directionless(BackupProto_ChatItem.DirectionlessMessageDetails()),
|
||||
expireStartDate: nil,
|
||||
expiresInMs: nil,
|
||||
isSealedSender: false,
|
||||
@@ -71,8 +72,8 @@ final class MessageBackupThreadMergeChatUpdateArchiver {
|
||||
// MARK: -
|
||||
|
||||
func restoreThreadMergeChatUpdate(
|
||||
_ threadMergeUpdateProto: BackupProto.ThreadMergeChatUpdate,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
_ threadMergeUpdateProto: BackupProto_ThreadMergeChatUpdate,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
@@ -89,7 +90,7 @@ final class MessageBackupThreadMergeChatUpdateArchiver {
|
||||
}
|
||||
|
||||
guard let previousE164 = E164(threadMergeUpdateProto.previousE164) else {
|
||||
return invalidProtoData(.invalidE164(protoClass: BackupProto.ThreadMergeChatUpdate.self))
|
||||
return invalidProtoData(.invalidE164(protoClass: BackupProto_ThreadMergeChatUpdate.self))
|
||||
}
|
||||
|
||||
guard case .contact(let mergedThread) = chatThread.threadType else {
|
||||
|
||||
@@ -8,11 +8,11 @@ import LibSignalClient
|
||||
|
||||
public extension MessageBackup {
|
||||
|
||||
/// An identifier for a ``BackupProto.ChatItem`` backup frame.
|
||||
/// An identifier for a ``BackupProto_ChatItem`` backup frame.
|
||||
struct ChatItemId: MessageBackupLoggableId, Hashable {
|
||||
let value: UInt64
|
||||
|
||||
public init(backupProtoChatItem: BackupProto.ChatItem) {
|
||||
public init(backupProtoChatItem: BackupProto_ChatItem) {
|
||||
self.value = backupProtoChatItem.dateSent
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public extension MessageBackup {
|
||||
|
||||
// MARK: MessageBackupLoggableId
|
||||
|
||||
public var typeLogString: String { "BackupProto.ChatItem" }
|
||||
public var typeLogString: String { "BackupProto_ChatItem" }
|
||||
public var idLogString: String { "timestamp: \(value)" }
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public protocol MessageBackupChatItemArchiver: MessageBackupProtoArchiver {
|
||||
typealias ArchiveMultiFrameResult = MessageBackup.ArchiveMultiFrameResult<MessageBackup.InteractionUniqueId>
|
||||
typealias RestoreFrameResult = MessageBackup.RestoreFrameResult<ChatItemId>
|
||||
|
||||
/// Archive all ``TSInteraction``s (they map to ``BackupProto.ChatItem`` and ``BackupProto.Call``).
|
||||
/// Archive all ``TSInteraction``s (they map to ``BackupProto_ChatItem`` and ``BackupProto_Call``).
|
||||
///
|
||||
/// - Returns: ``ArchiveMultiFrameResult.success`` if all frames were written without error, or either
|
||||
/// partial or complete failure otherwise.
|
||||
@@ -47,13 +47,13 @@ public protocol MessageBackupChatItemArchiver: MessageBackupProtoArchiver {
|
||||
tx: DBReadTransaction
|
||||
) -> ArchiveMultiFrameResult
|
||||
|
||||
/// Restore a single ``BackupProto.ChatItem`` frame.
|
||||
/// Restore a single ``BackupProto_ChatItem`` frame.
|
||||
///
|
||||
/// - Returns: ``RestoreFrameResult.success`` if all frames were read without error.
|
||||
/// How to handle ``RestoreFrameResult.failure`` is up to the caller,
|
||||
/// but typically an error will be shown to the user, but the restore will be allowed to proceed.
|
||||
func restore(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult
|
||||
|
||||
@@ -215,14 +215,13 @@ public class MessageBackupChatItemArchiverImpl: MessageBackupChatItemArchiver {
|
||||
return .success
|
||||
}
|
||||
|
||||
var chatItem = BackupProto.ChatItem(
|
||||
chatId: chatId.value,
|
||||
authorId: details.author.value,
|
||||
dateSent: interaction.timestamp,
|
||||
expireStartDate: details.expireStartDate ?? 0,
|
||||
expiresInMs: details.expiresInMs ?? 0,
|
||||
sms: details.isSms
|
||||
)
|
||||
var chatItem = BackupProto_ChatItem()
|
||||
chatItem.chatID = chatId.value
|
||||
chatItem.authorID = details.author.value
|
||||
chatItem.dateSent = interaction.timestamp
|
||||
chatItem.expireStartDate = details.expireStartDate ?? 0
|
||||
chatItem.expiresInMs = details.expiresInMs ?? 0
|
||||
chatItem.sms = details.isSms
|
||||
chatItem.item = details.chatItemType
|
||||
chatItem.directionalDetails = details.directionalDetails
|
||||
chatItem.revisions = details.revisions
|
||||
@@ -231,7 +230,7 @@ public class MessageBackupChatItemArchiverImpl: MessageBackupChatItemArchiver {
|
||||
stream,
|
||||
objectId: interaction.uniqueInteractionId
|
||||
) {
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .chatItem(chatItem)
|
||||
return frame
|
||||
}
|
||||
@@ -247,7 +246,7 @@ public class MessageBackupChatItemArchiverImpl: MessageBackupChatItemArchiver {
|
||||
}
|
||||
|
||||
public func restore(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
|
||||
@@ -20,15 +20,15 @@ extension MessageBackup {
|
||||
}
|
||||
|
||||
struct InteractionArchiveDetails {
|
||||
typealias DirectionalDetails = BackupProto.ChatItem.DirectionalDetails
|
||||
typealias ChatItemType = BackupProto.ChatItem.Item
|
||||
typealias DirectionalDetails = BackupProto_ChatItem.OneOf_DirectionalDetails
|
||||
typealias ChatItemType = BackupProto_ChatItem.OneOf_Item
|
||||
|
||||
let author: RecipientId
|
||||
let directionalDetails: DirectionalDetails
|
||||
let expireStartDate: UInt64?
|
||||
let expiresInMs: UInt64?
|
||||
// TODO: [Backups] Include edit revisions.
|
||||
let revisions: [BackupProto.ChatItem] = []
|
||||
let revisions: [BackupProto_ChatItem] = []
|
||||
// TODO: [Backups] Properly set isSms. This will only be relevant for messages we previously restored from an Android.
|
||||
let isSms: Bool = false
|
||||
let isSealedSender: Bool
|
||||
@@ -166,7 +166,7 @@ internal protocol MessageBackupInteractionArchiver: MessageBackupProtoArchiver {
|
||||
) -> MessageBackup.ArchiveInteractionResult<Details>
|
||||
|
||||
func restoreChatItem(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
@@ -301,7 +301,7 @@ extension MessageBackup.RestoreInteractionResult where Component == Void {
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.ChatItem {
|
||||
extension BackupProto_ChatItem {
|
||||
|
||||
var id: MessageBackup.ChatItemId {
|
||||
return .init(backupProtoChatItem: self)
|
||||
|
||||
@@ -21,11 +21,11 @@ internal class MessageBackupReactionArchiver: MessageBackupProtoArchiver {
|
||||
_ message: TSMessage,
|
||||
context: MessageBackup.RecipientArchivingContext,
|
||||
tx: DBReadTransaction
|
||||
) -> MessageBackup.ArchiveInteractionResult<[BackupProto.Reaction]> {
|
||||
) -> MessageBackup.ArchiveInteractionResult<[BackupProto_Reaction]> {
|
||||
let reactions = reactionStore.allReactions(messageId: message.uniqueId, tx: tx)
|
||||
|
||||
var errors = [ArchiveFrameError]()
|
||||
var reactionProtos = [BackupProto.Reaction]()
|
||||
var reactionProtos = [BackupProto_Reaction]()
|
||||
|
||||
for reaction in reactions {
|
||||
guard
|
||||
@@ -47,14 +47,13 @@ internal class MessageBackupReactionArchiver: MessageBackupProtoArchiver {
|
||||
continue
|
||||
}
|
||||
|
||||
let reaction = BackupProto.Reaction(
|
||||
emoji: reaction.emoji,
|
||||
authorId: authorId.value,
|
||||
sentTimestamp: reaction.sentAtTimestamp,
|
||||
sortOrder: reaction.sortOrder
|
||||
)
|
||||
var reactionProto = BackupProto_Reaction()
|
||||
reactionProto.emoji = reaction.emoji
|
||||
reactionProto.authorID = authorId.value
|
||||
reactionProto.sentTimestamp = reaction.sentAtTimestamp
|
||||
reactionProto.sortOrder = reaction.sortOrder
|
||||
|
||||
reactionProtos.append(reaction)
|
||||
reactionProtos.append(reactionProto)
|
||||
}
|
||||
|
||||
if errors.isEmpty {
|
||||
@@ -67,7 +66,7 @@ internal class MessageBackupReactionArchiver: MessageBackupProtoArchiver {
|
||||
// MARK: Restoring
|
||||
|
||||
func restoreReactions(
|
||||
_ reactions: [BackupProto.Reaction],
|
||||
_ reactions: [BackupProto_Reaction],
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
message: TSMessage,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
|
||||
@@ -93,12 +93,11 @@ internal class MessageBackupTSIncomingMessageArchiver: MessageBackupInteractionA
|
||||
private func buildIncomingMessageDetails(
|
||||
_ message: TSIncomingMessage
|
||||
) -> MessageBackup.ArchiveInteractionResult<Details.DirectionalDetails> {
|
||||
let incomingMessage = BackupProto.ChatItem.IncomingMessageDetails(
|
||||
dateReceived: message.receivedAtTimestamp,
|
||||
dateServerSent: message.serverDeliveryTimestamp,
|
||||
read: message.wasRead,
|
||||
sealedSender: message.wasReceivedByUD
|
||||
)
|
||||
var incomingMessage = BackupProto_ChatItem.IncomingMessageDetails()
|
||||
incomingMessage.dateReceived = message.receivedAtTimestamp
|
||||
incomingMessage.dateServerSent = message.serverDeliveryTimestamp
|
||||
incomingMessage.read = message.wasRead
|
||||
incomingMessage.sealedSender = message.wasReceivedByUD
|
||||
|
||||
return .success(.incoming(incomingMessage))
|
||||
}
|
||||
@@ -106,12 +105,12 @@ internal class MessageBackupTSIncomingMessageArchiver: MessageBackupInteractionA
|
||||
// MARK: - Restoring
|
||||
|
||||
func restoreChatItem(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreInteractionResult<Void> {
|
||||
let incomingDetails: BackupProto.ChatItem.IncomingMessageDetails
|
||||
let incomingDetails: BackupProto_ChatItem.IncomingMessageDetails
|
||||
switch chatItem.directionalDetails {
|
||||
case .incoming(let incomingMessageDetails):
|
||||
incomingDetails = incomingMessageDetails
|
||||
|
||||
@@ -28,13 +28,13 @@ extension MessageBackup {
|
||||
// construct objects that are parsed from the backup proto but require
|
||||
// the TSMessage to exist first before they can be created/inserted.
|
||||
|
||||
fileprivate let reactions: [BackupProto.Reaction]
|
||||
fileprivate let reactions: [BackupProto_Reaction]
|
||||
}
|
||||
|
||||
struct Payment {
|
||||
enum Status {
|
||||
case success(BackupProto.PaymentNotification.TransactionDetails.Transaction.Status)
|
||||
case failure(BackupProto.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason)
|
||||
case success(BackupProto_PaymentNotification.TransactionDetails.Transaction.Status)
|
||||
case failure(BackupProto_PaymentNotification.TransactionDetails.FailedTransaction.FailureReason)
|
||||
}
|
||||
|
||||
let amount: String?
|
||||
@@ -42,7 +42,7 @@ extension MessageBackup {
|
||||
let note: String?
|
||||
|
||||
fileprivate let status: Status
|
||||
fileprivate let payment: BackupProto.PaymentNotification.TransactionDetails.Transaction?
|
||||
fileprivate let payment: BackupProto_PaymentNotification.TransactionDetails.Transaction?
|
||||
}
|
||||
|
||||
case text(Text)
|
||||
@@ -135,12 +135,12 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
context: MessageBackup.RecipientArchivingContext,
|
||||
tx: DBReadTransaction
|
||||
) -> ArchiveInteractionResult<ChatItemType> {
|
||||
var standardMessage = BackupProto.StandardMessage()
|
||||
var standardMessage = BackupProto_StandardMessage()
|
||||
var partialErrors = [ArchiveFrameError]()
|
||||
|
||||
let text: BackupProto.Text
|
||||
let text: BackupProto_Text
|
||||
let textResult = archiveText(
|
||||
.init(text: messageBody, ranges: message.bodyRanges ?? .empty),
|
||||
MessageBody(text: messageBody, ranges: message.bodyRanges ?? .empty),
|
||||
interactionUniqueId: message.uniqueInteractionId
|
||||
)
|
||||
switch textResult.bubbleUp(ChatItemType.self, partialErrors: &partialErrors) {
|
||||
@@ -151,25 +151,24 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
standardMessage.text = text
|
||||
|
||||
let quote: BackupProto.Quote?
|
||||
if let quotedMessage = message.quotedMessage {
|
||||
let quote: BackupProto_Quote
|
||||
let quoteResult = archiveQuote(
|
||||
quotedMessage,
|
||||
interactionUniqueId: message.uniqueInteractionId,
|
||||
context: context
|
||||
)
|
||||
switch quoteResult.bubbleUp(ChatItemType.self, partialErrors: &partialErrors) {
|
||||
case .continue(let value):
|
||||
quote = value
|
||||
case .continue(let _quote):
|
||||
quote = _quote
|
||||
case .bubbleUpError(let errorResult):
|
||||
return errorResult
|
||||
}
|
||||
} else {
|
||||
quote = nil
|
||||
}
|
||||
standardMessage.quote = quote
|
||||
|
||||
let reactions: [BackupProto.Reaction]
|
||||
standardMessage.quote = quote
|
||||
}
|
||||
|
||||
let reactions: [BackupProto_Reaction]
|
||||
let reactionsResult = reactionArchiver.archiveReactions(
|
||||
message,
|
||||
context: context,
|
||||
@@ -200,10 +199,16 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
return .messageFailure([.archiveFrameError(.missingPaymentInformation, uniqueInteractionId)])
|
||||
}
|
||||
|
||||
var paymentNotificationProto = BackupProto.PaymentNotification()
|
||||
paymentNotificationProto.amountMob = archivedPaymentMessage.archivedPaymentInfo.amount
|
||||
paymentNotificationProto.feeMob = archivedPaymentMessage.archivedPaymentInfo.fee
|
||||
paymentNotificationProto.note = archivedPaymentMessage.archivedPaymentInfo.note
|
||||
var paymentNotificationProto = BackupProto_PaymentNotification()
|
||||
if let amount = archivedPaymentMessage.archivedPaymentInfo.amount {
|
||||
paymentNotificationProto.amountMob = amount
|
||||
}
|
||||
if let fee = archivedPaymentMessage.archivedPaymentInfo.fee {
|
||||
paymentNotificationProto.feeMob = fee
|
||||
}
|
||||
if let note = archivedPaymentMessage.archivedPaymentInfo.note {
|
||||
paymentNotificationProto.note = note
|
||||
}
|
||||
paymentNotificationProto.transactionDetails = historyItem.toTransactionDetailsProto()
|
||||
|
||||
return .success(.paymentNotification(paymentNotificationProto))
|
||||
@@ -225,21 +230,29 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
return .messageFailure([.archiveFrameError(.missingPaymentInformation, uniqueInteractionId)])
|
||||
}
|
||||
|
||||
var paymentNotificationProto = BackupProto.PaymentNotification()
|
||||
var paymentNotificationProto = BackupProto_PaymentNotification()
|
||||
|
||||
if let amount = model.paymentAmount {
|
||||
paymentNotificationProto.amountMob = PaymentsFormat.format(
|
||||
if
|
||||
let amount = model.paymentAmount,
|
||||
let amountString = PaymentsFormat.format(
|
||||
picoMob: amount.picoMob,
|
||||
isShortForm: true
|
||||
)
|
||||
{
|
||||
paymentNotificationProto.amountMob = amountString
|
||||
}
|
||||
if let fee = model.mobileCoin?.feeAmount {
|
||||
paymentNotificationProto.feeMob = PaymentsFormat.format(
|
||||
if
|
||||
let fee = model.mobileCoin?.feeAmount,
|
||||
let feeString = PaymentsFormat.format(
|
||||
picoMob: fee.picoMob,
|
||||
isShortForm: true
|
||||
)
|
||||
{
|
||||
paymentNotificationProto.feeMob = feeString
|
||||
}
|
||||
if let memoMessage = paymentNotification.memoMessage {
|
||||
paymentNotificationProto.note = memoMessage
|
||||
}
|
||||
paymentNotificationProto.note = paymentNotification.memoMessage
|
||||
paymentNotificationProto.transactionDetails = model.asArchivedPayment().toTransactionDetailsProto()
|
||||
|
||||
return .success(.paymentNotification(paymentNotificationProto))
|
||||
@@ -248,11 +261,12 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
private func archiveText(
|
||||
_ messageBody: MessageBody,
|
||||
interactionUniqueId: MessageBackup.InteractionUniqueId
|
||||
) -> ArchiveInteractionResult<BackupProto.Text> {
|
||||
var text = BackupProto.Text(body: messageBody.text)
|
||||
) -> ArchiveInteractionResult<BackupProto_Text> {
|
||||
var text = BackupProto_Text()
|
||||
text.body = messageBody.text
|
||||
|
||||
for bodyRangeParam in messageBody.ranges.toProtoBodyRanges() {
|
||||
var bodyRange = BackupProto.BodyRange()
|
||||
var bodyRange = BackupProto_BodyRange()
|
||||
bodyRange.start = bodyRangeParam.start
|
||||
bodyRange.length = bodyRangeParam.length
|
||||
|
||||
@@ -261,14 +275,14 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
mentionAci.serviceIdBinary.asData
|
||||
)
|
||||
} else if let style = bodyRangeParam.style {
|
||||
let backupProtoStyle: BackupProto.BodyRange.Style = {
|
||||
let backupProtoStyle: BackupProto_BodyRange.Style = {
|
||||
switch style {
|
||||
case .none: return .NONE
|
||||
case .bold: return .BOLD
|
||||
case .italic: return .ITALIC
|
||||
case .spoiler: return .SPOILER
|
||||
case .strikethrough: return .STRIKETHROUGH
|
||||
case .monospace: return .MONOSPACE
|
||||
case .none: return .none
|
||||
case .bold: return .bold
|
||||
case .italic: return .italic
|
||||
case .spoiler: return .spoiler
|
||||
case .strikethrough: return .strikethrough
|
||||
case .monospace: return .monospace
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -285,7 +299,7 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
_ quotedMessage: TSQuotedMessage,
|
||||
interactionUniqueId: MessageBackup.InteractionUniqueId,
|
||||
context: MessageBackup.RecipientArchivingContext
|
||||
) -> ArchiveInteractionResult<BackupProto.Quote> {
|
||||
) -> ArchiveInteractionResult<BackupProto_Quote> {
|
||||
var partialErrors = [ArchiveFrameError]()
|
||||
|
||||
guard let authorAddress = quotedMessage.authorAddress.asSingleServiceIdBackupAddress() else {
|
||||
@@ -300,19 +314,20 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
)])
|
||||
}
|
||||
|
||||
var quote = BackupProto.Quote(
|
||||
authorId: authorId.value,
|
||||
type: quotedMessage.isGiftBadge ? .GIFTBADGE : .NORMAL
|
||||
)
|
||||
quote.targetSentTimestamp = quotedMessage.timestampValue?.uint64Value
|
||||
var quote = BackupProto_Quote()
|
||||
quote.authorID = authorId.value
|
||||
quote.type = quotedMessage.isGiftBadge ? .giftbadge : .normal
|
||||
if let targetSentTimestamp = quotedMessage.timestampValue?.uint64Value {
|
||||
quote.targetSentTimestamp = targetSentTimestamp
|
||||
}
|
||||
|
||||
if let body = quotedMessage.body {
|
||||
let textResult = archiveText(
|
||||
.init(text: body, ranges: quotedMessage.bodyRanges ?? .empty),
|
||||
MessageBody(text: body, ranges: quotedMessage.bodyRanges ?? .empty),
|
||||
interactionUniqueId: interactionUniqueId
|
||||
)
|
||||
let text: BackupProto.Text
|
||||
switch textResult.bubbleUp(BackupProto.Quote.self, partialErrors: &partialErrors) {
|
||||
let text: BackupProto_Text
|
||||
switch textResult.bubbleUp(BackupProto_Quote.self, partialErrors: &partialErrors) {
|
||||
case .continue(let value):
|
||||
text = value
|
||||
case .bubbleUpError(let errorResult):
|
||||
@@ -457,28 +472,33 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
|
||||
private func restorePaymentNotification(
|
||||
_ paymentNotification: BackupProto.PaymentNotification,
|
||||
_ paymentNotification: BackupProto_PaymentNotification,
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
thread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBReadTransaction
|
||||
) -> RestoreInteractionResult<MessageBackup.RestoredMessageContents> {
|
||||
let status: MessageBackup.RestoredMessageContents.Payment.Status
|
||||
let paymentTransaction: BackupProto.PaymentNotification.TransactionDetails.Transaction?
|
||||
switch paymentNotification.transactionDetails?.payment {
|
||||
case .failedTransaction(let failedTransaction):
|
||||
status = .failure(failedTransaction.reason)
|
||||
paymentTransaction = nil
|
||||
case .transaction(let payment):
|
||||
status = .success(payment.status)
|
||||
paymentTransaction = payment
|
||||
case .none:
|
||||
let paymentTransaction: BackupProto_PaymentNotification.TransactionDetails.Transaction?
|
||||
if
|
||||
paymentNotification.hasTransactionDetails,
|
||||
let paymentDetails = paymentNotification.transactionDetails.payment
|
||||
{
|
||||
switch paymentDetails {
|
||||
case .failedTransaction(let failedTransaction):
|
||||
status = .failure(failedTransaction.reason)
|
||||
paymentTransaction = nil
|
||||
case .transaction(let payment):
|
||||
status = .success(payment.status)
|
||||
paymentTransaction = payment
|
||||
}
|
||||
} else {
|
||||
// Default to 'success' if there is no included information
|
||||
status = .success(.SUCCESSFUL)
|
||||
status = .success(.successful)
|
||||
paymentTransaction = nil
|
||||
}
|
||||
|
||||
return .success(.archivedPayment(.init(
|
||||
return .success(.archivedPayment(MessageBackup.RestoredMessageContents.Payment(
|
||||
amount: paymentNotification.amountMob,
|
||||
fee: paymentNotification.feeMob,
|
||||
note: paymentNotification.note,
|
||||
@@ -488,7 +508,7 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
|
||||
private func restoreStandardMessage(
|
||||
_ standardMessage: BackupProto.StandardMessage,
|
||||
_ standardMessage: BackupProto_StandardMessage,
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
@@ -497,10 +517,10 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
var partialErrors = [RestoreFrameError]()
|
||||
|
||||
let quotedMessage: TSQuotedMessage?
|
||||
if let quoteProto = standardMessage.quote {
|
||||
if standardMessage.hasQuote {
|
||||
guard
|
||||
let quoteResult = restoreQuote(
|
||||
quoteProto,
|
||||
standardMessage.quote,
|
||||
chatItemId: chatItemId,
|
||||
thread: chatThread,
|
||||
context: context,
|
||||
@@ -514,10 +534,11 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
quotedMessage = nil
|
||||
}
|
||||
|
||||
guard let text = standardMessage.text else {
|
||||
guard standardMessage.hasText else {
|
||||
// TODO: [Backups] Support messages with no text
|
||||
return .messageFailure([.restoreFrameError(.unimplemented, chatItemId)])
|
||||
}
|
||||
let text = standardMessage.text
|
||||
|
||||
let messageBodyResult = restoreMessageBody(text, chatItemId: chatItemId)
|
||||
switch messageBodyResult {
|
||||
@@ -542,7 +563,7 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
|
||||
func restoreMessageBody(
|
||||
_ text: BackupProto.Text,
|
||||
_ text: BackupProto_Text,
|
||||
chatItemId: MessageBackup.ChatItemId
|
||||
) -> RestoreInteractionResult<MessageBody> {
|
||||
return restoreMessageBody(
|
||||
@@ -554,23 +575,25 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
|
||||
private func restoreMessageBody(
|
||||
text: String,
|
||||
bodyRangeProtos: [BackupProto.BodyRange],
|
||||
bodyRangeProtos: [BackupProto_BodyRange],
|
||||
chatItemId: MessageBackup.ChatItemId
|
||||
) -> RestoreInteractionResult<MessageBody> {
|
||||
var partialErrors = [RestoreFrameError]()
|
||||
var bodyMentions = [NSRange: Aci]()
|
||||
var bodyStyles = [NSRangedValue<MessageBodyRanges.SingleStyle>]()
|
||||
for bodyRange in bodyRangeProtos {
|
||||
guard let bodyRangeStart = bodyRange.start, let bodyRangeLength = bodyRange.length else {
|
||||
guard bodyRange.hasStart, bodyRange.hasLength else {
|
||||
continue
|
||||
}
|
||||
let bodyRangeStart = bodyRange.start
|
||||
let bodyRangeLength = bodyRange.length
|
||||
|
||||
let range = NSRange(location: Int(bodyRangeStart), length: Int(bodyRangeLength))
|
||||
switch bodyRange.associatedValue {
|
||||
case .mentionAci(let aciData):
|
||||
guard let mentionAci = try? Aci.parseFrom(serviceIdBinary: aciData) else {
|
||||
partialErrors.append(.restoreFrameError(
|
||||
.invalidProtoData(.invalidAci(protoClass: BackupProto.BodyRange.self)),
|
||||
.invalidProtoData(.invalidAci(protoClass: BackupProto_BodyRange.self)),
|
||||
chatItemId
|
||||
))
|
||||
continue
|
||||
@@ -579,27 +602,27 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
case .style(let protoBodyRangeStyle):
|
||||
let swiftStyle: MessageBodyRanges.SingleStyle
|
||||
switch protoBodyRangeStyle {
|
||||
case .NONE:
|
||||
case .none, .UNRECOGNIZED:
|
||||
partialErrors.append(.restoreFrameError(
|
||||
.invalidProtoData(.unrecognizedBodyRangeStyle),
|
||||
chatItemId
|
||||
))
|
||||
continue
|
||||
case .BOLD:
|
||||
case .bold:
|
||||
swiftStyle = .bold
|
||||
case .ITALIC:
|
||||
case .italic:
|
||||
swiftStyle = .italic
|
||||
case .MONOSPACE:
|
||||
case .monospace:
|
||||
swiftStyle = .monospace
|
||||
case .SPOILER:
|
||||
case .spoiler:
|
||||
swiftStyle = .spoiler
|
||||
case .STRIKETHROUGH:
|
||||
case .strikethrough:
|
||||
swiftStyle = .strikethrough
|
||||
}
|
||||
bodyStyles.append(.init(swiftStyle, range: range))
|
||||
case nil:
|
||||
partialErrors.append(.restoreFrameError(
|
||||
.invalidProtoData(.invalidAci(protoClass: BackupProto.BodyRange.self)),
|
||||
.invalidProtoData(.invalidAci(protoClass: BackupProto_BodyRange.self)),
|
||||
chatItemId
|
||||
))
|
||||
continue
|
||||
@@ -618,7 +641,7 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
|
||||
private func restoreQuote(
|
||||
_ quote: BackupProto.Quote,
|
||||
_ quote: BackupProto_Quote,
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
thread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
@@ -653,10 +676,10 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
|
||||
let targetMessageTimestamp: NSNumber?
|
||||
if
|
||||
let targetSentTimestamp = quote.targetSentTimestamp,
|
||||
SDS.fitsInInt64(targetSentTimestamp)
|
||||
quote.hasTargetSentTimestamp,
|
||||
SDS.fitsInInt64(quote.targetSentTimestamp)
|
||||
{
|
||||
targetMessageTimestamp = NSNumber(value: targetSentTimestamp)
|
||||
targetMessageTimestamp = NSNumber(value: quote.targetSentTimestamp)
|
||||
} else {
|
||||
targetMessageTimestamp = nil
|
||||
}
|
||||
@@ -679,9 +702,9 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
} else {
|
||||
bodySource = .remote
|
||||
|
||||
if let text = quote.text {
|
||||
if quote.hasText {
|
||||
guard let bodyResult = restoreMessageBody(
|
||||
text: text,
|
||||
text: quote.text,
|
||||
bodyRangeProtos: quote.bodyRanges,
|
||||
chatItemId: chatItemId
|
||||
)
|
||||
@@ -697,9 +720,9 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
|
||||
let isGiftBadge: Bool
|
||||
switch quote.type {
|
||||
case .UNKNOWN, .NORMAL:
|
||||
case .UNRECOGNIZED, .unknown, .normal:
|
||||
isGiftBadge = false
|
||||
case .GIFTBADGE:
|
||||
case .giftbadge:
|
||||
isGiftBadge = true
|
||||
}
|
||||
|
||||
@@ -727,16 +750,18 @@ internal class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchive
|
||||
}
|
||||
|
||||
private func findTargetMessageForQuote(
|
||||
quote: BackupProto.Quote,
|
||||
quote: BackupProto_Quote,
|
||||
thread: MessageBackup.ChatThread,
|
||||
tx: DBReadTransaction
|
||||
) -> TSMessage? {
|
||||
guard let targetSentTimestamp = quote.targetSentTimestamp else {
|
||||
return nil
|
||||
}
|
||||
guard
|
||||
quote.hasTargetSentTimestamp,
|
||||
SDS.fitsInInt64(quote.targetSentTimestamp)
|
||||
else { return nil }
|
||||
|
||||
let messageCandidates: [TSInteraction] = (try? interactionStore
|
||||
.interactions(
|
||||
withTimestamp: targetSentTimestamp,
|
||||
withTimestamp: quote.targetSentTimestamp,
|
||||
tx: tx
|
||||
)
|
||||
) ?? []
|
||||
@@ -784,7 +809,7 @@ fileprivate extension ArchivedPayment {
|
||||
)
|
||||
case .success(let status):
|
||||
let payment = backup.payment
|
||||
let transactionIdentifier = payment?.mobileCoinIdentification?.nilIfEmpty.map {
|
||||
let transactionIdentifier = payment?.mobileCoinIdentification.nilIfEmpty.map {
|
||||
TransactionIdentifier(publicKey: $0.publicKey, keyImages: $0.keyImages)
|
||||
}
|
||||
|
||||
@@ -809,27 +834,27 @@ fileprivate extension ArchivedPayment {
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason {
|
||||
extension BackupProto_PaymentNotification.TransactionDetails.FailedTransaction.FailureReason {
|
||||
func asFailureType() -> ArchivedPayment.FailureReason {
|
||||
switch self {
|
||||
case .GENERIC: return .genericFailure
|
||||
case .NETWORK: return .networkFailure
|
||||
case .INSUFFICIENT_FUNDS: return .insufficientFundsFailure
|
||||
case .UNRECOGNIZED, .generic: return .genericFailure
|
||||
case .network: return .networkFailure
|
||||
case .insufficientFunds: return .insufficientFundsFailure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.PaymentNotification.TransactionDetails.Transaction.Status {
|
||||
extension BackupProto_PaymentNotification.TransactionDetails.Transaction.Status {
|
||||
func asStatusType() -> ArchivedPayment.Status {
|
||||
switch self {
|
||||
case .INITIAL: return .initial
|
||||
case .SUBMITTED: return .submitted
|
||||
case .SUCCESSFUL: return .successful
|
||||
case .UNRECOGNIZED, .initial: return .initial
|
||||
case .submitted: return .submitted
|
||||
case .successful: return .successful
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification {
|
||||
extension BackupProto_PaymentNotification.TransactionDetails.MobileCoinTxoIdentification {
|
||||
var nilIfEmpty: Self? {
|
||||
(publicKey.isEmpty && keyImages.isEmpty) ? nil : self
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ internal class MessageBackupTSOutgoingMessageArchiver: MessageBackupInteractionA
|
||||
var perRecipientErrors = [ArchiveFrameError]()
|
||||
|
||||
var wasAnySendSealedSender = false
|
||||
var outgoingMessage = BackupProto.ChatItem.OutgoingMessageDetails()
|
||||
var outgoingMessage = BackupProto_ChatItem.OutgoingMessageDetails()
|
||||
|
||||
for (address, sendState) in message.recipientAddressStates ?? [:] {
|
||||
guard let recipientAddress = address.asSingleServiceIdBackupAddress()?.asArchivingAddress() else {
|
||||
@@ -112,45 +112,45 @@ internal class MessageBackupTSOutgoingMessageArchiver: MessageBackupInteractionA
|
||||
}
|
||||
var isNetworkFailure = false
|
||||
var isIdentityKeyMismatchFailure = false
|
||||
let protoDeliveryStatus: BackupProto.SendStatus.Status
|
||||
let protoDeliveryStatus: BackupProto_SendStatus.Status
|
||||
let statusTimestamp: UInt64
|
||||
switch sendState.state {
|
||||
case OWSOutgoingMessageRecipientState.sent:
|
||||
if let readTimestamp = sendState.readTimestamp {
|
||||
protoDeliveryStatus = .READ
|
||||
protoDeliveryStatus = .read
|
||||
statusTimestamp = readTimestamp.uint64Value
|
||||
} else if let viewedTimestamp = sendState.viewedTimestamp {
|
||||
protoDeliveryStatus = .VIEWED
|
||||
protoDeliveryStatus = .viewed
|
||||
statusTimestamp = viewedTimestamp.uint64Value
|
||||
} else if let deliveryTimestamp = sendState.deliveryTimestamp {
|
||||
protoDeliveryStatus = .DELIVERED
|
||||
protoDeliveryStatus = .delivered
|
||||
statusTimestamp = deliveryTimestamp.uint64Value
|
||||
} else {
|
||||
protoDeliveryStatus = .SENT
|
||||
protoDeliveryStatus = .sent
|
||||
statusTimestamp = message.timestamp
|
||||
}
|
||||
case OWSOutgoingMessageRecipientState.failed:
|
||||
// TODO: [Backups] Identify specific errors (see recipientState.errorCode). For now, call everything network.
|
||||
isNetworkFailure = true
|
||||
isIdentityKeyMismatchFailure = false
|
||||
protoDeliveryStatus = .FAILED
|
||||
protoDeliveryStatus = .failed
|
||||
statusTimestamp = message.timestamp
|
||||
case OWSOutgoingMessageRecipientState.sending, OWSOutgoingMessageRecipientState.pending:
|
||||
protoDeliveryStatus = .PENDING
|
||||
protoDeliveryStatus = .pending
|
||||
statusTimestamp = message.timestamp
|
||||
case OWSOutgoingMessageRecipientState.skipped:
|
||||
protoDeliveryStatus = .SKIPPED
|
||||
protoDeliveryStatus = .skipped
|
||||
statusTimestamp = message.timestamp
|
||||
}
|
||||
|
||||
let sendStatus = BackupProto.SendStatus(
|
||||
recipientId: recipientId.value,
|
||||
deliveryStatus: protoDeliveryStatus,
|
||||
networkFailure: isNetworkFailure,
|
||||
identityKeyMismatch: isIdentityKeyMismatchFailure,
|
||||
sealedSender: sendState.wasSentByUD.negated,
|
||||
lastStatusUpdateTimestamp: statusTimestamp
|
||||
)
|
||||
var sendStatus = BackupProto_SendStatus()
|
||||
sendStatus.recipientID = recipientId.value
|
||||
sendStatus.deliveryStatus = protoDeliveryStatus
|
||||
sendStatus.networkFailure = isNetworkFailure
|
||||
sendStatus.identityKeyMismatch = isIdentityKeyMismatchFailure
|
||||
// TODO: [Backups] Is this check inverted?
|
||||
sendStatus.sealedSender = sendState.wasSentByUD.negated
|
||||
sendStatus.lastStatusUpdateTimestamp = statusTimestamp
|
||||
|
||||
outgoingMessage.sendStatus.append(sendStatus)
|
||||
|
||||
@@ -160,13 +160,13 @@ internal class MessageBackupTSOutgoingMessageArchiver: MessageBackupInteractionA
|
||||
}
|
||||
|
||||
if perRecipientErrors.isEmpty {
|
||||
return .success(.init(
|
||||
return .success(OutgoingMessageDetails(
|
||||
details: .outgoing(outgoingMessage),
|
||||
wasAnySendSealedSender: wasAnySendSealedSender
|
||||
))
|
||||
} else {
|
||||
return .partialFailure(
|
||||
.init(
|
||||
OutgoingMessageDetails(
|
||||
details: .outgoing(outgoingMessage),
|
||||
wasAnySendSealedSender: wasAnySendSealedSender
|
||||
),
|
||||
@@ -178,12 +178,12 @@ internal class MessageBackupTSOutgoingMessageArchiver: MessageBackupInteractionA
|
||||
// MARK: - Restoring
|
||||
|
||||
func restoreChatItem(
|
||||
_ chatItem: BackupProto.ChatItem,
|
||||
_ chatItem: BackupProto_ChatItem,
|
||||
chatThread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreInteractionResult<Void> {
|
||||
let outgoingDetails: BackupProto.ChatItem.OutgoingMessageDetails
|
||||
let outgoingDetails: BackupProto_ChatItem.OutgoingMessageDetails
|
||||
switch chatItem.directionalDetails {
|
||||
case .outgoing(let backupProtoChatItemOutgoingMessageDetails):
|
||||
outgoingDetails = backupProtoChatItemOutgoingMessageDetails
|
||||
|
||||
@@ -11,7 +11,7 @@ import LibSignalClient
|
||||
///
|
||||
/// So we represent restored messages as "transcripts" that we can plug into the same
|
||||
/// transcript processing pipes as synced message transcripts.
|
||||
internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
|
||||
let type: SentMessageTranscriptType
|
||||
|
||||
@@ -22,10 +22,10 @@ internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
|
||||
let recipientStates: [MessageBackup.InteropAddress: TSOutgoingMessageRecipientState]
|
||||
|
||||
internal static func from(
|
||||
chatItem: BackupProto.ChatItem,
|
||||
static func from(
|
||||
chatItem: BackupProto_ChatItem,
|
||||
contents: MessageBackup.RestoredMessageContents,
|
||||
outgoingDetails: BackupProto.ChatItem.OutgoingMessageDetails,
|
||||
outgoingDetails: BackupProto_ChatItem.OutgoingMessageDetails,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
chatThread: MessageBackup.ChatThread
|
||||
) -> MessageBackup.RestoreInteractionResult<RestoredSentMessageTranscript> {
|
||||
@@ -117,7 +117,7 @@ internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
private static func restoreMessageTranscript(
|
||||
contents: MessageBackup.RestoredMessageContents.Text,
|
||||
target: SentMessageTranscriptTarget,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
expirationToken: DisappearingMessageToken
|
||||
) -> SentMessageTranscriptType {
|
||||
let messageParams = SentMessageTranscriptType.Message(
|
||||
@@ -155,7 +155,7 @@ internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
private static func restorePaymentTranscript(
|
||||
payment: MessageBackup.RestoredMessageContents.Payment,
|
||||
target: SentMessageTranscriptTarget,
|
||||
chatItem: BackupProto.ChatItem,
|
||||
chatItem: BackupProto_ChatItem,
|
||||
expirationToken: DisappearingMessageToken
|
||||
) -> SentMessageTranscriptType {
|
||||
return .archivedPayment(
|
||||
@@ -171,7 +171,7 @@ internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
}
|
||||
|
||||
private static func recipientState(
|
||||
for sendStatus: BackupProto.SendStatus,
|
||||
for sendStatus: BackupProto_SendStatus,
|
||||
partialErrors: inout [MessageBackup.RestoreFrameError<MessageBackup.ChatItemId>],
|
||||
chatItemId: MessageBackup.ChatItemId
|
||||
) -> TSOutgoingMessageRecipientState? {
|
||||
@@ -186,37 +186,37 @@ internal class RestoredSentMessageTranscript: SentMessageTranscript {
|
||||
recipientState.wasSentByUD = sendStatus.sealedSender.negated
|
||||
|
||||
switch sendStatus.deliveryStatus {
|
||||
case .UNKNOWN:
|
||||
case .unknown, .UNRECOGNIZED:
|
||||
partialErrors.append(.restoreFrameError(.invalidProtoData(.unrecognizedMessageSendStatus), chatItemId))
|
||||
return nil
|
||||
case .PENDING:
|
||||
case .pending:
|
||||
recipientState.state = .pending
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .SENT:
|
||||
case .sent:
|
||||
recipientState.state = .sent
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .DELIVERED:
|
||||
case .delivered:
|
||||
recipientState.state = .sent
|
||||
recipientState.deliveryTimestamp = NSNumber(value: sendStatus.lastStatusUpdateTimestamp)
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .READ:
|
||||
case .read:
|
||||
recipientState.state = .sent
|
||||
recipientState.readTimestamp = NSNumber(value: sendStatus.lastStatusUpdateTimestamp)
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .VIEWED:
|
||||
case .viewed:
|
||||
recipientState.state = .sent
|
||||
recipientState.viewedTimestamp = NSNumber(value: sendStatus.lastStatusUpdateTimestamp)
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .SKIPPED:
|
||||
case .skipped:
|
||||
recipientState.state = .skipped
|
||||
recipientState.errorCode = nil
|
||||
return recipientState
|
||||
case .FAILED:
|
||||
case .failed:
|
||||
recipientState.state = .failed
|
||||
if sendStatus.identityKeyMismatch {
|
||||
// We want to explicitly represent identity key errors.
|
||||
|
||||
@@ -332,22 +332,22 @@ extension MessageBackup {
|
||||
/// A message must come from either an Aci or an E164.
|
||||
/// One in the backup did not.
|
||||
case incomingMessageNotFromAciOrE164
|
||||
/// Outgoing message's BackupProto.SendStatus can only be for BackupProto.Contacts.
|
||||
/// Outgoing message's `BackupProto_SendStatus` can only be for `BackupProto_Contacts`.
|
||||
/// One in the backup was to a group, self recipient, or something else.
|
||||
case outgoingNonContactMessageRecipient
|
||||
/// A BackupProto.SendStatus had an unregonized BackupProto.SendStatusStatus.
|
||||
/// A `BackupProto_SendStatus` had an unregonized `BackupProto_SendStatusStatus`.
|
||||
case unrecognizedMessageSendStatus
|
||||
|
||||
/// BackupProto.Reaction must come from either an Aci or an E164.
|
||||
/// `BackupProto_Reaction` must come from either an Aci or an E164.
|
||||
/// One in the backup did not.
|
||||
case reactionNotFromAciOrE164
|
||||
|
||||
/// A BackupProto.BodyRange with a missing or unrecognized style.
|
||||
/// A `BackupProto_BodyRange` with a missing or unrecognized style.
|
||||
case unrecognizedBodyRangeStyle
|
||||
|
||||
/// A BackupProto.Group's gv2 master key could not be parsed by libsignal.
|
||||
/// A `BackupProto_Group's` gv2 master key could not be parsed by libsignal.
|
||||
case invalidGV2MasterKey
|
||||
/// A BackupProtoGroup was missing its group snapshot.
|
||||
/// A `BackupProto_Group` was missing its group snapshot.
|
||||
case missingGV2GroupSnapshot
|
||||
/// A ``BackupProtoGroup/BackupProtoFullGroupMember/role`` was
|
||||
/// unrecognized. Includes the class of the offending proto.
|
||||
@@ -358,14 +358,14 @@ extension MessageBackup {
|
||||
/// We failed to build a V2 group model while restoring a group.
|
||||
case failedToBuildGV2GroupModel
|
||||
|
||||
/// A BackupProto.GroupChangeChatUpdate ChatItem with a non-group-chat chatId.
|
||||
/// A `BackupProto_GroupChangeChatUpdate` ChatItem with a non-group-chat chatId.
|
||||
case groupUpdateMessageInNonGroupChat
|
||||
/// A BackupProto.GroupChangeChatUpdate ChatItem without any updates!
|
||||
/// A `BackupProto_GroupChangeChatUpdate` ChatItem without any updates!
|
||||
case emptyGroupUpdates
|
||||
/// A BackupProto.GroupSequenceOfRequestsAndCancelsUpdate where
|
||||
/// A `BackupProto_GroupSequenceOfRequestsAndCancelsUpdate` where
|
||||
/// the requester is the local user, which isn't allowed.
|
||||
case sequenceOfRequestsAndCancelsWithLocalAci
|
||||
/// An unrecognized BackupProto.GroupChangeChatUpdate.
|
||||
/// An unrecognized `BackupProto_GroupChangeChatUpdate`.
|
||||
case unrecognizedGroupUpdate
|
||||
|
||||
/// A frame was entirely missing its enclosed item.
|
||||
@@ -376,34 +376,34 @@ extension MessageBackup {
|
||||
/// A profile key for the local user that could not be parsed into a valid aes256 key
|
||||
case invalidLocalUsernameLink
|
||||
|
||||
/// A BackupProto.IndividualCall chat item update was associated
|
||||
/// A `BackupProto_IndividualCall` chat item update was associated
|
||||
/// with a thread that was not a contact thread.
|
||||
case individualCallNotInContactThread
|
||||
/// A BackupProto.IndividualCall had an unrecognized type.
|
||||
/// A `BackupProto_IndividualCall` had an unrecognized type.
|
||||
case individualCallUnrecognizedType
|
||||
/// A BackupProto.IndividualCall had an unrecognized direction.
|
||||
/// A `BackupProto_IndividualCall` had an unrecognized direction.
|
||||
case individualCallUnrecognizedDirection
|
||||
/// A BackupProto.IndividualCall had an unrecognized state.
|
||||
/// A `BackupProto_IndividualCall` had an unrecognized state.
|
||||
case individualCallUnrecognizedState
|
||||
|
||||
/// A BackupProto.GroupCall chat item update was associated with
|
||||
/// A `BackupProto_GroupCall` chat item update was associated with
|
||||
/// a thread that was not a group thread.
|
||||
case groupCallNotInGroupThread
|
||||
/// A BackupProto.GroupCall had an unrecognized state.
|
||||
/// A `BackupProto_GroupCall` had an unrecognized state.
|
||||
case groupCallUnrecognizedState
|
||||
/// A BackupProto.GroupCall referenced a recipient that was not
|
||||
/// A `BackupProto_GroupCall` referenced a recipient that was not
|
||||
/// a contact or otherwise did not contain an ACI.
|
||||
case groupCallRecipientIdNotAnAci(RecipientId)
|
||||
|
||||
/// BackupProto.DistributionListItem was missing its item
|
||||
/// `BackupProto_DistributionListItem` was missing its item
|
||||
case distributionListItemMissingItem
|
||||
/// BackupProto.DistributionList.distributionId was not a valid UUID
|
||||
/// `BackupProto_DistributionList.distributionId` was not a valid UUID
|
||||
case invalidDistributionListId
|
||||
/// BackupProto.DistributionList.privacyMode was missing, or contained an unknown privacy mode
|
||||
/// `BackupProto_DistributionList.privacyMode` was missing, or contained an unknown privacy mode
|
||||
case invalidDistributionListPrivacyMode
|
||||
/// The specified BackupProto.DistributionList.privacyMode was missing a list of associated member IDs
|
||||
/// The specified `BackupProto_DistributionList.privacyMode` was missing a list of associated member IDs
|
||||
case invalidDistributionListPrivacyModeMissingRequiredMembers
|
||||
/// BackupProto.DistributionListItem.deletionTimestamp was invalid
|
||||
/// `BackupProto_DistributionListItem.deletionTimestamp` was invalid
|
||||
case invalidDistributionListDeletionTimestamp
|
||||
|
||||
/// A ``BackupProto/ChatUpdateMessage/update`` was empty.
|
||||
|
||||
@@ -63,7 +63,7 @@ extension MessageBackupProtoArchiver {
|
||||
internal static func writeFrameToStream<AppIdType>(
|
||||
_ stream: MessageBackupProtoOutputStream,
|
||||
objectId: AppIdType,
|
||||
frameBuilder: () -> BackupProto.Frame
|
||||
frameBuilder: () -> BackupProto_Frame
|
||||
) -> MessageBackup.ArchiveFrameError<AppIdType>? {
|
||||
let frame = frameBuilder()
|
||||
switch stream.writeFrame(frame) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import Foundation
|
||||
import LibSignalClient
|
||||
|
||||
/// Archives ``SignalRecipient``s as ``BackupProto.Contact`` recipients.
|
||||
/// Archives ``SignalRecipient``s as ``BackupProto_Contact`` recipients.
|
||||
public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
typealias RecipientId = MessageBackup.RecipientId
|
||||
typealias RecipientAppId = MessageBackup.RecipientArchivingContext.Address
|
||||
@@ -90,63 +90,72 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
let storyContext = recipient.aci.map { self.storyStore.getOrCreateStoryContextAssociatedData(for: $0, tx: tx) }
|
||||
|
||||
var contact = BackupProto.Contact(
|
||||
blocked: blockedAddresses.contains(recipient.address),
|
||||
visibility: { () -> BackupProto.Contact.Visibility in
|
||||
if self.recipientHidingManager.isHiddenRecipient(recipient, tx: tx) {
|
||||
if
|
||||
let contactThread = threadStore.fetchContactThread(recipient: recipient, tx: tx),
|
||||
threadStore.hasPendingMessageRequest(thread: contactThread, tx: tx)
|
||||
{
|
||||
return .HIDDEN_MESSAGE_REQUEST
|
||||
}
|
||||
|
||||
return .HIDDEN
|
||||
} else {
|
||||
return .VISIBLE
|
||||
var contact = BackupProto_Contact()
|
||||
contact.blocked = blockedAddresses.contains(recipient.address)
|
||||
contact.visibility = { () -> BackupProto_Contact.Visibility in
|
||||
if self.recipientHidingManager.isHiddenRecipient(recipient, tx: tx) {
|
||||
if
|
||||
let contactThread = threadStore.fetchContactThread(recipient: recipient, tx: tx),
|
||||
threadStore.hasPendingMessageRequest(thread: contactThread, tx: tx)
|
||||
{
|
||||
return .hiddenMessageRequest
|
||||
}
|
||||
}(),
|
||||
profileSharing: whitelistedAddresses.contains(recipient.address),
|
||||
hideStory: storyContext?.isHidden ?? false
|
||||
)
|
||||
contact.registration = { () -> BackupProto.Contact.Registration in
|
||||
if !recipient.isRegistered {
|
||||
let unregisteredAtTimestamp = recipient.unregisteredAtTimestamp ?? SignalRecipient.Constants.distantPastUnregisteredTimestamp
|
||||
|
||||
return .notRegistered(BackupProto.Contact.NotRegistered(
|
||||
unregisteredTimestamp: unregisteredAtTimestamp
|
||||
))
|
||||
return .hidden
|
||||
} else {
|
||||
return .visible
|
||||
}
|
||||
}()
|
||||
contact.profileSharing = whitelistedAddresses.contains(recipient.address)
|
||||
contact.hideStory = storyContext?.isHidden ?? false
|
||||
contact.registration = { () -> BackupProto_Contact.OneOf_Registration in
|
||||
if !recipient.isRegistered {
|
||||
var notRegistered = BackupProto_Contact.NotRegistered()
|
||||
notRegistered.unregisteredTimestamp = recipient.unregisteredAtTimestamp ?? SignalRecipient.Constants.distantPastUnregisteredTimestamp
|
||||
|
||||
return .notRegistered(notRegistered)
|
||||
}
|
||||
|
||||
return .registered(BackupProto.Contact.Registered())
|
||||
}()
|
||||
|
||||
contact.aci = recipient.aci.map(\.rawUUID.data)
|
||||
contact.pni = recipient.pni.map(\.rawUUID.data)
|
||||
contact.e164 = { () -> UInt64? in
|
||||
guard let phoneNumberString = recipient.phoneNumber?.stringValue else { return nil }
|
||||
return E164(phoneNumberString)?.uint64Value
|
||||
return .registered(BackupProto_Contact.Registered())
|
||||
}()
|
||||
|
||||
if let aci = recipient.aci {
|
||||
contact.username = usernameLookupManager.fetchUsername(
|
||||
forAci: aci, transaction: tx
|
||||
)
|
||||
contact.aci = aci.rawUUID.data
|
||||
|
||||
if let username = usernameLookupManager.fetchUsername(forAci: aci, transaction: tx) {
|
||||
contact.username = username
|
||||
}
|
||||
}
|
||||
if let pni = recipient.pni {
|
||||
contact.pni = pni.rawUUID.data
|
||||
}
|
||||
if
|
||||
let phoneNumberString = recipient.phoneNumber?.stringValue,
|
||||
let phoneNumberUInt = E164(phoneNumberString)?.uint64Value
|
||||
{
|
||||
contact.e164 = phoneNumberUInt
|
||||
}
|
||||
|
||||
let userProfile = self.profileManager.getUserProfile(for: recipient.address, tx: tx)
|
||||
contact.profileKey = userProfile?.profileKey.map(\.keyData)
|
||||
contact.profileGivenName = userProfile?.givenName
|
||||
contact.profileFamilyName = userProfile?.familyName
|
||||
if let profileKey = userProfile?.profileKey {
|
||||
contact.profileKey = profileKey.keyData
|
||||
}
|
||||
if let givenName = userProfile?.givenName {
|
||||
contact.profileGivenName = givenName
|
||||
}
|
||||
if let familyName = userProfile?.familyName {
|
||||
contact.profileFamilyName = familyName
|
||||
}
|
||||
|
||||
Self.writeFrameToStream(
|
||||
stream,
|
||||
objectId: .contact(contactAddress),
|
||||
frameBuilder: {
|
||||
var recipient = BackupProto.Recipient(id: recipientId.value)
|
||||
var recipient = BackupProto_Recipient()
|
||||
recipient.id = recipientId.value
|
||||
recipient.destination = .contact(contact)
|
||||
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .recipient(recipient)
|
||||
return frame
|
||||
}
|
||||
@@ -161,8 +170,8 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
}
|
||||
|
||||
func restoreContactRecipientProto(
|
||||
_ contactProto: BackupProto.Contact,
|
||||
recipient: BackupProto.Recipient,
|
||||
_ contactProto: BackupProto_Contact,
|
||||
recipient: BackupProto_Recipient,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
@@ -193,33 +202,33 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
let pni: Pni?
|
||||
let e164: E164?
|
||||
let profileKey: OWSAES256Key?
|
||||
if let aciRaw = contactProto.aci {
|
||||
guard let aciUuid = UUID(data: aciRaw) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto.Contact.self)))
|
||||
if contactProto.hasAci {
|
||||
guard let aciUuid = UUID(data: contactProto.aci) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto_Contact.self)))
|
||||
}
|
||||
aci = Aci.init(fromUUID: aciUuid)
|
||||
} else {
|
||||
aci = nil
|
||||
}
|
||||
if let pniRaw = contactProto.pni {
|
||||
guard let pniUuid = UUID(data: pniRaw) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidPni(protoClass: BackupProto.Contact.self)))
|
||||
if contactProto.hasPni {
|
||||
guard let pniUuid = UUID(data: contactProto.pni) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidPni(protoClass: BackupProto_Contact.self)))
|
||||
}
|
||||
pni = Pni.init(fromUUID: pniUuid)
|
||||
} else {
|
||||
pni = nil
|
||||
}
|
||||
if let contactProtoE164 = contactProto.e164 {
|
||||
guard let protoE164 = E164(contactProtoE164) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidE164(protoClass: BackupProto.Contact.self)))
|
||||
if contactProto.hasE164 {
|
||||
guard let protoE164 = E164(contactProto.e164) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidE164(protoClass: BackupProto_Contact.self)))
|
||||
}
|
||||
e164 = protoE164
|
||||
} else {
|
||||
e164 = nil
|
||||
}
|
||||
if let contactProtoProfileKeyData = contactProto.profileKey {
|
||||
guard let protoProfileKey = OWSAES256Key(data: contactProtoProfileKeyData) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidProfileKey(protoClass: BackupProto.Contact.self)))
|
||||
if contactProto.hasProfileKey {
|
||||
guard let protoProfileKey = OWSAES256Key(data: contactProto.profileKey) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidProfileKey(protoClass: BackupProto_Contact.self)))
|
||||
}
|
||||
profileKey = protoProfileKey
|
||||
} else {
|
||||
@@ -272,9 +281,9 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
if
|
||||
let aci = recipient.aci,
|
||||
let username = contactProto.username
|
||||
contactProto.hasUsername
|
||||
{
|
||||
usernameLookupManager.saveUsername(username, forAci: aci, transaction: tx)
|
||||
usernameLookupManager.saveUsername(contactProto.username, forAci: aci, transaction: tx)
|
||||
}
|
||||
|
||||
if contactProto.profileSharing {
|
||||
@@ -287,7 +296,7 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
}
|
||||
|
||||
switch contactProto.visibility {
|
||||
case .HIDDEN, .HIDDEN_MESSAGE_REQUEST:
|
||||
case .hidden, .hiddenMessageRequest:
|
||||
/// Message-request state for hidden recipients isn't explicitly
|
||||
/// tracked on iOS, and instead is derived from their hidden state
|
||||
/// and the most-recent interactions in their 1:1 chat. So, for both
|
||||
@@ -297,7 +306,7 @@ public class MessageBackupContactRecipientArchiver: MessageBackupProtoArchiver {
|
||||
} catch let error {
|
||||
return restoreFrameError(.databaseInsertionFailed(error))
|
||||
}
|
||||
case .VISIBLE:
|
||||
case .visible, .UNRECOGNIZED:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
}
|
||||
|
||||
// Ensure that explicit/blocklist have valid member recipient addresses
|
||||
let privacyMode: BackupProto.DistributionList.PrivacyMode? = {
|
||||
let privacyMode: BackupProto_DistributionList.PrivacyMode? = {
|
||||
switch storyThread.storyViewMode {
|
||||
case .disabled:
|
||||
return nil
|
||||
@@ -112,19 +112,19 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
errors.append(.archiveFrameError(.distributionListUnexpectedRecipients, distributionListAppId))
|
||||
return nil
|
||||
}
|
||||
return .ALL
|
||||
return .all
|
||||
case .explicit:
|
||||
guard memberRecipientIds.count > 0 else {
|
||||
errors.append(.archiveFrameError(.distributionListMissingRecipients, distributionListAppId))
|
||||
return nil
|
||||
}
|
||||
return .ONLY_WITH
|
||||
return .onlyWith
|
||||
case .blockList:
|
||||
guard memberRecipientIds.count > 0 else {
|
||||
errors.append(.archiveFrameError(.distributionListMissingRecipients, distributionListAppId))
|
||||
return nil
|
||||
}
|
||||
return .ALL_EXCEPT
|
||||
return .allExcept
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -133,21 +133,22 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
return
|
||||
}
|
||||
|
||||
var distributionList = BackupProto.DistributionList(
|
||||
name: storyThread.name,
|
||||
allowReplies: storyThread.allowsReplies,
|
||||
privacyMode: privacyMode
|
||||
)
|
||||
var distributionList = BackupProto_DistributionList()
|
||||
distributionList.name = storyThread.name
|
||||
distributionList.allowReplies = storyThread.allowsReplies
|
||||
distributionList.privacyMode = privacyMode
|
||||
distributionList.memberRecipientIds = memberRecipientIds
|
||||
|
||||
var distributionListItem = BackupProto.DistributionListItem(distributionId: distributionId)
|
||||
var distributionListItem = BackupProto_DistributionListItem()
|
||||
distributionListItem.distributionID = distributionId
|
||||
distributionListItem.item = .distributionList(distributionList)
|
||||
|
||||
Self.writeFrameToStream(stream, objectId: distributionListAppId) {
|
||||
var recipient = BackupProto.Recipient(id: recipientId.value)
|
||||
var recipient = BackupProto_Recipient()
|
||||
recipient.id = recipientId.value
|
||||
recipient.destination = .distributionList(distributionListItem)
|
||||
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .recipient(recipient)
|
||||
return frame
|
||||
}.map { errors.append($0) }
|
||||
@@ -172,22 +173,24 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
|
||||
let recipientId = context.assignRecipientId(to: distributionListAppId)
|
||||
|
||||
var distributionList = BackupProto.DistributionListItem(distributionId: distributionId)
|
||||
var distributionList = BackupProto_DistributionListItem()
|
||||
distributionList.distributionID = distributionId
|
||||
distributionList.item = .deletionTimestamp(deletionTimestamp)
|
||||
|
||||
Self.writeFrameToStream(stream, objectId: distributionListAppId) {
|
||||
var recipient = BackupProto.Recipient(id: recipientId.value)
|
||||
var recipient = BackupProto_Recipient()
|
||||
recipient.id = recipientId.value
|
||||
recipient.destination = .distributionList(distributionList)
|
||||
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .recipient(recipient)
|
||||
return frame
|
||||
}.map { errors.append($0) }
|
||||
}
|
||||
|
||||
func restoreDistributionListRecipientProto(
|
||||
_ distributionListItemProto: BackupProto.DistributionListItem,
|
||||
recipient: BackupProto.Recipient,
|
||||
_ distributionListItemProto: BackupProto_DistributionListItem,
|
||||
recipient: BackupProto_Recipient,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
@@ -198,7 +201,7 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
return .failure([.restoreFrameError(error, recipient.recipientId, line: line)])
|
||||
}
|
||||
|
||||
guard let distributionId = UUID(data: distributionListItemProto.distributionId) else {
|
||||
guard let distributionId = UUID(data: distributionListItemProto.distributionID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidDistributionListId))
|
||||
}
|
||||
|
||||
@@ -234,12 +237,12 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
result = restoreFrameError(.invalidProtoData(.distributionListItemMissingItem))
|
||||
}
|
||||
|
||||
context[recipient.recipientId] = .distributionList(distributionListItemProto.distributionId)
|
||||
context[recipient.recipientId] = .distributionList(distributionListItemProto.distributionID)
|
||||
return result
|
||||
}
|
||||
|
||||
private func buildDistributionList(
|
||||
from distributionListProto: BackupProto.DistributionList,
|
||||
from distributionListProto: BackupProto_DistributionList,
|
||||
distributionId: UUID,
|
||||
recipientId: MessageBackup.RecipientId,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
@@ -255,7 +258,7 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
return contactAddress.asInteropAddress()
|
||||
case .distributionList, .group, .localAddress, .releaseNotesChannel, .none:
|
||||
error = .failure([.restoreFrameError(
|
||||
.invalidProtoData(.invalidDistributionListMember(protoClass: BackupProto.DistributionList.self)),
|
||||
.invalidProtoData(.invalidDistributionListMember(protoClass: BackupProto_DistributionList.self)),
|
||||
recipientId
|
||||
)])
|
||||
return nil
|
||||
@@ -268,13 +271,13 @@ public class MessageBackupDistributionListRecipientArchiver: MessageBackupProtoA
|
||||
|
||||
let viewMode: TSThreadStoryViewMode? = {
|
||||
switch distributionListProto.privacyMode {
|
||||
case .ALL:
|
||||
case .all:
|
||||
return .default
|
||||
case .ALL_EXCEPT:
|
||||
case .allExcept:
|
||||
return .blockList
|
||||
case .ONLY_WITH:
|
||||
case .onlyWith:
|
||||
return .explicit
|
||||
case .UNKNOWN:
|
||||
case .unknown, .UNRECOGNIZED:
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
import Foundation
|
||||
import LibSignalClient
|
||||
|
||||
/// Archives ``TSGroupThread``s as ``BackupProto.Group`` recipients.
|
||||
/// Archives ``TSGroupThread``s as ``BackupProto_Group`` recipients.
|
||||
///
|
||||
/// This is a bit confusing, because ``TSThread`` mostly corresponds to
|
||||
/// ``BackupProto.Chat``, and there will in fact _also_ be a chat for the group
|
||||
/// ``BackupProto_Chat``, and there will in fact _also_ be a chat for the group
|
||||
/// thread. Its just that our group thread contains all the metadata
|
||||
/// corresponding to both the Chat and Recipient parts of the Backup proto.
|
||||
public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
@@ -104,38 +104,40 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
return
|
||||
}
|
||||
|
||||
var group = BackupProto.Group(
|
||||
masterKey: groupMasterKey,
|
||||
whitelisted: profileManager.isThread(
|
||||
inProfileWhitelist: groupThread, tx: tx
|
||||
),
|
||||
hideStory: storyStore.getOrCreateStoryContextAssociatedData(
|
||||
forGroupThread: groupThread, tx: tx
|
||||
).isHidden,
|
||||
storySendMode: { () -> BackupProto.Group.StorySendMode in
|
||||
switch groupThread.storyViewMode {
|
||||
case .disabled: return .DISABLED
|
||||
case .explicit, .blockList: return .ENABLED
|
||||
case .default: return .DEFAULT
|
||||
}
|
||||
}()
|
||||
var group = BackupProto_Group()
|
||||
group.masterKey = groupMasterKey
|
||||
group.whitelisted = profileManager.isThread(
|
||||
inProfileWhitelist: groupThread, tx: tx
|
||||
)
|
||||
group.snapshot = { () -> BackupProto.Group.GroupSnapshot in
|
||||
var groupSnapshot = BackupProto.Group.GroupSnapshot(
|
||||
publicKey: groupPublicKey,
|
||||
avatarUrl: groupModel.avatarUrlPath ?? "",
|
||||
version: groupModel.revision,
|
||||
inviteLinkPassword: groupModel.inviteLinkPassword ?? Data(),
|
||||
announcementsOnly: groupModel.isAnnouncementsOnly
|
||||
)
|
||||
groupSnapshot.title = groupModel.groupName?.nilIfEmpty.map { .buildTitle($0) }
|
||||
groupSnapshot.descriptionText = groupModel.descriptionText?.nilIfEmpty.map { .buildDescriptionText($0) }
|
||||
groupSnapshot.disappearingMessagesTimer = { () -> BackupProto.Group.GroupAttributeBlob? in
|
||||
group.hideStory = storyStore.getOrCreateStoryContextAssociatedData(
|
||||
forGroupThread: groupThread, tx: tx
|
||||
).isHidden
|
||||
group.storySendMode = { () -> BackupProto_Group.StorySendMode in
|
||||
switch groupThread.storyViewMode {
|
||||
case .disabled: return .disabled
|
||||
case .explicit, .blockList: return .enabled
|
||||
case .default: return .default
|
||||
}
|
||||
}()
|
||||
group.snapshot = { () -> BackupProto_Group.GroupSnapshot in
|
||||
var groupSnapshot = BackupProto_Group.GroupSnapshot()
|
||||
groupSnapshot.publicKey = groupPublicKey
|
||||
groupSnapshot.avatarURL = groupModel.avatarUrlPath ?? ""
|
||||
groupSnapshot.version = groupModel.revision
|
||||
groupSnapshot.inviteLinkPassword = groupModel.inviteLinkPassword ?? Data()
|
||||
groupSnapshot.announcementsOnly = groupModel.isAnnouncementsOnly
|
||||
if let groupName = groupModel.groupName?.nilIfEmpty {
|
||||
groupSnapshot.title = .buildTitle(groupName)
|
||||
}
|
||||
if let groupDescription = groupModel.descriptionText?.nilIfEmpty {
|
||||
groupSnapshot.description_p = .buildDescriptionText(groupDescription)
|
||||
}
|
||||
groupSnapshot.disappearingMessagesTimer = { () -> BackupProto_Group.GroupAttributeBlob in
|
||||
let durationSeconds = disappearingMessageConfigStore.durationSeconds(for: groupThread, tx: tx)
|
||||
return durationSeconds > 0 ? .buildDisappearingMessageTimer(durationSeconds) : nil
|
||||
return .buildDisappearingMessageTimer(durationSeconds)
|
||||
}()
|
||||
groupSnapshot.accessControl = groupModel.access.asBackupProtoAccessControl
|
||||
groupSnapshot.members = groupMembership.fullMembers.compactMap { address -> BackupProto.Group.Member? in
|
||||
groupSnapshot.members = groupMembership.fullMembers.compactMap { address -> BackupProto_Group.Member? in
|
||||
guard
|
||||
let aci = address.aci,
|
||||
let role = groupMembership.role(for: address),
|
||||
@@ -147,7 +149,7 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
return .build(serviceId: aci, role: role, profileKeyData: profileKey)
|
||||
}
|
||||
groupSnapshot.membersPendingProfileKey = groupMembership.invitedMembers.compactMap { address -> BackupProto.Group.MemberPendingProfileKey? in
|
||||
groupSnapshot.membersPendingProfileKey = groupMembership.invitedMembers.compactMap { address -> BackupProto_Group.MemberPendingProfileKey? in
|
||||
guard
|
||||
let serviceId = address.serviceId,
|
||||
let role = groupMembership.role(for: address),
|
||||
@@ -159,10 +161,9 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
// iOS doesn't track the timestamp of the invite, so we'll
|
||||
// default-populate it.
|
||||
var invitedMemberProto = BackupProto.Group.MemberPendingProfileKey(
|
||||
addedByUserId: addedByAci.serviceIdBinary.asData,
|
||||
timestamp: 0
|
||||
)
|
||||
var invitedMemberProto = BackupProto_Group.MemberPendingProfileKey()
|
||||
invitedMemberProto.addedByUserID = addedByAci.serviceIdBinary.asData
|
||||
invitedMemberProto.timestamp = 0
|
||||
invitedMemberProto.member = .build(
|
||||
serviceId: serviceId,
|
||||
role: role,
|
||||
@@ -170,7 +171,7 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
)
|
||||
return invitedMemberProto
|
||||
}
|
||||
groupSnapshot.membersPendingAdminApproval = groupMembership.requestingMembers.compactMap { address -> BackupProto.Group.MemberPendingAdminApproval? in
|
||||
groupSnapshot.membersPendingAdminApproval = groupMembership.requestingMembers.compactMap { address -> BackupProto_Group.MemberPendingAdminApproval? in
|
||||
guard
|
||||
let aci = address.aci,
|
||||
let profileKey = profileManager.getProfileKeyData(for: address, tx: tx)
|
||||
@@ -181,17 +182,19 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
// iOS doesn't track the timestamp of the request, so we'll
|
||||
// default-populate it.
|
||||
return BackupProto.Group.MemberPendingAdminApproval(
|
||||
userId: aci.serviceIdBinary.asData,
|
||||
profileKey: profileKey,
|
||||
timestamp: 0
|
||||
)
|
||||
var memberPendingAdminApproval = BackupProto_Group.MemberPendingAdminApproval()
|
||||
memberPendingAdminApproval.userID = aci.serviceIdBinary.asData
|
||||
memberPendingAdminApproval.profileKey = profileKey
|
||||
memberPendingAdminApproval.timestamp = 0
|
||||
|
||||
return memberPendingAdminApproval
|
||||
}
|
||||
groupSnapshot.membersBanned = groupMembership.bannedMembers.map { aci, bannedAtMillis -> BackupProto.Group.MemberBanned in
|
||||
return BackupProto.Group.MemberBanned(
|
||||
userId: aci.serviceIdBinary.asData,
|
||||
timestamp: bannedAtMillis
|
||||
)
|
||||
groupSnapshot.membersBanned = groupMembership.bannedMembers.map { aci, bannedAtMillis -> BackupProto_Group.MemberBanned in
|
||||
var memberBanned = BackupProto_Group.MemberBanned()
|
||||
memberBanned.userID = aci.serviceIdBinary.asData
|
||||
memberBanned.timestamp = bannedAtMillis
|
||||
|
||||
return memberBanned
|
||||
}
|
||||
|
||||
return groupSnapshot
|
||||
@@ -201,10 +204,11 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
stream,
|
||||
objectId: groupAppId,
|
||||
frameBuilder: {
|
||||
var recipient = BackupProto.Recipient(id: recipientId.value)
|
||||
var recipient = BackupProto_Recipient()
|
||||
recipient.id = recipientId.value
|
||||
recipient.destination = .group(group)
|
||||
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .recipient(recipient)
|
||||
return frame
|
||||
}
|
||||
@@ -212,8 +216,8 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
}
|
||||
|
||||
func restoreGroupRecipientProto(
|
||||
_ groupProto: BackupProto.Group,
|
||||
recipient: BackupProto.Recipient,
|
||||
_ groupProto: BackupProto_Group,
|
||||
recipient: BackupProto_Recipient,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
@@ -233,17 +237,18 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
return restoreFrameError(.invalidProtoData(.invalidGV2MasterKey))
|
||||
}
|
||||
|
||||
guard let groupSnapshot = groupProto.snapshot else {
|
||||
guard groupProto.hasSnapshot else {
|
||||
return restoreFrameError(.invalidProtoData(.missingGV2GroupSnapshot))
|
||||
}
|
||||
let groupSnapshot = groupProto.snapshot
|
||||
|
||||
var groupMembershipBuilder = GroupMembership.Builder()
|
||||
for fullMember in groupSnapshot.members {
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: fullMember.userId) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto.Group.Member.self)))
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: fullMember.userID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto_Group.Member.self)))
|
||||
}
|
||||
guard let role = TSGroupMemberRole(backupProtoRole: fullMember.role) else {
|
||||
return restoreFrameError(.invalidProtoData(.unrecognizedGV2MemberRole(protoClass: BackupProto.Group.Member.self)))
|
||||
return restoreFrameError(.invalidProtoData(.unrecognizedGV2MemberRole(protoClass: BackupProto_Group.Member.self)))
|
||||
}
|
||||
|
||||
groupMembershipBuilder.addFullMember(aci, role: role)
|
||||
@@ -261,17 +266,18 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
}
|
||||
}
|
||||
for invitedMember in groupSnapshot.membersPendingProfileKey {
|
||||
guard let memberDetails = invitedMember.member else {
|
||||
guard invitedMember.hasMember else {
|
||||
return restoreFrameError(.invalidProtoData(.invitedGV2MemberMissingMemberDetails))
|
||||
}
|
||||
guard let serviceId = try? ServiceId.parseFrom(serviceIdBinary: memberDetails.userId) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidServiceId(protoClass: BackupProto.Group.MemberPendingProfileKey.self)))
|
||||
let memberDetails = invitedMember.member
|
||||
guard let serviceId = try? ServiceId.parseFrom(serviceIdBinary: memberDetails.userID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidServiceId(protoClass: BackupProto_Group.MemberPendingProfileKey.self)))
|
||||
}
|
||||
guard let role = TSGroupMemberRole(backupProtoRole: memberDetails.role) else {
|
||||
return restoreFrameError(.invalidProtoData(.unrecognizedGV2MemberRole(protoClass: BackupProto.Group.MemberPendingProfileKey.self)))
|
||||
return restoreFrameError(.invalidProtoData(.unrecognizedGV2MemberRole(protoClass: BackupProto_Group.MemberPendingProfileKey.self)))
|
||||
}
|
||||
guard let addedByAci = try? Aci.parseFrom(serviceIdBinary: invitedMember.addedByUserId) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto.Group.MemberPendingProfileKey.self)))
|
||||
guard let addedByAci = try? Aci.parseFrom(serviceIdBinary: invitedMember.addedByUserID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto_Group.MemberPendingProfileKey.self)))
|
||||
}
|
||||
|
||||
groupMembershipBuilder.addInvitedMember(
|
||||
@@ -281,8 +287,8 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
)
|
||||
}
|
||||
for requestingMember in groupSnapshot.membersPendingAdminApproval {
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: requestingMember.userId) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto.Group.MemberPendingAdminApproval.self)))
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: requestingMember.userID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto_Group.MemberPendingAdminApproval.self)))
|
||||
}
|
||||
groupMembershipBuilder.addRequestingMember(aci)
|
||||
|
||||
@@ -299,8 +305,8 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
}
|
||||
}
|
||||
for bannedMember in groupSnapshot.membersBanned {
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: bannedMember.userId) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto.Group.MemberBanned.self)))
|
||||
guard let aci = try? Aci.parseFrom(serviceIdBinary: bannedMember.userID) else {
|
||||
return restoreFrameError(.invalidProtoData(.invalidAci(protoClass: BackupProto_Group.MemberBanned.self)))
|
||||
}
|
||||
let bannedAtTimestampMillis = bannedMember.timestamp
|
||||
|
||||
@@ -318,9 +324,9 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
groupModelBuilder.name = groupSnapshot.extractTitle
|
||||
groupModelBuilder.descriptionText = groupSnapshot.extractDescriptionText
|
||||
groupModelBuilder.avatarData = nil
|
||||
groupModelBuilder.avatarUrlPath = groupSnapshot.avatarUrl.nilIfEmpty
|
||||
groupModelBuilder.avatarUrlPath = groupSnapshot.avatarURL.nilIfEmpty
|
||||
groupModelBuilder.groupMembership = groupMembershipBuilder.build()
|
||||
groupModelBuilder.groupAccess = groupSnapshot.accessControl.map(GroupAccess.init(backupProtoAccessControl:))
|
||||
groupModelBuilder.groupAccess = GroupAccess(backupProtoAccessControl: groupSnapshot.accessControl)
|
||||
groupModelBuilder.inviteLinkPassword = groupSnapshot.inviteLinkPassword.nilIfEmpty
|
||||
groupModelBuilder.isAnnouncementsOnly = groupSnapshot.announcementsOnly
|
||||
|
||||
@@ -350,12 +356,12 @@ public class MessageBackupGroupRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
let isStorySendEnabled: Bool? = {
|
||||
switch groupProto.storySendMode {
|
||||
case .DEFAULT:
|
||||
case .default, .UNRECOGNIZED:
|
||||
// No explicit setting.
|
||||
return nil
|
||||
case .DISABLED:
|
||||
case .disabled:
|
||||
return false
|
||||
case .ENABLED:
|
||||
case .enabled:
|
||||
return true
|
||||
}
|
||||
}()
|
||||
@@ -403,43 +409,43 @@ private extension OWSAES256Key {
|
||||
|
||||
// MARK: -
|
||||
|
||||
private extension BackupProto.Group.GroupAttributeBlob {
|
||||
static func buildTitle(_ title: String) -> BackupProto.Group.GroupAttributeBlob {
|
||||
var blob = BackupProto.Group.GroupAttributeBlob()
|
||||
private extension BackupProto_Group.GroupAttributeBlob {
|
||||
static func buildTitle(_ title: String) -> BackupProto_Group.GroupAttributeBlob {
|
||||
var blob = BackupProto_Group.GroupAttributeBlob()
|
||||
blob.content = .title(title)
|
||||
return blob
|
||||
}
|
||||
|
||||
static func buildDescriptionText(_ descriptionText: String) -> BackupProto.Group.GroupAttributeBlob {
|
||||
var blob = BackupProto.Group.GroupAttributeBlob()
|
||||
static func buildDescriptionText(_ descriptionText: String) -> BackupProto_Group.GroupAttributeBlob {
|
||||
var blob = BackupProto_Group.GroupAttributeBlob()
|
||||
blob.content = .descriptionText(descriptionText)
|
||||
return blob
|
||||
}
|
||||
|
||||
static func buildDisappearingMessageTimer(_ disappearingMessageDuration: UInt32) -> BackupProto.Group.GroupAttributeBlob {
|
||||
var blob = BackupProto.Group.GroupAttributeBlob()
|
||||
static func buildDisappearingMessageTimer(_ disappearingMessageDuration: UInt32) -> BackupProto_Group.GroupAttributeBlob {
|
||||
var blob = BackupProto_Group.GroupAttributeBlob()
|
||||
blob.content = .disappearingMessagesDuration(disappearingMessageDuration)
|
||||
return blob
|
||||
}
|
||||
}
|
||||
|
||||
private extension BackupProto.Group.GroupSnapshot {
|
||||
private extension BackupProto_Group.GroupSnapshot {
|
||||
var extractTitle: String? {
|
||||
switch title?.content {
|
||||
switch title.content {
|
||||
case .title(let title): return title
|
||||
case nil, .avatar, .descriptionText, .disappearingMessagesDuration: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var extractDescriptionText: String? {
|
||||
switch descriptionText?.content {
|
||||
switch description_p.content {
|
||||
case .descriptionText(let descriptionText): return descriptionText
|
||||
case nil, .title, .avatar, .disappearingMessagesDuration: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var extractDisappearingMessageTimer: UInt32? {
|
||||
switch disappearingMessagesTimer?.content {
|
||||
switch disappearingMessagesTimer.content {
|
||||
case .disappearingMessagesDuration(let disappearingMessageDuration): return disappearingMessageDuration
|
||||
case nil, .title, .avatar, .descriptionText: return nil
|
||||
}
|
||||
@@ -448,37 +454,37 @@ private extension BackupProto.Group.GroupSnapshot {
|
||||
|
||||
// MARK: -
|
||||
|
||||
private extension BackupProto.Group.Member {
|
||||
private extension BackupProto_Group.Member {
|
||||
static func build(
|
||||
serviceId: ServiceId,
|
||||
role: TSGroupMemberRole,
|
||||
profileKeyData: Data?
|
||||
) -> BackupProto.Group.Member {
|
||||
) -> BackupProto_Group.Member {
|
||||
// iOS doesn't track the joinedAtRevision, so we'll default-populate it.
|
||||
return BackupProto.Group.Member(
|
||||
userId: serviceId.serviceIdBinary.asData,
|
||||
role: role.asBackupProtoRole,
|
||||
profileKey: profileKeyData ?? Data(),
|
||||
joinedAtVersion: 0
|
||||
)
|
||||
var member = BackupProto_Group.Member()
|
||||
member.userID = serviceId.serviceIdBinary.asData
|
||||
member.role = role.asBackupProtoRole
|
||||
member.profileKey = profileKeyData ?? Data()
|
||||
member.joinedAtVersion = 0
|
||||
return member
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private extension TSGroupMemberRole {
|
||||
init?(backupProtoRole: BackupProto.Group.Member.Role) {
|
||||
init?(backupProtoRole: BackupProto_Group.Member.Role) {
|
||||
switch backupProtoRole {
|
||||
case .UNKNOWN: return nil
|
||||
case .DEFAULT: self = .normal
|
||||
case .ADMINISTRATOR: self = .administrator
|
||||
case .unknown, .UNRECOGNIZED: return nil
|
||||
case .default: self = .normal
|
||||
case .administrator: self = .administrator
|
||||
}
|
||||
}
|
||||
|
||||
var asBackupProtoRole: BackupProto.Group.Member.Role {
|
||||
var asBackupProtoRole: BackupProto_Group.Member.Role {
|
||||
switch self {
|
||||
case .normal: return .DEFAULT
|
||||
case .administrator: return .ADMINISTRATOR
|
||||
case .normal: return .default
|
||||
case .administrator: return .administrator
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,29 +492,29 @@ private extension TSGroupMemberRole {
|
||||
// MARK: -
|
||||
|
||||
private extension GroupV2Access {
|
||||
init(backupProtoAccessRequired: BackupProto.Group.AccessControl.AccessRequired) {
|
||||
init(backupProtoAccessRequired: BackupProto_Group.AccessControl.AccessRequired) {
|
||||
switch backupProtoAccessRequired {
|
||||
case .UNKNOWN: self = .unknown
|
||||
case .ANY: self = .any
|
||||
case .MEMBER: self = .member
|
||||
case .ADMINISTRATOR: self = .administrator
|
||||
case .UNSATISFIABLE: self = .unsatisfiable
|
||||
case .unknown, .UNRECOGNIZED: self = .unknown
|
||||
case .any: self = .any
|
||||
case .member: self = .member
|
||||
case .administrator: self = .administrator
|
||||
case .unsatisfiable: self = .unsatisfiable
|
||||
}
|
||||
}
|
||||
|
||||
var asBackupProtoAccessRequired: BackupProto.Group.AccessControl.AccessRequired {
|
||||
var asBackupProtoAccessRequired: BackupProto_Group.AccessControl.AccessRequired {
|
||||
switch self {
|
||||
case .unknown: return .UNKNOWN
|
||||
case .any: return .ANY
|
||||
case .member: return .MEMBER
|
||||
case .administrator: return .ADMINISTRATOR
|
||||
case .unsatisfiable: return .UNSATISFIABLE
|
||||
case .unknown: return .unknown
|
||||
case .any: return .any
|
||||
case .member: return .member
|
||||
case .administrator: return .administrator
|
||||
case .unsatisfiable: return .unsatisfiable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension GroupAccess {
|
||||
convenience init(backupProtoAccessControl: BackupProto.Group.AccessControl) {
|
||||
convenience init(backupProtoAccessControl: BackupProto_Group.AccessControl) {
|
||||
self.init(
|
||||
members: GroupV2Access(backupProtoAccessRequired: backupProtoAccessControl.members),
|
||||
attributes: GroupV2Access(backupProtoAccessRequired: backupProtoAccessControl.attributes),
|
||||
@@ -516,11 +522,11 @@ private extension GroupAccess {
|
||||
)
|
||||
}
|
||||
|
||||
var asBackupProtoAccessControl: BackupProto.Group.AccessControl {
|
||||
return BackupProto.Group.AccessControl(
|
||||
attributes: attributes.asBackupProtoAccessRequired,
|
||||
members: members.asBackupProtoAccessRequired,
|
||||
addFromInviteLink: addFromInviteLink.asBackupProtoAccessRequired
|
||||
)
|
||||
var asBackupProtoAccessControl: BackupProto_Group.AccessControl {
|
||||
var accessControl = BackupProto_Group.AccessControl()
|
||||
accessControl.attributes = attributes.asBackupProtoAccessRequired
|
||||
accessControl.members = members.asBackupProtoAccessRequired
|
||||
accessControl.addFromInviteLink = members.asBackupProtoAccessRequired
|
||||
return accessControl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ extension MessageBackup {
|
||||
public typealias RestoreLocalRecipientResult = RestoreFrameResult<RecipientId>
|
||||
}
|
||||
|
||||
/// Archiver for the ``BackupProto.SelfRecipient`` recipient, a.k.a. the local
|
||||
/// Archiver for the ``BackupProto_Self`` recipient, a.k.a. the local
|
||||
/// user author/recipient. Used as the recipient for the Note To Self chat.
|
||||
public class MessageBackupLocalRecipientArchiver: MessageBackupProtoArchiver {
|
||||
private static let localRecipientId = MessageBackup.RecipientId(value: 1)
|
||||
@@ -26,12 +26,13 @@ public class MessageBackupLocalRecipientArchiver: MessageBackupProtoArchiver {
|
||||
stream,
|
||||
objectId: MessageBackup.LocalRecipientId()
|
||||
) {
|
||||
let selfRecipient = BackupProto.SelfRecipient()
|
||||
let selfRecipient = BackupProto_Self()
|
||||
|
||||
var recipient = BackupProto.Recipient(id: Self.localRecipientId.value)
|
||||
recipient.destination = .selfRecipient(selfRecipient)
|
||||
var recipient = BackupProto_Recipient()
|
||||
recipient.id = Self.localRecipientId.value
|
||||
recipient.destination = .self_p(selfRecipient)
|
||||
|
||||
var frame = BackupProto.Frame()
|
||||
var frame = BackupProto_Frame()
|
||||
frame.item = .recipient(recipient)
|
||||
return frame
|
||||
}
|
||||
@@ -45,8 +46,8 @@ public class MessageBackupLocalRecipientArchiver: MessageBackupProtoArchiver {
|
||||
|
||||
/// Restore a single ``BackupProto/Recipient`` frame for the local recipient.
|
||||
public func restoreSelfRecipient(
|
||||
_ selfRecipientProto: BackupProto.SelfRecipient,
|
||||
recipient: BackupProto.Recipient,
|
||||
_ selfRecipientProto: BackupProto_Self,
|
||||
recipient: BackupProto_Recipient,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreLocalRecipientResult {
|
||||
|
||||
@@ -34,8 +34,8 @@ public class MessageBackupReleaseNotesRecipientArchiver: MessageBackupProtoArchi
|
||||
// MARK: -
|
||||
|
||||
func restoreReleaseNotesRecipientProto(
|
||||
_ releaseNotesRecipientProto: BackupProto.ReleaseNotes,
|
||||
recipient: BackupProto.Recipient,
|
||||
_ releaseNotesRecipientProto: BackupProto_ReleaseNotes,
|
||||
recipient: BackupProto_Recipient,
|
||||
context: MessageBackup.RecipientRestoringContext,
|
||||
tx: any DBWriteTransaction
|
||||
) -> RestoreFrameResult {
|
||||
|
||||
@@ -15,28 +15,28 @@ extension MessageBackup {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init(recipient: BackupProto.Recipient) {
|
||||
fileprivate init(recipient: BackupProto_Recipient) {
|
||||
self.init(value: recipient.id)
|
||||
}
|
||||
|
||||
fileprivate init(chat: BackupProto.Chat) {
|
||||
self.init(value: chat.recipientId)
|
||||
fileprivate init(chat: BackupProto_Chat) {
|
||||
self.init(value: chat.recipientID)
|
||||
}
|
||||
|
||||
fileprivate init(chatItem: BackupProto.ChatItem) {
|
||||
self.init(value: chatItem.authorId)
|
||||
fileprivate init(chatItem: BackupProto_ChatItem) {
|
||||
self.init(value: chatItem.authorID)
|
||||
}
|
||||
|
||||
fileprivate init(reaction: BackupProto.Reaction) {
|
||||
self.init(value: reaction.authorId)
|
||||
fileprivate init(reaction: BackupProto_Reaction) {
|
||||
self.init(value: reaction.authorID)
|
||||
}
|
||||
|
||||
fileprivate init(quote: BackupProto.Quote) {
|
||||
self.init(value: quote.authorId)
|
||||
fileprivate init(quote: BackupProto_Quote) {
|
||||
self.init(value: quote.authorID)
|
||||
}
|
||||
|
||||
fileprivate init(sendStatus: BackupProto.SendStatus) {
|
||||
self.init(value: sendStatus.recipientId)
|
||||
fileprivate init(sendStatus: BackupProto_SendStatus) {
|
||||
self.init(value: sendStatus.recipientID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ extension MessageBackup {
|
||||
* to the ID addressing system of the backup protos.
|
||||
*
|
||||
* For example, we will assign a ``BackupRecipientId`` to each ``SignalRecipient`` as we
|
||||
* insert them. Later, when we create the ``BackupProto.Chat`` corresponding to the ``TSContactThread``
|
||||
* insert them. Later, when we create the ``BackupProto_Chat`` corresponding to the ``TSContactThread``
|
||||
* for that recipient, we will need to add the corresponding ``BackupRecipientId``, which we look up
|
||||
* using the contact's Aci/Pni/e164, from the map this context keeps.
|
||||
*/
|
||||
@@ -165,7 +165,7 @@ extension MessageBackup {
|
||||
}
|
||||
|
||||
extension MessageBackup.RecipientId: MessageBackupLoggableId {
|
||||
public var typeLogString: String { "BackupProto.Recipient" }
|
||||
public var typeLogString: String { "BackupProto_Recipient" }
|
||||
|
||||
public var idLogString: String { "\(self.value)" }
|
||||
}
|
||||
@@ -195,42 +195,42 @@ extension MessageBackup.RecipientArchivingContext.Address: MessageBackupLoggable
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.Recipient {
|
||||
extension BackupProto_Recipient {
|
||||
|
||||
public var recipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(recipient: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.Chat {
|
||||
extension BackupProto_Chat {
|
||||
|
||||
public var typedRecipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(chat: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.ChatItem {
|
||||
extension BackupProto_ChatItem {
|
||||
|
||||
public var authorRecipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(chatItem: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.Reaction {
|
||||
extension BackupProto_Reaction {
|
||||
|
||||
public var authorRecipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(reaction: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.Quote {
|
||||
extension BackupProto_Quote {
|
||||
|
||||
public var authorRecipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(quote: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension BackupProto.SendStatus {
|
||||
extension BackupProto_SendStatus {
|
||||
public var destinationRecipientId: MessageBackup.RecipientId {
|
||||
return MessageBackup.RecipientId(sendStatus: self)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
public extension MessageBackup {
|
||||
/// An identifier for a ``BackupProto.StickerPack`` backup frame.
|
||||
/// An identifier for a ``BackupProto_StickerPack`` backup frame.
|
||||
struct StickerPackId: MessageBackupLoggableId {
|
||||
let value: Data
|
||||
|
||||
@@ -14,7 +14,7 @@ public extension MessageBackup {
|
||||
|
||||
// MARK: MessageBackupLoggableId
|
||||
|
||||
public var typeLogString: String { "BackupProto.StickPack" }
|
||||
public var typeLogString: String { "BackupProto_StickPack" }
|
||||
public var idLogString: String {
|
||||
/// Since sticker pack IDs are a cross-client identifier, we don't
|
||||
/// want to log them directly.
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Wire
|
||||
|
||||
extension MessageBackup {
|
||||
public enum ProtoInputStreamReadResult<T> {
|
||||
case success(T, moreBytesAvailable: Bool)
|
||||
@@ -25,10 +23,10 @@ public protocol MessageBackupProtoInputStream {
|
||||
|
||||
/// Read the single header object at the start of every backup file.
|
||||
/// If this header is missing or invalid, the backup should be discarded.
|
||||
func readHeader() -> MessageBackup.ProtoInputStreamReadResult<BackupProto.BackupInfo>
|
||||
func readHeader() -> MessageBackup.ProtoInputStreamReadResult<BackupProto_BackupInfo>
|
||||
|
||||
/// Read a the next frame from the backup file.
|
||||
func readFrame() -> MessageBackup.ProtoInputStreamReadResult<BackupProto.Frame>
|
||||
func readFrame() -> MessageBackup.ProtoInputStreamReadResult<BackupProto_Frame>
|
||||
|
||||
/// Close the stream. Attempting to read after closing will result in failures.
|
||||
func closeFileStream()
|
||||
@@ -47,17 +45,15 @@ internal class MessageBackupProtoInputStreamImpl: MessageBackupProtoInputStream
|
||||
self.inputStreamDelegate = inputStreamDelegate
|
||||
}
|
||||
|
||||
internal func readHeader() -> MessageBackup.ProtoInputStreamReadResult<BackupProto.BackupInfo> {
|
||||
internal func readHeader() -> MessageBackup.ProtoInputStreamReadResult<BackupProto_BackupInfo> {
|
||||
return readProto { protoData in
|
||||
return try ProtoDecoder(enumDecodingStrategy: .returnNil)
|
||||
.decode(BackupProto.BackupInfo.self, from: protoData)
|
||||
return try BackupProto_BackupInfo(contiguousBytes: protoData)
|
||||
}
|
||||
}
|
||||
|
||||
internal func readFrame() -> MessageBackup.ProtoInputStreamReadResult<BackupProto.Frame> {
|
||||
internal func readFrame() -> MessageBackup.ProtoInputStreamReadResult<BackupProto_Frame> {
|
||||
return readProto { protoData in
|
||||
return try ProtoDecoder(enumDecodingStrategy: .returnNil)
|
||||
.decode(BackupProto.Frame.self, from: protoData)
|
||||
return try BackupProto_Frame(contiguousBytes: protoData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Wire
|
||||
|
||||
extension MessageBackup {
|
||||
public enum ProtoOutputStreamWriteResult {
|
||||
case success
|
||||
@@ -29,10 +27,10 @@ public protocol MessageBackupProtoOutputStream {
|
||||
/// Write a header (BakckupInfo) to the backup file.
|
||||
/// It is the caller's responsibility to ensure this is always written, and is the first thing written,
|
||||
/// in order to produce a valid backup file.
|
||||
func writeHeader(_ header: BackupProto.BackupInfo) -> MessageBackup.ProtoOutputStreamWriteResult
|
||||
func writeHeader(_ header: BackupProto_BackupInfo) -> MessageBackup.ProtoOutputStreamWriteResult
|
||||
|
||||
/// Write a frame to the backup file.
|
||||
func writeFrame(_ frame: BackupProto.Frame) -> MessageBackup.ProtoOutputStreamWriteResult
|
||||
func writeFrame(_ frame: BackupProto_Frame) -> MessageBackup.ProtoOutputStreamWriteResult
|
||||
|
||||
/// Closes the output stream.
|
||||
func closeFileStream() throws
|
||||
@@ -46,10 +44,10 @@ internal class MessageBackupProtoOutputStreamImpl: MessageBackupProtoOutputStrea
|
||||
self.outputStream = outputStream
|
||||
}
|
||||
|
||||
internal func writeHeader(_ header: BackupProto.BackupInfo) -> MessageBackup.ProtoOutputStreamWriteResult {
|
||||
internal func writeHeader(_ header: BackupProto_BackupInfo) -> MessageBackup.ProtoOutputStreamWriteResult {
|
||||
let bytes: Data
|
||||
do {
|
||||
bytes = try ProtoEncoder().encode(header)
|
||||
bytes = try header.serializedData()
|
||||
} catch {
|
||||
return .protoSerializationError(error)
|
||||
}
|
||||
@@ -61,10 +59,10 @@ internal class MessageBackupProtoOutputStreamImpl: MessageBackupProtoOutputStrea
|
||||
return .success
|
||||
}
|
||||
|
||||
internal func writeFrame(_ frame: BackupProto.Frame) -> MessageBackup.ProtoOutputStreamWriteResult {
|
||||
internal func writeFrame(_ frame: BackupProto_Frame) -> MessageBackup.ProtoOutputStreamWriteResult {
|
||||
let bytes: Data
|
||||
do {
|
||||
bytes = try ProtoEncoder().encode(frame)
|
||||
bytes = try frame.serializedData()
|
||||
} catch {
|
||||
return .protoSerializationError(error)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
extension MessageBackup {
|
||||
/// An identifier for an empty ``BackupProto.Frame``.
|
||||
/// An identifier for an empty ``BackupProto_Frame``.
|
||||
///
|
||||
/// Uses a singleton pattern, as frames do not contain their own ID and
|
||||
/// consequently all empty frames are equivalent.
|
||||
|
||||
@@ -316,10 +316,10 @@ public class MessageBackupManagerImpl: MessageBackupManager {
|
||||
}
|
||||
|
||||
private func writeHeader(stream: MessageBackupProtoOutputStream, tx: DBWriteTransaction) throws {
|
||||
let backupInfo = BackupProto.BackupInfo(
|
||||
version: Constants.supportedBackupVersion,
|
||||
backupTimeMs: dateProvider().ows_millisecondsSince1970
|
||||
)
|
||||
var backupInfo = BackupProto_BackupInfo()
|
||||
backupInfo.version = Constants.supportedBackupVersion
|
||||
backupInfo.backupTimeMs = dateProvider().ows_millisecondsSince1970
|
||||
|
||||
switch stream.writeHeader(backupInfo) {
|
||||
case .success:
|
||||
break
|
||||
@@ -416,7 +416,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
|
||||
tx: DBWriteTransaction
|
||||
) throws {
|
||||
|
||||
let backupInfo: BackupProto.BackupInfo
|
||||
let backupInfo: BackupProto_BackupInfo
|
||||
var hasMoreFrames = false
|
||||
switch stream.readHeader() {
|
||||
case .success(let header, let moreBytesAvailable):
|
||||
@@ -441,7 +441,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
|
||||
)
|
||||
|
||||
while hasMoreFrames {
|
||||
let frame: BackupProto.Frame
|
||||
let frame: BackupProto_Frame
|
||||
switch stream.readFrame() {
|
||||
case let .success(_frame, moreBytesAvailable):
|
||||
frame = _frame
|
||||
@@ -463,7 +463,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
|
||||
.invalidProtoData(.recipientMissingDestination),
|
||||
recipient.recipientId
|
||||
)])
|
||||
case .selfRecipient(let selfRecipientProto):
|
||||
case .self_p(let selfRecipientProto):
|
||||
recipientResult = localRecipientArchiver.restoreSelfRecipient(
|
||||
selfRecipientProto,
|
||||
recipient: recipient,
|
||||
@@ -553,15 +553,15 @@ public class MessageBackupManagerImpl: MessageBackupManager {
|
||||
// TODO: [Backups] Restore sticker packs.
|
||||
try processRestoreFrameErrors(errors: [.restoreFrameError(
|
||||
.unimplemented,
|
||||
MessageBackup.StickerPackId(backupProtoStickerPack.packId)
|
||||
MessageBackup.StickerPackId(backupProtoStickerPack.packID)
|
||||
)])
|
||||
case .adHocCall(let backupProtoAdHocCall):
|
||||
// TODO: [Backups] Restore ad-hoc calls.
|
||||
try processRestoreFrameErrors(errors: [.restoreFrameError(
|
||||
.unimplemented,
|
||||
MessageBackup.AdHocCallId(
|
||||
backupProtoAdHocCall.callId,
|
||||
recipientId: backupProtoAdHocCall.recipientId
|
||||
backupProtoAdHocCall.callID,
|
||||
recipientId: backupProtoAdHocCall.recipientID
|
||||
)
|
||||
)])
|
||||
case nil:
|
||||
|
||||
@@ -115,37 +115,41 @@ public struct ArchivedPayment: Codable, Hashable, FetchableRecord, PersistableRe
|
||||
}
|
||||
|
||||
extension ArchivedPayment {
|
||||
func toTransactionDetailsProto() -> BackupProto.PaymentNotification.TransactionDetails {
|
||||
var transactionDetails = BackupProto.PaymentNotification.TransactionDetails()
|
||||
func toTransactionDetailsProto() -> BackupProto_PaymentNotification.TransactionDetails {
|
||||
var transactionDetails = BackupProto_PaymentNotification.TransactionDetails()
|
||||
|
||||
if status.isFailure {
|
||||
let reason: BackupProto.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason = {
|
||||
let reason: BackupProto_PaymentNotification.TransactionDetails.FailedTransaction.FailureReason = {
|
||||
switch failureReason {
|
||||
case .genericFailure: return .GENERIC
|
||||
case .networkFailure: return .NETWORK
|
||||
case .insufficientFundsFailure: return .INSUFFICIENT_FUNDS
|
||||
case .genericFailure: return .generic
|
||||
case .networkFailure: return .network
|
||||
case .insufficientFundsFailure: return .insufficientFunds
|
||||
case .none:
|
||||
owsFailDebug("Invalid status for failure type")
|
||||
return .GENERIC
|
||||
return .generic
|
||||
}
|
||||
}()
|
||||
|
||||
transactionDetails.payment = .failedTransaction(.init(reason: reason))
|
||||
var failedTransaction = BackupProto_PaymentNotification.TransactionDetails.FailedTransaction()
|
||||
failedTransaction.reason = reason
|
||||
|
||||
transactionDetails.payment = .failedTransaction(failedTransaction)
|
||||
} else {
|
||||
let success: BackupProto.PaymentNotification.TransactionDetails.Transaction.Status = {
|
||||
let success: BackupProto_PaymentNotification.TransactionDetails.Transaction.Status = {
|
||||
switch status {
|
||||
case .initial: return .INITIAL
|
||||
case .submitted: return .SUBMITTED
|
||||
case .successful: return .SUCCESSFUL
|
||||
case .initial: return .initial
|
||||
case .submitted: return .submitted
|
||||
case .successful: return .successful
|
||||
case .error:
|
||||
owsFailDebug("Invalid status for success type")
|
||||
return .SUCCESSFUL
|
||||
return .successful
|
||||
}
|
||||
}()
|
||||
|
||||
var transaction = BackupProto.PaymentNotification.TransactionDetails.Transaction(status: success)
|
||||
var transaction = BackupProto_PaymentNotification.TransactionDetails.Transaction()
|
||||
transaction.status = success
|
||||
|
||||
var identification = BackupProto.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification()
|
||||
var identification = BackupProto_PaymentNotification.TransactionDetails.MobileCoinTxoIdentification()
|
||||
if let keyImages = mobileCoinIdentification?.keyImages {
|
||||
identification.keyImages = keyImages
|
||||
}
|
||||
@@ -154,11 +158,11 @@ extension ArchivedPayment {
|
||||
}
|
||||
transaction.mobileCoinIdentification = identification
|
||||
|
||||
transaction.timestamp = timestamp
|
||||
transaction.blockIndex = blockIndex
|
||||
transaction.blockTimestamp = blockTimestamp
|
||||
transaction.transaction = self.transaction
|
||||
transaction.receipt = receipt
|
||||
if let timestamp { transaction.timestamp = timestamp }
|
||||
if let blockIndex { transaction.blockIndex = blockIndex }
|
||||
if let blockTimestamp { transaction.blockIndex = blockTimestamp }
|
||||
if let _transaction = self.transaction { transaction.transaction = _transaction }
|
||||
if let receipt { transaction.receipt = receipt }
|
||||
|
||||
transactionDetails.payment = .transaction(transaction)
|
||||
}
|
||||
|
||||
13324
SignalServiceKit/protobuf/Backups/Backup.pb.swift
Normal file
13324
SignalServiceKit/protobuf/Backups/Backup.pb.swift
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,7 @@
|
||||
# Backup Proto
|
||||
# Backup protos
|
||||
|
||||
The Backup protos are generated using [Wire](https://github.com/square/wire),
|
||||
in contrast with the rest of the Signal-iOS protos which use (at the time of
|
||||
writing) a combination of
|
||||
[Swift-Protobuf](https://github.com/apple/swift-protobuf/) and bespoke
|
||||
code-generation in [ProtoWrappers.py](../../../Scripts/protos/ProtoWrappers.py).
|
||||
## `Swift-Protobuf`
|
||||
|
||||
Using `Wire` for Backups obviates the need for updates to `ProtoWrappers.py`,
|
||||
and the models generated by `Wire` are easier to work with than those generated
|
||||
by `ProtoWrappers.py`.
|
||||
We use [`Swift-Protobuf`](https://github.com/apple/swift-protobuf) to generate Swift code for working with `Backup.proto`, much like we do for all our other proto definitions.
|
||||
|
||||
Additionally, the `Wire`-generated models expose `optional` protobuf fields as
|
||||
`Optional` values in Swift. This is in contrast to `Swift-Protobuf`, which
|
||||
exposes those fields as non-`Optional` (with a default value returned if none is
|
||||
present) with `hasField` properties allowing the caller to inspect if a value
|
||||
was explicitly set. While the `Swift-Protobuf` approach is arguably closer to
|
||||
the raw behavior of protobufs, the `Wire` approach more directly supports the
|
||||
type-safe calling patterns we want to use in code.
|
||||
|
||||
## How to generate models
|
||||
|
||||
See [compile-backups-proto-with-wire](../../../Scripts/protos/compile-backups-proto-with-wire).
|
||||
That script reads the `Backup.proto` file in this directory, downloads the
|
||||
`Wire` (if necessary), and runs it to generate models to the right place.
|
||||
|
||||
## Special considerations when using `Wire`
|
||||
|
||||
`Wire` does not support adding a prefix to type names for namespacing purposes.
|
||||
To achieve the same result we instead nest all proto types in `Backup.proto`
|
||||
under a top-level `message BackupProto`, such that when they are generated the
|
||||
corresponding Swift types are nested under a generated (empty)
|
||||
`struct BackupProto`.
|
||||
However, unlike the other protos, we do not use the "wrapper" code generated by `$REPO_ROOT/Scripts/protos/ProtoWrappers.py` to wrap the `Swift-Protobuf`-generated code for Backups, because `ProtoWrappers.py` is incompatible with some of the syntactic structures we use in `Backup.proto`.
|
||||
|
||||
16
SignalServiceKit/protobuf/Backups/generate-backup-protos.sh
Executable file
16
SignalServiceKit/protobuf/Backups/generate-backup-protos.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
BACKUP_PROTO_DIR="$REPO_ROOT/SignalServiceKit/protobuf/Backups"
|
||||
BACKUP_PROTO_FILE="$BACKUP_PROTO_DIR/Backup.proto"
|
||||
BACKUP_SWIFT_FILE="$BACKUP_PROTO_DIR/Backup.pb.swift"
|
||||
|
||||
echo "Generating Backup.pb.swift file with protoc and Swift-Protobuf..."
|
||||
|
||||
protoc \
|
||||
--proto_path="$BACKUP_PROTO_DIR" \
|
||||
--swift_out="$BACKUP_PROTO_DIR" \
|
||||
--swift_opt=Visibility=public \
|
||||
"$BACKUP_PROTO_FILE"
|
||||
|
||||
"$REPO_ROOT"/Scripts/lint/lint-license-headers --fix "$BACKUP_PROTO_FILE"
|
||||
@@ -188,8 +188,8 @@ extension IncomingContactSyncJobRecord: ValidatableModel {
|
||||
IncomingContactSyncJobRecord(
|
||||
cdnNumber: 3,
|
||||
cdnKey: "hello",
|
||||
encryptionKey: Data(base64URLEncoded: "mMiOmZhbHNlLCJzdXBlciI6eyJ1b")!,
|
||||
digest: Data(base64URLEncoded: "291bnQiOjYsInJlY29yZFR5cGUiO")!,
|
||||
encryptionKey: Data(base64Encoded: "mMiOmZhbHNlLCJzdXBlciI6eyJ1b")!,
|
||||
digest: Data(base64Encoded: "291bnQiOjYsInJlY29yZFR5cGUiO")!,
|
||||
plaintextLength: 55,
|
||||
isCompleteContactSync: true
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user