Compare commits
1 Commits
master
...
charlesmch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3073c98ca0 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,7 +17,6 @@ DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
xcshareddata
|
||||
|
||||
Pods/
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
language: objective-c
|
||||
|
||||
osx_image: xcode8.3
|
||||
osx_image: xcode8
|
||||
|
||||
env:
|
||||
-EARLY_START_SIMULATOR=1 # early starting simulator reduces false negatives due to test timeouts
|
||||
|
||||
before_install:
|
||||
- brew update
|
||||
- bundle
|
||||
- bundle exec pod repo update --silent
|
||||
- gem install cocoapods xcpretty --no-ri --no-rdoc
|
||||
- pod repo update --silent
|
||||
|
||||
after_failure:
|
||||
- sleep 10 # This prevents the occasional output truncation that happens when piping to xcpretty.
|
||||
|
||||
script: make scan_test
|
||||
script: make
|
||||
|
||||
|
||||
@ -11,19 +11,3 @@ target 'TSKitiOSTestApp' do
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
if target.to_s == "SignalServiceKit"
|
||||
puts "--[!] Disabling singleton enforcement for SSK."
|
||||
target.build_configurations.each do |config|
|
||||
existing_definitions = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS']
|
||||
if existing_definitions == nil || existing.length == 0
|
||||
existing_definitions = "$(inheritied)"
|
||||
end
|
||||
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = "#{existing_definitions} SSK_BUILDING_FOR_TESTS=1"
|
||||
config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-DSSK_BUILDING_FOR_TESTS']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -17,7 +17,6 @@ PODS:
|
||||
- AFNetworking/NSURLSession
|
||||
- AxolotlKit (0.8.1):
|
||||
- 25519 (~> 2.0.1)
|
||||
- CocoaLumberjack
|
||||
- HKDFKit (~> 0.0.3)
|
||||
- ProtocolBuffers (~> 1.9.8)
|
||||
- CocoaLumberjack (2.4.0):
|
||||
@ -29,11 +28,12 @@ PODS:
|
||||
- CocoaLumberjack/Extensions (2.4.0):
|
||||
- CocoaLumberjack/Default
|
||||
- HKDFKit (0.0.3)
|
||||
- libPhoneNumber-iOS (0.9.10)
|
||||
- libPhoneNumber-iOS (0.9.4)
|
||||
- Mantle (2.1.0):
|
||||
- Mantle/extobjc (= 2.1.0)
|
||||
- Mantle/extobjc (2.1.0)
|
||||
- ProtocolBuffers (1.9.11)
|
||||
- Reachability (3.2)
|
||||
- SAMKeychain (1.5.2)
|
||||
- SignalServiceKit (0.9.0):
|
||||
- '25519'
|
||||
@ -45,7 +45,7 @@ PODS:
|
||||
- SAMKeychain
|
||||
- SocketRocket
|
||||
- TwistedOakCollapsingFutures
|
||||
- YapDatabase/SQLCipher (~> 2.9.3)
|
||||
- YapDatabase/SQLCipher
|
||||
- SocketRocket (0.5.1)
|
||||
- SQLCipher/common (3.4.1)
|
||||
- SQLCipher/fts (3.4.1):
|
||||
@ -53,53 +53,54 @@ PODS:
|
||||
- TwistedOakCollapsingFutures (1.0.0):
|
||||
- UnionFind (~> 1.0)
|
||||
- UnionFind (1.0.1)
|
||||
- YapDatabase/SQLCipher (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Core (2.9.3):
|
||||
- YapDatabase/SQLCipher (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Core (2.9.2):
|
||||
- CocoaLumberjack (~> 2)
|
||||
- SQLCipher/fts
|
||||
- YapDatabase/SQLCipher/Extensions (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/ActionManager (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/Views (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions/ActionManager (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/ActionManager (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/Views (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions/ActionManager (2.9.2):
|
||||
- Reachability (~> 3)
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views (2.9.3):
|
||||
- YapDatabase/SQLCipher/Extensions/Views (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
|
||||
DEPENDENCIES:
|
||||
@ -111,13 +112,13 @@ EXTERNAL SOURCES:
|
||||
AxolotlKit:
|
||||
:git: https://github.com/WhisperSystems/SignalProtocolKit.git
|
||||
SignalServiceKit:
|
||||
:path: ../../SignalServiceKit.podspec
|
||||
:path: "../../SignalServiceKit.podspec"
|
||||
SocketRocket:
|
||||
:git: https://github.com/facebook/SocketRocket.git
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
AxolotlKit:
|
||||
:commit: 28afe5c1dbcfdea73d147e464c53d191d1e3ea50
|
||||
:commit: a3c843cc8a423c5924c663490978f81dba34d04e
|
||||
:git: https://github.com/WhisperSystems/SignalProtocolKit.git
|
||||
SocketRocket:
|
||||
:commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf
|
||||
@ -126,20 +127,21 @@ CHECKOUT OPTIONS:
|
||||
SPEC CHECKSUMS:
|
||||
'25519': dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
|
||||
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
|
||||
AxolotlKit: a9530d6835baae0f204b1f6b9dd79b7901176f0d
|
||||
AxolotlKit: 240c7d761e4b1be9c6de78ebec498aaeedc978f4
|
||||
CocoaLumberjack: aa9dcab71bdf9eaf2a63bbd9ddc87863efe45457
|
||||
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
|
||||
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
|
||||
libPhoneNumber-iOS: 63bab980d1fc9783d82d955800ac9d7c1d81fde3
|
||||
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
|
||||
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
|
||||
SignalServiceKit: 2ad8d86da055e24ac3ea0354ec1d4b13251af28f
|
||||
SignalServiceKit: 59a79a51b89b963ba94db30cc99ed5212da0bb9f
|
||||
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
|
||||
SQLCipher: 43d12c0eb9c57fb438749618fc3ce0065509a559
|
||||
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
|
||||
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
|
||||
YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266
|
||||
YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f
|
||||
|
||||
PODFILE CHECKSUM: a0f4507b6b4e6f9da3250901b06187a67236e083
|
||||
PODFILE CHECKSUM: 1a7633963dbcaa43f298949d83c42c1cd1dce940
|
||||
|
||||
COCOAPODS: 1.2.1
|
||||
COCOAPODS: 1.2.0
|
||||
|
||||
@ -457,7 +457,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
276B029791E679B0E87877B7 /* [CP] Copy Pods Resources */ = {
|
||||
@ -532,7 +532,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FF3F51F81980908EDE1836B76AA3A1EC"
|
||||
BlueprintIdentifier = "1D0826C97B09E58C83B3C228FBC535FA"
|
||||
BuildableName = "libSignalServiceKit.a"
|
||||
BlueprintName = "SignalServiceKit"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
|
||||
189
Gemfile.lock
189
Gemfile.lock
@ -1,189 +0,0 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.5)
|
||||
activesupport (4.2.9)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.1)
|
||||
public_suffix (~> 2.0, >= 2.0.2)
|
||||
babosa (1.0.2)
|
||||
claide (1.0.2)
|
||||
cocoapods (1.2.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.1, < 2.0)
|
||||
cocoapods-core (= 1.2.1)
|
||||
cocoapods-deintegrate (>= 1.0.1, < 2.0)
|
||||
cocoapods-downloader (>= 1.1.3, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.2.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (~> 2.0.1)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.5.7)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (~> 1.1)
|
||||
xcodeproj (>= 1.4.4, < 2.0)
|
||||
cocoapods-core (1.2.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.1)
|
||||
cocoapods-downloader (1.1.3)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-trunk (1.2.0)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (= 0.7.8)
|
||||
cocoapods-try (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.5)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.9)
|
||||
declarative-option (0.1.0)
|
||||
domain_name (0.5.20170404)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.2.1)
|
||||
escape (0.0.4)
|
||||
excon (0.57.1)
|
||||
faraday (0.12.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.11.0.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.0)
|
||||
fastlane (2.46.0)
|
||||
CFPropertyList (>= 2.3, < 3.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 2.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.5, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
excon (>= 0.45.0, < 1.0.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.0.1, < 2.0.0)
|
||||
google-api-client (>= 0.12.0, < 0.13.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
mini_magick (~> 4.5.1)
|
||||
multi_json
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 1.1.0, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
slack-notifier (>= 1.3, < 2.0.0)
|
||||
terminal-notifier (>= 1.6.2, < 2.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (~> 0.5.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.4.4, < 2.0.0)
|
||||
xcpretty (>= 0.2.4, < 1.0.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fourflusher (2.0.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.0.3)
|
||||
google-api-client (0.12.0)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.5)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mime-types (~> 3.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
googleauth (0.5.1)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.4)
|
||||
logging (~> 2.0)
|
||||
memoist (~> 0.12)
|
||||
multi_json (~> 1.11)
|
||||
os (~> 0.9)
|
||||
signet (~> 0.7)
|
||||
highline (1.7.8)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (0.8.6)
|
||||
json (2.1.0)
|
||||
jwt (1.5.6)
|
||||
little-plugger (1.1.4)
|
||||
logging (2.2.2)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.10)
|
||||
memoist (0.16.0)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_magick (4.5.1)
|
||||
minitest (5.10.2)
|
||||
molinillo (0.5.7)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.2.3)
|
||||
nap (1.1.0)
|
||||
netrc (0.7.8)
|
||||
os (0.9.6)
|
||||
plist (3.3.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.0.2)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (1.1.0)
|
||||
rubyzip (1.2.1)
|
||||
security (0.1.3)
|
||||
signet (0.7.3)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.5)
|
||||
multi_json (~> 1.10)
|
||||
slack-notifier (1.5.1)
|
||||
terminal-notifier (1.8.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thread_safe (0.3.6)
|
||||
tty-screen (0.5.0)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.4)
|
||||
unicode-display_width (1.3.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.5.0)
|
||||
CFPropertyList (~> 2.3.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.3)
|
||||
xcpretty (0.2.8)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (0.0.4)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.6
|
||||
7
Makefile
7
Makefile
@ -14,11 +14,9 @@ default: test
|
||||
|
||||
test: pod_install retest
|
||||
|
||||
scan_test: pod_install scan
|
||||
|
||||
pod_install:
|
||||
cd $(WORKING_DIR) && \
|
||||
bundle exec pod install
|
||||
pod install
|
||||
|
||||
build: pod_install
|
||||
cd $(WORKING_DIR) && \
|
||||
@ -30,9 +28,6 @@ retest: optional_early_start_simulator
|
||||
-destination '${BUILD_DESTINATION}' \
|
||||
test | xcpretty
|
||||
|
||||
scan:
|
||||
bundle exec fastlane scan
|
||||
|
||||
clean:
|
||||
cd $(WORKING_DIR) && \
|
||||
$(XCODE_BUILD) \
|
||||
|
||||
24
README.md
24
README.md
@ -1,27 +1,3 @@
|
||||
# SignalServiceKit has Moved
|
||||
|
||||
Per https://github.com/WhisperSystems/Signal-iOS/pull/2341 we've moved
|
||||
the SignalServiceKit codebase into the primary Signal-iOS repository at
|
||||
https://github.com/WhisperSystems/Signal-iOS. As such, this repository
|
||||
will no longer be updated.
|
||||
|
||||
Don't worry - we will continue to make updates to SignalServiceKit, and
|
||||
you can continue to use it in your projects as before. The only
|
||||
difference is where the code lives.
|
||||
|
||||
If you are using Cocoapods, staying up to date is as simple as modifying
|
||||
a line in your Podfile from this:
|
||||
|
||||
```
|
||||
- pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git'
|
||||
```
|
||||
|
||||
To this:
|
||||
|
||||
```
|
||||
+ pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/Signal-iOS.git'
|
||||
```
|
||||
|
||||
# SignalServiceKit
|
||||
|
||||
SignalServiceKit is an Objective-C library for communicating with the Signal
|
||||
|
||||
@ -17,37 +17,15 @@ An Objective-C library for communicating with the Signal messaging service.
|
||||
|
||||
s.homepage = "https://github.com/WhisperSystems/SignalServiceKit"
|
||||
s.license = 'GPLv3'
|
||||
s.author = { "Whisper Systems" => "ios@whispersystems.com" }
|
||||
s.author = { "Frederic Jacobs" => "github@fredericjacobs.com" }
|
||||
s.source = { :git => "https://github.com/WhisperSystems/SignalServiceKit.git", :tag => s.version.to_s }
|
||||
s.social_media_url = 'https://twitter.com/WhipserSystems'
|
||||
|
||||
deprecation_message = <<EOS
|
||||
installing SignalServiceKit via the Signal-iOS repository.
|
||||
|
||||
To get future updates, point your Podfile at the new location. Simply change this:
|
||||
|
||||
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git'
|
||||
|
||||
To this:
|
||||
|
||||
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/Signal-iOS.git'
|
||||
|
||||
Sorry for the disruption!
|
||||
|
||||
EOS
|
||||
|
||||
s.deprecated_in_favor_of = deprecation_message
|
||||
s.social_media_url = 'https://twitter.com/FredericJacobs'
|
||||
|
||||
s.platform = :ios, '8.0'
|
||||
#s.ios.deployment_target = '8.0'
|
||||
#s.osx.deployment_target = '10.9'
|
||||
s.requires_arc = true
|
||||
|
||||
# By not including any actual files, upgrading users will see
|
||||
# that they need to point upgrades to the new source at
|
||||
# https://github.com/WhisperSystems/Signal-iOS
|
||||
# Details in README.md
|
||||
s.source_files = 'README.md'
|
||||
s.source_files = 'src/**/*.{h,m,mm}'
|
||||
|
||||
s.resources = ['src/Security/PinningCertificate/textsecure.cer',
|
||||
'src/Security/PinningCertificate/GIAG2.crt']
|
||||
|
||||
1
fastlane/.gitignore
vendored
1
fastlane/.gitignore
vendored
@ -1 +0,0 @@
|
||||
test_output
|
||||
@ -1,8 +0,0 @@
|
||||
# For more information about this configuration visit
|
||||
# https://github.com/fastlane/fastlane/tree/master/scan#scanfile
|
||||
|
||||
workspace "Example/TSKitiOSTestApp/TSKitiOSTestApp.xcworkspace"
|
||||
scheme "TSKitiOSTestApp"
|
||||
|
||||
devices ["iPhone SE"]
|
||||
|
||||
@ -34,24 +34,6 @@ message Content {
|
||||
optional DataMessage dataMessage = 1;
|
||||
optional SyncMessage syncMessage = 2;
|
||||
optional CallMessage callMessage = 3;
|
||||
optional NullMessage nullMessage = 4;
|
||||
}
|
||||
|
||||
message NullMessage {
|
||||
optional bytes padding = 1;
|
||||
}
|
||||
|
||||
message Verified {
|
||||
enum State {
|
||||
DEFAULT = 0;
|
||||
VERIFIED = 1;
|
||||
UNVERIFIED = 2;
|
||||
}
|
||||
|
||||
optional string destination = 1;
|
||||
optional bytes identityKey = 2;
|
||||
optional State state = 3;
|
||||
optional bytes nullMessage = 4;
|
||||
}
|
||||
|
||||
message CallMessage {
|
||||
@ -142,14 +124,26 @@ message SyncMessage {
|
||||
optional uint64 timestamp = 2;
|
||||
}
|
||||
|
||||
optional Sent sent = 1;
|
||||
optional Contacts contacts = 2;
|
||||
optional Groups groups = 3;
|
||||
optional Request request = 4;
|
||||
repeated Read read = 5;
|
||||
optional Blocked blocked = 6;
|
||||
optional Verified verified = 7;
|
||||
optional bytes padding = 8;
|
||||
message Verification {
|
||||
enum State {
|
||||
DEFAULT = 0;
|
||||
VERIFIED = 1;
|
||||
NO_LONGER_VERIFIED = 2;
|
||||
}
|
||||
|
||||
optional State state = 1;
|
||||
// The e164 phone number of the user.
|
||||
optional string destination = 2;
|
||||
optional bytes identityKey = 3;
|
||||
}
|
||||
|
||||
optional Sent sent = 1;
|
||||
optional Contacts contacts = 2;
|
||||
optional Groups groups = 3;
|
||||
optional Request request = 4;
|
||||
repeated Read read = 5;
|
||||
optional Blocked blocked = 6;
|
||||
repeated Verification verification = 7;
|
||||
}
|
||||
|
||||
message AttachmentPointer {
|
||||
@ -192,7 +186,6 @@ message ContactDetails {
|
||||
optional string name = 2;
|
||||
optional Avatar avatar = 3;
|
||||
optional string color = 4;
|
||||
optional Verified verified = 5;
|
||||
}
|
||||
|
||||
message GroupDetails {
|
||||
|
||||
@ -244,12 +244,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (NSArray<NSString *> *)textSecureIdentifiers {
|
||||
__block NSMutableArray *identifiers = [NSMutableArray array];
|
||||
|
||||
[[TSStorageManager sharedManager].dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
if ([SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction]) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
if ([SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction]) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
}];
|
||||
return [identifiers copy];
|
||||
}
|
||||
|
||||
@ -122,11 +122,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
NSMutableSet *recipientIds = [NSMutableSet set];
|
||||
[[TSStorageManager sharedManager].dbReadConnection
|
||||
readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
||||
[recipientIds addObjectsFromArray:allRecipientKeys];
|
||||
}];
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
||||
[recipientIds addObjectsFromArray:allRecipientKeys];
|
||||
}];
|
||||
|
||||
NSMutableSet<NSString *> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
|
||||
|
||||
@ -135,7 +135,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[recipientIds minusSet:matchedIds];
|
||||
|
||||
// Cleaning up unregistered identifiers
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
[[TSStorageManager sharedManager].dbConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in recipientIds) {
|
||||
SignalRecipient *recipient =
|
||||
@ -185,22 +185,23 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
// Insert or update contact attributes
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in attributesForIdentifier) {
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient recipientWithTextSecureIdentifier:identifier withTransaction:transaction];
|
||||
if (!recipient) {
|
||||
recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier relay:nil];
|
||||
}
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in attributesForIdentifier) {
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient recipientWithTextSecureIdentifier:identifier withTransaction:transaction];
|
||||
if (!recipient) {
|
||||
recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier
|
||||
relay:nil];
|
||||
}
|
||||
|
||||
NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
|
||||
NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
|
||||
|
||||
recipient.relay = attributes[@"relay"];
|
||||
recipient.relay = attributes[@"relay"];
|
||||
|
||||
[recipient saveWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
[recipient saveWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
success([NSSet setWithArray:attributesForIdentifier.allKeys]);
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
NBPhoneNumber *number = [phoneUtil parse:text defaultRegion:regionCode error:&parseError];
|
||||
|
||||
if (parseError) {
|
||||
DDLogDebug(@"Issue while parsing number: %@", [parseError description]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@ -85,9 +85,6 @@
|
||||
NSDictionary *countryCodeComponent = @{NSLocaleCountryCode : countryCode};
|
||||
NSString *identifier = [NSLocale localeIdentifierFromComponents:countryCodeComponent];
|
||||
NSString *country = [NSLocale.currentLocale displayNameForKey:NSLocaleIdentifier value:identifier];
|
||||
if (country.length < 1) {
|
||||
country = [NSLocale.systemLocale displayNameForKey:NSLocaleIdentifier value:identifier];
|
||||
}
|
||||
return country;
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
{
|
||||
__block SignalRecipient *recipient;
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
recipient = [self recipientWithTextSecureIdentifier:textSecureIdentifier withTransaction:transaction];
|
||||
}];
|
||||
return recipient;
|
||||
|
||||
@ -176,6 +176,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// data loss and will resolve all known issues.
|
||||
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate;
|
||||
|
||||
// Returns YES IFF the interaction should show up in the inbox as the last message.
|
||||
+ (BOOL)shouldInteractionAppearInInbox:(TSInteraction *)interaction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -131,7 +131,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)enumerateInteractionsUsingBlock:(void (^)(TSInteraction *interaction))block
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self enumerateInteractionsWithTransaction:transaction
|
||||
usingBlock:^(
|
||||
TSInteraction *interaction, YapDatabaseReadTransaction *transaction) {
|
||||
@ -172,7 +172,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (NSUInteger)numberOfInteractions
|
||||
{
|
||||
__block NSUInteger count;
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
count = [interactionsByThread numberOfItemsInGroup:self.uniqueId];
|
||||
}];
|
||||
@ -193,7 +193,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (NSArray<id<OWSReadTracking>> *)unseenMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
NSMutableArray<id<OWSReadTracking>> *messages = [NSMutableArray new];
|
||||
[[TSDatabaseView unseenDatabaseViewExtension:transaction]
|
||||
[[transaction ext:TSUnseenDatabaseViewExtensionName]
|
||||
enumerateRowsInGroup:self.uniqueId
|
||||
usingBlock:^(
|
||||
NSString *collection, NSString *key, id object, id metadata, NSUInteger index, BOOL *stop) {
|
||||
@ -237,7 +237,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (TSInteraction *) lastInteraction {
|
||||
__block TSInteraction *last;
|
||||
[TSStorageManager.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[TSStorageManager.sharedManager.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
||||
last = [[transaction ext:TSMessageDatabaseViewExtensionName] lastObjectInGroup:self.uniqueId];
|
||||
}];
|
||||
return last;
|
||||
@ -246,7 +246,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (TSInteraction *)lastInteractionForInbox
|
||||
{
|
||||
__block TSInteraction *last = nil;
|
||||
[TSStorageManager.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[TSStorageManager.sharedManager.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[transaction ext:TSMessageDatabaseViewExtensionName]
|
||||
enumerateRowsInGroup:self.uniqueId
|
||||
withOptions:NSEnumerationReverse
|
||||
@ -283,12 +283,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
}
|
||||
|
||||
// Returns YES IFF the interaction should show up in the inbox as the last message.
|
||||
+ (BOOL)shouldInteractionAppearInInbox:(TSInteraction *)interaction
|
||||
{
|
||||
OWSAssert(interaction);
|
||||
|
||||
if (interaction.isDynamicInteraction) {
|
||||
DDLogDebug(@"%@ not showing dynamic interaction in inbox: %@", self.tag, interaction.debugDescription);
|
||||
return NO;
|
||||
}
|
||||
|
||||
@ -297,11 +297,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange) {
|
||||
// Otherwise all group threads with the recipient will percolate to the top of the inbox, even though
|
||||
// there was no meaningful interaction.
|
||||
DDLogDebug(
|
||||
@"%@ not showing nonblocking identity change in inbox: %@", self.tag, errorMessage.debugDescription);
|
||||
return NO;
|
||||
}
|
||||
} else if ([interaction isKindOfClass:[TSInfoMessage class]]) {
|
||||
TSInfoMessage *infoMessage = (TSInfoMessage *)interaction;
|
||||
if (infoMessage.messageType == TSInfoMessageVerificationStateChange) {
|
||||
DDLogDebug(
|
||||
@"%@ not showing verification state change in inbox: %@", self.tag, infoMessage.debugDescription);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@ -397,7 +401,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestThread:transaction
|
||||
changeBlock:^(TSThread *thread) {
|
||||
[thread setMutedUntilDate:mutedUntilDate];
|
||||
|
||||
@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSAssert(contactId.length > 0);
|
||||
|
||||
__block TSContactThread *thread;
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [self getOrCreateThreadWithContactId:contactId transaction:transaction];
|
||||
}];
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSAssert(groupModel.groupId.length > 0);
|
||||
|
||||
__block TSGroupThread *thread;
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [self getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
}];
|
||||
return thread;
|
||||
|
||||
@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBlockedBuilder *blockedPhoneNumbersBuilder =
|
||||
[OWSSignalServiceProtosSyncMessageBlockedBuilder new];
|
||||
@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setBlocked:[blockedPhoneNumbersBuilder build]];
|
||||
|
||||
return syncMessageBuilder;
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -7,12 +7,10 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAccount;
|
||||
@class OWSRecipientIdentity;
|
||||
|
||||
@interface OWSContactsOutputStream : OWSChunkedOutputStream
|
||||
|
||||
- (void)writeSignalAccount:(SignalAccount *)signalAccount
|
||||
recipientIdentity:(nullable OWSRecipientIdentity *)recipientIdentity;
|
||||
- (void)writeSignalAccount:(SignalAccount *)signalAccount;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
#import "OWSContactsOutputStream.h"
|
||||
#import "Contact.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "NSData+keyVersionByte.h"
|
||||
#import "OWSRecipientIdentity.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "SignalAccount.h"
|
||||
#import <ProtocolBuffers/CodedOutputStream.h>
|
||||
@ -16,23 +14,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@implementation OWSContactsOutputStream
|
||||
|
||||
- (void)writeSignalAccount:(SignalAccount *)signalAccount
|
||||
recipientIdentity:(nullable OWSRecipientIdentity *)recipientIdentity
|
||||
{
|
||||
OWSAssert(signalAccount);
|
||||
OWSAssert(signalAccount.contact);
|
||||
|
||||
|
||||
OWSSignalServiceProtosContactDetailsBuilder *contactBuilder = [OWSSignalServiceProtosContactDetailsBuilder new];
|
||||
[contactBuilder setName:signalAccount.contact.fullName];
|
||||
[contactBuilder setNumber:signalAccount.recipientId];
|
||||
|
||||
if (recipientIdentity != nil) {
|
||||
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
|
||||
verifiedBuilder.destination = recipientIdentity.recipientId;
|
||||
verifiedBuilder.identityKey = [recipientIdentity.identityKey prependKeyType];
|
||||
verifiedBuilder.state = OWSVerificationStateToProtoState(recipientIdentity.verificationState);
|
||||
contactBuilder.verifiedBuilder = verifiedBuilder;
|
||||
}
|
||||
|
||||
NSData *avatarPng;
|
||||
if (signalAccount.contact.image) {
|
||||
OWSSignalServiceProtosContactDetailsAvatarBuilder *avatarBuilder =
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSReadReceipt.h"
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
@ -106,7 +104,7 @@ NSString *const OWSReadReceiptColumnSenderId = @"senderId";
|
||||
stringWithFormat:@"WHERE %@ = ? AND %@ = ?", OWSReadReceiptColumnSenderId, OWSReadReceiptColumnTimestamp];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:queryFormat, senderId, @(timestamp)];
|
||||
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSReadReceiptIndexOnSenderIdAndTimestamp]
|
||||
enumerateKeysAndObjectsMatchingQuery:query
|
||||
usingBlock:^(NSString *collection, NSString *key, id object, BOOL *stop) {
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSReadReceiptsMessage.h"
|
||||
#import "OWSReadReceipt.h"
|
||||
@ -28,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
for (OWSReadReceipt *readReceipt in self.readReceipts) {
|
||||
@ -39,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[syncMessageBuilder addRead:[readProtoBuilder build]];
|
||||
}
|
||||
|
||||
return syncMessageBuilder;
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -94,9 +94,8 @@ NSString *const OWSReadReceiptsProcessorMarkedMessageAsReadNotification =
|
||||
// Always mark the message specified by the read receipt as read.
|
||||
[interactionsToMarkAsRead addObject:message];
|
||||
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[TSDatabaseView unseenDatabaseViewExtension:transaction]
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[transaction ext:TSUnseenDatabaseViewExtensionName]
|
||||
enumerateRowsInGroup:message.uniqueThreadId
|
||||
usingBlock:^(NSString *collection,
|
||||
NSString *key,
|
||||
|
||||
@ -9,15 +9,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSVerificationStateSyncMessage : OWSOutgoingSyncMessage
|
||||
|
||||
- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
verificationForRecipientId:(NSString *)recipientId;
|
||||
- (void)addVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId;
|
||||
|
||||
// This is a clunky name, but we want to differentiate it from `recipientIdentifier` inherited from `TSOutgoingMessage`
|
||||
@property (nonatomic, readonly) NSString *verificationForRecipientId;
|
||||
|
||||
@property (nonatomic, readonly) size_t paddingBytesLength;
|
||||
@property (nonatomic, readonly) size_t unpaddedVerifiedLength;
|
||||
// Returns the list of recipient ids referenced in this message.
|
||||
- (NSArray<NSString *> *)recipientIds;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -3,18 +3,29 @@
|
||||
//
|
||||
|
||||
#import "OWSVerificationStateSyncMessage.h"
|
||||
#import "Cryptography.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSVerificationStateTuple : NSObject
|
||||
|
||||
@property (nonatomic) OWSVerificationState verificationState;
|
||||
@property (nonatomic) NSData *identityKey;
|
||||
@property (nonatomic) NSString *recipientId;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSVerificationStateTuple
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSVerificationStateSyncMessage ()
|
||||
|
||||
@property (nonatomic, readonly) OWSVerificationState verificationState;
|
||||
@property (nonatomic, readonly) NSData *identityKey;
|
||||
@property (nonatomic, readonly) NSMutableArray<OWSVerificationStateTuple *> *tuples;
|
||||
|
||||
@end
|
||||
|
||||
@ -22,78 +33,68 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OWSVerificationStateSyncMessage
|
||||
|
||||
- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
verificationForRecipientId:(NSString *)verificationForRecipientId
|
||||
- (instancetype)init
|
||||
{
|
||||
OWSAssert(identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(verificationForRecipientId.length > 0);
|
||||
|
||||
// we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device
|
||||
// will figure that out on it's own.
|
||||
OWSAssert(verificationState != OWSVerificationStateNoLongerVerified);
|
||||
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_verificationState = verificationState;
|
||||
_identityKey = identityKey;
|
||||
_verificationForRecipientId = verificationForRecipientId;
|
||||
|
||||
// This sync message should be 1-512 bytes longer than the corresponding NullMessage
|
||||
// we store this values so the corresponding NullMessage can subtract it from the total length.
|
||||
_paddingBytesLength = arc4random_uniform(512) + 1;
|
||||
|
||||
_tuples = [NSMutableArray new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (void)addVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(self.identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(self.verificationForRecipientId.length > 0);
|
||||
OWSAssert(identityKey.length > 0);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
OWSAssert(self.tuples);
|
||||
|
||||
// we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device
|
||||
// will figure that out on it's own.
|
||||
OWSAssert(self.verificationState != OWSVerificationStateNoLongerVerified);
|
||||
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
|
||||
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
|
||||
verifiedBuilder.destination = self.verificationForRecipientId;
|
||||
verifiedBuilder.identityKey = self.identityKey;
|
||||
verifiedBuilder.state = OWSVerificationStateToProtoState(self.verificationState);
|
||||
|
||||
OWSAssert(self.paddingBytesLength != 0);
|
||||
|
||||
// We add the same amount of padding in the VerificationStateSync message and it's coresponding NullMessage so that
|
||||
// the sync message is indistinguishable from an outgoing Sent transcript corresponding to the NullMessage. We pad
|
||||
// the NullMessage so as to obscure it's content. The sync message (like all sync messages) will be *additionally*
|
||||
// padded by the superclass while being sent. The end result is we send a NullMessage of a non-distinct size, and a
|
||||
// verification sync which is ~1-512 bytes larger then that.
|
||||
verifiedBuilder.nullMessage = [Cryptography generateRandomBytes:self.paddingBytesLength];
|
||||
|
||||
syncMessageBuilder.verifiedBuilder = verifiedBuilder;
|
||||
|
||||
return syncMessageBuilder;
|
||||
OWSVerificationStateTuple *tuple = [OWSVerificationStateTuple new];
|
||||
tuple.verificationState = verificationState;
|
||||
tuple.identityKey = identityKey;
|
||||
tuple.recipientId = recipientId;
|
||||
[self.tuples addObject:tuple];
|
||||
}
|
||||
|
||||
- (size_t)unpaddedVerifiedLength
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSAssert(self.identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(self.verificationForRecipientId.length > 0);
|
||||
OWSAssert(self.tuples.count > 0);
|
||||
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
for (OWSVerificationStateTuple *tuple in self.tuples) {
|
||||
OWSSignalServiceProtosSyncMessageVerificationBuilder *verificationBuilder = [OWSSignalServiceProtosSyncMessageVerificationBuilder new];
|
||||
verificationBuilder.destination = tuple.recipientId;
|
||||
verificationBuilder.identityKey = tuple.identityKey;
|
||||
switch (tuple.verificationState) {
|
||||
case OWSVerificationStateDefault:
|
||||
verificationBuilder.state = OWSSignalServiceProtosSyncMessageVerificationStateDefault;
|
||||
break;
|
||||
case OWSVerificationStateVerified:
|
||||
verificationBuilder.state = OWSSignalServiceProtosSyncMessageVerificationStateVerified;
|
||||
break;
|
||||
case OWSVerificationStateNoLongerVerified:
|
||||
verificationBuilder.state = OWSSignalServiceProtosSyncMessageVerificationStateNoLongerVerified;
|
||||
break;
|
||||
}
|
||||
[syncMessageBuilder addVerification:[verificationBuilder build]];
|
||||
}
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
// we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device
|
||||
// will figure that out on it's own.
|
||||
OWSAssert(self.verificationState != OWSVerificationStateNoLongerVerified);
|
||||
- (NSArray<NSString *> *)recipientIds
|
||||
{
|
||||
NSMutableArray<NSString *> *result = [NSMutableArray new];
|
||||
for (OWSVerificationStateTuple *tuple in self.tuples) {
|
||||
OWSAssert(tuple.recipientId.length > 0);
|
||||
[result addObject:tuple.recipientId];
|
||||
}
|
||||
|
||||
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
|
||||
verifiedBuilder.destination = self.verificationForRecipientId;
|
||||
verifiedBuilder.identityKey = self.identityKey;
|
||||
verifiedBuilder.state = OWSVerificationStateToProtoState(self.verificationState);
|
||||
|
||||
return [verifiedBuilder build].data.length;
|
||||
return [result copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -27,8 +27,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// This only applies for attachments being uploaded.
|
||||
@property (atomic) BOOL isUploaded;
|
||||
|
||||
@property (nonatomic, readonly) NSDate *creationTimestamp;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (nullable UIImage *)image;
|
||||
#endif
|
||||
@ -46,6 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (void)deleteAttachments;
|
||||
+ (NSString *)attachmentsFolder;
|
||||
+ (NSUInteger)numberOfItemsInAttachmentsFolder;
|
||||
|
||||
- (CGSize)imageSizeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (CGSize)imageSizeWithoutTransaction;
|
||||
|
||||
@ -41,9 +41,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// state, but this constructor is used only for new outgoing
|
||||
// attachments which haven't been uploaded yet.
|
||||
_isUploaded = NO;
|
||||
_creationTimestamp = [NSDate new];
|
||||
|
||||
[self ensureFilePath];
|
||||
// This instance hasn't been persisted yet.
|
||||
[self ensureFilePathAndPersist:NO];
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -63,9 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// attachments which don't need to be uploaded.
|
||||
_isUploaded = YES;
|
||||
self.attachmentType = pointer.attachmentType;
|
||||
_creationTimestamp = [NSDate new];
|
||||
|
||||
[self ensureFilePath];
|
||||
// This instance hasn't been persisted yet.
|
||||
[self ensureFilePathAndPersist:NO];
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -77,13 +77,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
// OWS105AttachmentFilePaths will ensure the file path is saved if necessary.
|
||||
[self ensureFilePath];
|
||||
|
||||
// OWS105AttachmentFilePaths will ensure the creation timestamp is saved if necessary.
|
||||
if (!_creationTimestamp) {
|
||||
_creationTimestamp = [NSDate new];
|
||||
}
|
||||
// This instance has been persisted, we need to
|
||||
// update it in the database.
|
||||
[self ensureFilePathAndPersist:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -101,7 +97,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ensureFilePath
|
||||
- (void)ensureFilePathAndPersist:(BOOL)shouldPersist
|
||||
{
|
||||
if (self.localRelativeFilePath) {
|
||||
return;
|
||||
@ -131,6 +127,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
self.localRelativeFilePath = localRelativeFilePath;
|
||||
OWSAssert(self.filePath);
|
||||
|
||||
if (shouldPersist) {
|
||||
// It's not ideal to do this asynchronously, but we can create a new transaction
|
||||
// within initWithCoder: which will be called from within a transaction.
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
OWSAssert(transaction);
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - File Management
|
||||
@ -162,31 +170,33 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (NSString *)attachmentsFolder
|
||||
{
|
||||
static NSString *attachmentsFolder = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *documentsPath =
|
||||
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
attachmentsFolder = [documentsPath stringByAppendingFormat:@"/Attachments"];
|
||||
NSString *documentsPath =
|
||||
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
NSString *attachmentFolder = [documentsPath stringByAppendingFormat:@"/Attachments"];
|
||||
|
||||
BOOL isDirectory;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentsFolder isDirectory:&isDirectory];
|
||||
if (exists) {
|
||||
OWSAssert(isDirectory);
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:attachmentFolder
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"Failed to create attachments directory: %@", error);
|
||||
}
|
||||
|
||||
DDLogInfo(@"Attachments directory already exists");
|
||||
} else {
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:attachmentsFolder
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"Failed to create attachments directory: %@", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
return attachmentsFolder;
|
||||
return attachmentFolder;
|
||||
}
|
||||
|
||||
+ (NSUInteger)numberOfItemsInAttachmentsFolder
|
||||
{
|
||||
NSError *error;
|
||||
NSUInteger count =
|
||||
[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self attachmentsFolder] error:&error] count];
|
||||
|
||||
if (error) {
|
||||
DDLogError(@"Unable to count attachments in attachments folder. Error: %@", error);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
- (nullable NSString *)filePath
|
||||
@ -281,28 +291,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (void)deleteAttachments
|
||||
{
|
||||
NSError *error;
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:self.attachmentsFolder];
|
||||
NSArray<NSURL *> *contents =
|
||||
[fileManager contentsOfDirectoryAtURL:fileURL includingPropertiesForKeys:nil options:0 error:&error];
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self attachmentsFolder] error:&error];
|
||||
if (error) {
|
||||
OWSFail(@"failed to get contents of attachments folder: %@ with error: %@", self.attachmentsFolder, error);
|
||||
return;
|
||||
DDLogError(@"Failed to delete attachment folder with error: %@", error.debugDescription);
|
||||
}
|
||||
|
||||
for (NSURL *url in contents) {
|
||||
NSError *deletionError;
|
||||
[fileManager removeItemAtURL:url error:&deletionError];
|
||||
if (deletionError) {
|
||||
OWSFail(@"failed to remove item at path: %@ with error: %@", url, deletionError);
|
||||
// continue to try to delete remaining items.
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
- (CGSize)calculateImageSize
|
||||
@ -374,7 +366,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (transaction) {
|
||||
updateDataStore(transaction);
|
||||
} else {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
updateDataStore(transaction);
|
||||
}];
|
||||
}
|
||||
@ -445,7 +437,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (transaction) {
|
||||
updateDataStore(transaction);
|
||||
} else {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
updateDataStore(transaction);
|
||||
}];
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSOutgoingSentMessageTranscript.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
@ -39,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
|
||||
@ -51,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
[syncMessageBuilder setSentBuilder:sentBuilder];
|
||||
|
||||
return syncMessageBuilder;
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
#import "OWSOutgoingSyncMessage.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "Cryptography.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -22,22 +21,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return NO;
|
||||
}
|
||||
|
||||
// This method should not be overridden, since we want to add random padding to *every* sync message
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBuilder *builder = [self syncMessageBuilder];
|
||||
|
||||
// Add a random 1-512 bytes to obscure sync message type
|
||||
size_t paddingBytesLength = arc4random_uniform(512) + 1;
|
||||
builder.padding = [Cryptography generateRandomBytes:paddingBytesLength];
|
||||
|
||||
return [builder build];
|
||||
}
|
||||
NSAssert(NO, @"buildSyncMessage must be overridden in subclass");
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSFail(@"Abstract method should be overridden in subclass.");
|
||||
return [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
// e.g.
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextData
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSOutgoingSyncMessage.h"
|
||||
|
||||
@ -8,13 +6,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
@protocol ContactsManagerProtocol;
|
||||
@class OWSIdentityManager;
|
||||
|
||||
@interface OWSSyncContactsMessage : OWSOutgoingSyncMessage
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
identityManager:(OWSIdentityManager *)identityManager;
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
- (NSData *)buildPlainTextAttachmentData;
|
||||
|
||||
@end
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSContactsOutputStream.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "SignalAccount.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -18,14 +17,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface OWSSyncContactsMessage ()
|
||||
|
||||
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
|
||||
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSSyncContactsMessage
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
{
|
||||
self = [super initWithTimestamp:[NSDate ows_millisecondTimeStamp]];
|
||||
if (!self) {
|
||||
@ -33,12 +30,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
_contactsManager = contactsManager;
|
||||
_identityManager = identityManager;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
if (self.attachmentIds.count != 1) {
|
||||
DDLogError(@"expected sync contact message to have exactly one attachment, but found %lu",
|
||||
@ -57,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setContactsBuilder:contactsBuilder];
|
||||
|
||||
return syncMessageBuilder;
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData
|
||||
@ -70,9 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSContactsOutputStream *contactsOutputStream = [OWSContactsOutputStream streamWithOutputStream:dataOutputStream];
|
||||
|
||||
for (SignalAccount *signalAccount in self.contactsManager.signalAccounts) {
|
||||
OWSRecipientIdentity *recipientIdentity = [self.identityManager recipientIdentityForRecipientId:signalAccount.recipientId];
|
||||
|
||||
[contactsOutputStream writeSignalAccount:signalAccount recipientIdentity:recipientIdentity];
|
||||
[contactsOutputStream writeSignalAccount:signalAccount];
|
||||
}
|
||||
|
||||
[contactsOutputStream flush];
|
||||
|
||||
@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return [super initWithTimestamp:[NSDate ows_millisecondTimeStamp]];
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
|
||||
if (self.attachmentIds.count != 1) {
|
||||
@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setGroupsBuilder:groupsBuilder];
|
||||
|
||||
return syncMessageBuilder;
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData
|
||||
|
||||
@ -180,7 +180,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
_read = YES;
|
||||
[self saveWithTransaction:transaction];
|
||||
[self touchThreadWithTransaction:transaction];
|
||||
|
||||
@ -78,7 +78,7 @@ NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingM
|
||||
+ (nullable instancetype)findMessageWithAuthorId:(NSString *)authorId timestamp:(uint64_t)timestamp
|
||||
{
|
||||
__block TSIncomingMessage *foundMessage;
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
// In theory we could build a new secondaryIndex for (authorId,timestamp), but in practice there should
|
||||
// be *very* few (millisecond) timestamps with multiple authors.
|
||||
[TSDatabaseSecondaryIndexes
|
||||
@ -127,7 +127,7 @@ NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingM
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
_read = YES;
|
||||
[self saveWithTransaction:transaction];
|
||||
[self touchThreadWithTransaction:transaction];
|
||||
|
||||
@ -119,7 +119,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
_read = YES;
|
||||
[self saveWithTransaction:transaction];
|
||||
[self touchThreadWithTransaction:transaction];
|
||||
|
||||
@ -157,8 +157,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
|
||||
// This isn't a perfect arrangement, but in practice this will prevent
|
||||
// data loss and will resolve all known issues.
|
||||
- (void)updateWithMessageState:(TSOutgoingMessageState)messageState;
|
||||
- (void)updateWithMessageState:(TSOutgoingMessageState)messageState
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)updateWithSendingError:(NSError *)error;
|
||||
- (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript;
|
||||
- (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@ -245,7 +245,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
{
|
||||
OWSAssert(error);
|
||||
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:TSOutgoingMessageStateUnsent];
|
||||
@ -256,25 +256,17 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithMessageState:(TSOutgoingMessageState)messageState
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithMessageState:messageState transaction:transaction];
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:messageState];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateWithMessageState:(TSOutgoingMessageState)messageState
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:messageState];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setHasSyncedTranscript:hasSyncedTranscript];
|
||||
@ -295,7 +287,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithCustomMessage:(NSString *)customMessage
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithCustomMessage:customMessage transaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -312,14 +304,14 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithWasDelivered
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithWasDeliveredWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateWithWasSentAndDelivered
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:TSOutgoingMessageStateSentToService];
|
||||
@ -397,7 +389,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithSentRecipient:(NSString *)contactId
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithSentRecipient:contactId transaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -455,6 +447,8 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
return [[self dataMessageBuilder] build];
|
||||
}
|
||||
|
||||
// For legacy message this is a serialized DataMessage.
|
||||
// For modern messages, e.g. Sync and Call messages, this is a serialized Contact
|
||||
- (NSData *)buildPlainTextData
|
||||
{
|
||||
OWSSignalServiceProtosContentBuilder *contentBuilder = [OWSSignalServiceProtosContentBuilder new];
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const kNSNotificationName_BlockedPhoneNumbersDidChange = @"kNSNotificationName_BlockedPhoneNumbersDidChange";
|
||||
|
||||
NSString *const kOWSBlockingManager_BlockedPhoneNumbersCollection = @"kOWSBlockingManager_BlockedPhoneNumbersCollection";
|
||||
// This key is used to persist the current "blocked phone numbers" state.
|
||||
NSString *const kOWSBlockingManager_BlockedPhoneNumbersKey = @"kOWSBlockingManager_BlockedPhoneNumbersKey";
|
||||
|
||||
@ -1,38 +1,38 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSStorageManager;
|
||||
@class TSMessage;
|
||||
@class TSThread;
|
||||
@class YapDatabaseReadTransaction;
|
||||
|
||||
@interface OWSDisappearingMessagesFinder : NSObject
|
||||
|
||||
- (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (void)enumerateUnstartedExpiringMessagesInThread:(TSThread *)thread
|
||||
block:(void (^_Nonnull)(TSMessage *message))block
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
+ (instancetype)defaultInstance;
|
||||
|
||||
- (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block;
|
||||
- (void)enumerateUnstartedExpiringMessagesInThread:(TSThread *)thread block:(void (^_Nonnull)(TSMessage *message))block;
|
||||
|
||||
/**
|
||||
* @return
|
||||
* uint64_t millisecond timestamp wrapped in a number. Retrieve with `unsignedLongLongvalue`.
|
||||
* or nil if there are no upcoming expired messages
|
||||
*/
|
||||
- (nullable NSNumber *)nextExpirationTimestampWithTransaction:(YapDatabaseReadTransaction *_Nonnull)transaction;
|
||||
- (nullable NSNumber *)nextExpirationTimestamp;
|
||||
|
||||
/**
|
||||
* Database extensions required for class to work.
|
||||
*/
|
||||
+ (void)asyncRegisterDatabaseExtensions:(TSStorageManager *)storageManager;
|
||||
- (void)asyncRegisterDatabaseExtensions;
|
||||
|
||||
/**
|
||||
* Only use the sync version for testing, generally we'll want to register extensions async
|
||||
*/
|
||||
+ (void)blockingRegisterDatabaseExtensions:(TSStorageManager *)storageManager;
|
||||
- (void)blockingRegisterDatabaseExtensions;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSDisappearingMessagesFinder.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
@ -18,13 +17,40 @@ static NSString *const OWSDisappearingMessageFinderThreadIdColumn = @"thread_id"
|
||||
static NSString *const OWSDisappearingMessageFinderExpiresAtColumn = @"expires_at";
|
||||
static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_messages_on_expires_at_and_thread_id_v2";
|
||||
|
||||
@interface OWSDisappearingMessagesFinder ()
|
||||
|
||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSDisappearingMessagesFinder
|
||||
|
||||
- (NSArray<NSString *> *)fetchUnstartedExpiringMessageIdsInThread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadTransaction *_Nonnull)transaction
|
||||
- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_storageManager = storageManager;
|
||||
_dbConnection = [storageManager newDatabaseConnection];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultInstance
|
||||
{
|
||||
static OWSDisappearingMessagesFinder *defaultInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
defaultInstance = [[self alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
});
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)fetchUnstartedExpiringMessageIdsInThread:(TSThread *)thread
|
||||
{
|
||||
NSMutableArray<NSString *> *messageIds = [NSMutableArray new];
|
||||
NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = 0 AND %@ = \"%@\"",
|
||||
OWSDisappearingMessageFinderExpiresAtColumn,
|
||||
@ -32,19 +58,19 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
thread.uniqueId];
|
||||
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
return [messageIds copy];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)fetchExpiredMessageIdsWithTransaction:(YapDatabaseReadTransaction *_Nonnull)transaction
|
||||
- (NSArray<NSString *> *)fetchExpiredMessageIds
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSMutableArray<NSString *> *messageIds = [NSMutableArray new];
|
||||
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
@ -54,31 +80,33 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
OWSDisappearingMessageFinderExpiresAtColumn,
|
||||
now];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
return [messageIds copy];
|
||||
}
|
||||
|
||||
- (nullable NSNumber *)nextExpirationTimestampWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (nullable NSNumber *)nextExpirationTimestamp
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ > 0 ORDER BY %@ ASC",
|
||||
OWSDisappearingMessageFinderExpiresAtColumn,
|
||||
OWSDisappearingMessageFinderExpiresAtColumn];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
|
||||
__block TSMessage *firstMessage;
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysAndObjectsMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) {
|
||||
firstMessage = (TSMessage *)object;
|
||||
*stop = YES;
|
||||
}];
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSDisappearingMessageFinderExpiresAtIndex]
|
||||
enumerateKeysAndObjectsMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, id object, BOOL *stop) {
|
||||
firstMessage = (TSMessage *)object;
|
||||
*stop = YES;
|
||||
}];
|
||||
}];
|
||||
|
||||
if (firstMessage && firstMessage.expiresAt > 0) {
|
||||
return [NSNumber numberWithUnsignedLongLong:firstMessage.expiresAt];
|
||||
@ -87,15 +115,10 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)enumerateUnstartedExpiringMessagesInThread:(TSThread *)thread
|
||||
block:(void (^_Nonnull)(TSMessage *message))block
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (void)enumerateUnstartedExpiringMessagesInThread:(TSThread *)thread block:(void (^_Nonnull)(TSMessage *message))block
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
for (NSString *expiringMessageId in
|
||||
[self fetchUnstartedExpiringMessageIdsInThread:thread transaction:transaction]) {
|
||||
TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiringMessageId transaction:transaction];
|
||||
for (NSString *expiringMessageId in [self fetchUnstartedExpiringMessageIdsInThread:thread]) {
|
||||
TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiringMessageId];
|
||||
if ([message isKindOfClass:[TSMessage class]]) {
|
||||
block(message);
|
||||
} else {
|
||||
@ -109,30 +132,23 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
* We don't want to instantiate potentially many messages at once.
|
||||
*/
|
||||
- (NSArray<TSMessage *> *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSMutableArray<TSMessage *> *messages = [NSMutableArray new];
|
||||
[self enumerateUnstartedExpiringMessagesInThread:thread
|
||||
block:^(TSMessage *message) {
|
||||
block:^(TSMessage *_Nonnull message) {
|
||||
[messages addObject:message];
|
||||
}
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
return [messages copy];
|
||||
}
|
||||
|
||||
|
||||
- (void)enumerateExpiredMessagesWithBlock:(void (^_Nonnull)(TSMessage *message))block
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
// Since we can't directly mutate the enumerated expired messages, we store only their ids in hopes of saving a
|
||||
// little memory and then enumerate the (larger) TSMessage objects one at a time.
|
||||
for (NSString *expiredMessageId in [self fetchExpiredMessageIdsWithTransaction:transaction]) {
|
||||
TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiredMessageId transaction:transaction];
|
||||
for (NSString *expiredMessageId in [self fetchExpiredMessageIds]) {
|
||||
TSMessage *_Nullable message = [TSMessage fetchObjectWithUniqueID:expiredMessageId];
|
||||
if ([message isKindOfClass:[TSMessage class]]) {
|
||||
block(message);
|
||||
} else {
|
||||
@ -145,22 +161,19 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
* Don't use this in production. Useful for testing.
|
||||
* We don't want to instantiate potentially many messages at once.
|
||||
*/
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessages
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSMutableArray<TSMessage *> *messages = [NSMutableArray new];
|
||||
[self enumerateExpiredMessagesWithBlock:^(TSMessage *message) {
|
||||
[self enumerateExpiredMessagesWithBlock:^(TSMessage *_Nonnull message) {
|
||||
[messages addObject:message];
|
||||
}
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
return [messages copy];
|
||||
}
|
||||
|
||||
#pragma mark - YapDatabaseExtension
|
||||
|
||||
+ (YapDatabaseSecondaryIndex *)indexDatabaseExtension
|
||||
- (YapDatabaseSecondaryIndex *)indexDatabaseExtension
|
||||
{
|
||||
YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new];
|
||||
[setup addColumn:OWSDisappearingMessageFinderExpiresAtColumn withType:YapDatabaseSecondaryIndexTypeInteger];
|
||||
@ -189,23 +202,23 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
}
|
||||
|
||||
// Useful for tests, don't use in app startup path because it's slow.
|
||||
+ (void)blockingRegisterDatabaseExtensions:(TSStorageManager *)storageManager
|
||||
- (void)blockingRegisterDatabaseExtensions
|
||||
{
|
||||
[storageManager.database registerExtension:[self indexDatabaseExtension]
|
||||
withName:OWSDisappearingMessageFinderExpiresAtIndex];
|
||||
[self.storageManager.database registerExtension:[self indexDatabaseExtension]
|
||||
withName:OWSDisappearingMessageFinderExpiresAtIndex];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterDatabaseExtensions:(TSStorageManager *)storageManager
|
||||
- (void)asyncRegisterDatabaseExtensions
|
||||
{
|
||||
[storageManager.database asyncRegisterExtension:[self indexDatabaseExtension]
|
||||
withName:OWSDisappearingMessageFinderExpiresAtIndex
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ completed registering extension async.", self.tag);
|
||||
} else {
|
||||
DDLogError(@"%@ failed registering extension async.", self.tag);
|
||||
}
|
||||
}];
|
||||
[self.storageManager.database asyncRegisterExtension:[self indexDatabaseExtension]
|
||||
withName:OWSDisappearingMessageFinderExpiresAtIndex
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ completed registering extension async.", self.tag);
|
||||
} else {
|
||||
DDLogError(@"%@ failed registering extension async.", self.tag);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
@ -17,10 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSDisappearingMessagesJob ()
|
||||
|
||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
||||
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *databaseConnection;
|
||||
|
||||
// This property should only be accessed on the serialQueue.
|
||||
@property (nonatomic, readonly) OWSDisappearingMessagesFinder *disappearingMessagesFinder;
|
||||
|
||||
// These three properties should only be accessed on the main thread.
|
||||
@ -51,9 +48,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
_storageManager = storageManager;
|
||||
_databaseConnection = storageManager.newDatabaseConnection;
|
||||
_disappearingMessagesFinder = [OWSDisappearingMessagesFinder new];
|
||||
_disappearingMessagesFinder = [[OWSDisappearingMessagesFinder alloc] initWithStorageManager:storageManager];
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
@ -84,32 +79,26 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return queue;
|
||||
}
|
||||
|
||||
// This method should only be called on the serialQueue.
|
||||
- (void)run
|
||||
{
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
__block uint expirationCount = 0;
|
||||
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.disappearingMessagesFinder enumerateExpiredMessagesWithBlock:^(TSMessage *message) {
|
||||
// sanity check
|
||||
if (message.expiresAt > now) {
|
||||
DDLogError(
|
||||
@"%@ Refusing to remove message which doesn't expire until: %lld", self.tag, message.expiresAt);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ Removing message which expired at: %lld", self.tag, message.expiresAt);
|
||||
[message removeWithTransaction:transaction];
|
||||
expirationCount++;
|
||||
[self.disappearingMessagesFinder enumerateExpiredMessagesWithBlock:^(TSMessage *message) {
|
||||
// sanity check
|
||||
if (message.expiresAt > now) {
|
||||
DDLogError(@"%@ Refusing to remove message which doesn't expire until: %lld", self.tag, message.expiresAt);
|
||||
return;
|
||||
}
|
||||
transaction:transaction];
|
||||
|
||||
DDLogDebug(@"%@ Removing message which expired at: %lld", self.tag, message.expiresAt);
|
||||
[message remove];
|
||||
expirationCount++;
|
||||
}];
|
||||
|
||||
DDLogDebug(@"%@ Removed %u expired messages", self.tag, expirationCount);
|
||||
}
|
||||
|
||||
// This method should only be called on the serialQueue.
|
||||
- (void)runLoop
|
||||
{
|
||||
DDLogVerbose(@"%@ Run", self.tag);
|
||||
@ -117,11 +106,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[self run];
|
||||
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
__block NSNumber *nextExpirationTimestampNumber;
|
||||
[self.databaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
nextExpirationTimestampNumber =
|
||||
[self.disappearingMessagesFinder nextExpirationTimestampWithTransaction:transaction];
|
||||
}];
|
||||
NSNumber *nextExpirationTimestampNumber = [self.disappearingMessagesFinder nextExpirationTimestamp];
|
||||
if (!nextExpirationTimestampNumber) {
|
||||
// In theory we could kill the loop here. It should resume when the next expiring message is saved,
|
||||
// But this is a safeguard for any race conditions that exist while running the job as a new message is saved.
|
||||
@ -164,20 +149,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
});
|
||||
}
|
||||
|
||||
// This method should only be called on the serialQueue.
|
||||
- (void)setExpirationForMessage:(TSMessage *)message expirationStartedAt:(uint64_t)expirationStartedAt
|
||||
{
|
||||
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self setExpirationForMessage:message expirationStartedAt:expirationStartedAt transaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setExpirationForMessage:(TSMessage *)message
|
||||
expirationStartedAt:(uint64_t)expirationStartedAt
|
||||
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
if (!message.isExpiringMessage) {
|
||||
return;
|
||||
}
|
||||
@ -188,7 +161,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// Don't clobber if multiple actions simultaneously triggered expiration.
|
||||
if (message.expireStartedAt == 0 || message.expireStartedAt > expirationStartedAt) {
|
||||
message.expireStartedAt = expirationStartedAt;
|
||||
[message saveWithTransaction:transaction];
|
||||
[message save];
|
||||
}
|
||||
|
||||
// Necessary that the async expiration run happens *after* the message is saved with expiration configuration.
|
||||
@ -202,26 +175,19 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
});
|
||||
}
|
||||
|
||||
// This method should only be called on the serialQueue.
|
||||
- (void)setExpirationsForThread:(TSThread *)thread
|
||||
{
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.disappearingMessagesFinder
|
||||
enumerateUnstartedExpiringMessagesInThread:thread
|
||||
block:^(TSMessage *_Nonnull message) {
|
||||
DDLogWarn(
|
||||
@"%@ Starting expiring message which should have already "
|
||||
@"been started.",
|
||||
self.tag);
|
||||
// specify "now" in case D.M. have since been disabled, but we have
|
||||
// existing unstarted expiring messages that still need to expire.
|
||||
[self setExpirationForMessage:message
|
||||
expirationStartedAt:now
|
||||
transaction:transaction];
|
||||
}
|
||||
transaction:transaction];
|
||||
}];
|
||||
[self.disappearingMessagesFinder
|
||||
enumerateUnstartedExpiringMessagesInThread:thread
|
||||
block:^(TSMessage *_Nonnull message) {
|
||||
DDLogWarn(@"%@ Starting expiring message which should have already "
|
||||
@"been started.",
|
||||
self.tag);
|
||||
// specify "now" in case D.M. have since been disabled, but we have
|
||||
// existing unstarted expiring messages that still need to expire.
|
||||
[self setExpirationForMessage:message expirationStartedAt:now];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
|
||||
@ -36,36 +36,33 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)fetchAttemptingOutAttachmentIdsWithTransaction:
|
||||
(YapDatabaseReadWriteTransaction *_Nonnull)transaction
|
||||
- (NSArray<NSString *> *)fetchAttemptingOutAttachmentIds:(YapDatabaseConnection *)dbConnection
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSMutableArray<NSString *> *attachmentIds = [NSMutableArray new];
|
||||
|
||||
NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ != %d",
|
||||
OWSFailedAttachmentDownloadsJobAttachmentStateColumn,
|
||||
(int)TSAttachmentPointerStateFailed];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
[[transaction ext:OWSFailedAttachmentDownloadsJobAttachmentStateIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[attachmentIds addObject:key];
|
||||
}];
|
||||
[dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSFailedAttachmentDownloadsJobAttachmentStateIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[attachmentIds addObject:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
return [attachmentIds copy];
|
||||
}
|
||||
|
||||
- (void)enumerateAttemptingOutAttachmentsWithBlock:(void (^_Nonnull)(TSAttachmentPointer *attachment))block
|
||||
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
YapDatabaseConnection *dbConnection = [self.storageManager newDatabaseConnection];
|
||||
|
||||
// Since we can't directly mutate the enumerated attachments, we store only their ids in hopes
|
||||
// of saving a little memory and then enumerate the (larger) TSAttachment objects one at a time.
|
||||
for (NSString *attachmentId in [self fetchAttemptingOutAttachmentIdsWithTransaction:transaction]) {
|
||||
TSAttachmentPointer *_Nullable attachment =
|
||||
[TSAttachmentPointer fetchObjectWithUniqueID:attachmentId transaction:transaction];
|
||||
for (NSString *attachmentId in [self fetchAttemptingOutAttachmentIds:dbConnection]) {
|
||||
TSAttachmentPointer *_Nullable attachment = [TSAttachmentPointer fetchObjectWithUniqueID:attachmentId];
|
||||
if ([attachment isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
block(attachment);
|
||||
} else {
|
||||
@ -77,19 +74,15 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i
|
||||
- (void)run
|
||||
{
|
||||
__block uint count = 0;
|
||||
[[self.storageManager newDatabaseConnection]
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self enumerateAttemptingOutAttachmentsWithBlock:^(TSAttachmentPointer *attachment) {
|
||||
// sanity check
|
||||
if (attachment.state != TSAttachmentPointerStateFailed) {
|
||||
DDLogDebug(@"%@ marking attachment as failed", self.tag);
|
||||
attachment.state = TSAttachmentPointerStateFailed;
|
||||
[attachment saveWithTransaction:transaction];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
transaction:transaction];
|
||||
}];
|
||||
[self enumerateAttemptingOutAttachmentsWithBlock:^(TSAttachmentPointer *attachment) {
|
||||
// sanity check
|
||||
if (attachment.state != TSAttachmentPointerStateFailed) {
|
||||
DDLogDebug(@"%@ marking attachment as failed", self.tag);
|
||||
attachment.state = TSAttachmentPointerStateFailed;
|
||||
[attachment save];
|
||||
count++;
|
||||
}
|
||||
}];
|
||||
|
||||
DDLogDebug(@"%@ Marked %u attachments as unsent", self.tag, count);
|
||||
}
|
||||
|
||||
@ -37,36 +37,33 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)fetchAttemptingOutMessageIdsWithTransaction:
|
||||
(YapDatabaseReadWriteTransaction *_Nonnull)transaction
|
||||
- (NSArray<NSString *> *)fetchAttemptingOutMessageIds:(YapDatabaseConnection *)dbConnection
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSMutableArray<NSString *> *messageIds = [NSMutableArray new];
|
||||
|
||||
NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ == %d",
|
||||
OWSFailedMessagesJobMessageStateColumn,
|
||||
(int)TSOutgoingMessageStateAttemptingOut];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
[[transaction ext:OWSFailedMessagesJobMessageStateIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
[dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSFailedMessagesJobMessageStateIndex]
|
||||
enumerateKeysMatchingQuery:query
|
||||
usingBlock:^void(NSString *collection, NSString *key, BOOL *stop) {
|
||||
[messageIds addObject:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
return [messageIds copy];
|
||||
}
|
||||
|
||||
- (void)enumerateAttemptingOutMessagesWithBlock:(void (^_Nonnull)(TSOutgoingMessage *message))block
|
||||
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
YapDatabaseConnection *dbConnection = [self.storageManager newDatabaseConnection];
|
||||
|
||||
// Since we can't directly mutate the enumerated "attempting out" expired messages, we store only their ids in hopes
|
||||
// of saving a little memory and then enumerate the (larger) TSMessage objects one at a time.
|
||||
for (NSString *expiredMessageId in [self fetchAttemptingOutMessageIdsWithTransaction:transaction]) {
|
||||
TSOutgoingMessage *_Nullable message =
|
||||
[TSOutgoingMessage fetchObjectWithUniqueID:expiredMessageId transaction:transaction];
|
||||
for (NSString *expiredMessageId in [self fetchAttemptingOutMessageIds:dbConnection]) {
|
||||
TSOutgoingMessage *_Nullable message = [TSOutgoingMessage fetchObjectWithUniqueID:expiredMessageId];
|
||||
if ([message isKindOfClass:[TSOutgoingMessage class]]) {
|
||||
block(message);
|
||||
} else {
|
||||
@ -78,26 +75,18 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m
|
||||
- (void)run
|
||||
{
|
||||
__block uint count = 0;
|
||||
[self enumerateAttemptingOutMessagesWithBlock:^(TSOutgoingMessage *message) {
|
||||
// sanity check
|
||||
OWSAssert(message.messageState == TSOutgoingMessageStateAttemptingOut);
|
||||
if (message.messageState != TSOutgoingMessageStateAttemptingOut) {
|
||||
DDLogError(@"%@ Refusing to mark as unsent message with state: %d", self.tag, (int)message.messageState);
|
||||
return;
|
||||
}
|
||||
|
||||
[[self.storageManager newDatabaseConnection]
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self enumerateAttemptingOutMessagesWithBlock:^(TSOutgoingMessage *message) {
|
||||
// sanity check
|
||||
OWSAssert(message.messageState == TSOutgoingMessageStateAttemptingOut);
|
||||
if (message.messageState != TSOutgoingMessageStateAttemptingOut) {
|
||||
DDLogError(
|
||||
@"%@ Refusing to mark as unsent message with state: %d", self.tag, (int)message.messageState);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ marking message as unsent: %@", self.tag, message.uniqueId);
|
||||
[message updateWithMessageState:TSOutgoingMessageStateUnsent transaction:transaction];
|
||||
OWSAssert(message.messageState == TSOutgoingMessageStateUnsent);
|
||||
|
||||
count++;
|
||||
}
|
||||
transaction:transaction];
|
||||
}];
|
||||
DDLogDebug(@"%@ marking message as unsent", self.tag);
|
||||
[message updateWithMessageState:TSOutgoingMessageStateUnsent];
|
||||
count++;
|
||||
}];
|
||||
|
||||
DDLogDebug(@"%@ Marked %u messages as unsent", self.tag, count);
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ extern NSString *const kNSNotificationName_IdentityStateDidChange;
|
||||
extern const NSUInteger kIdentityKeyLength;
|
||||
|
||||
@class OWSRecipientIdentity;
|
||||
@class OWSSignalServiceProtosVerified;
|
||||
@class OWSSignalServiceProtosSyncMessageVerification;
|
||||
|
||||
// This class can be safely accessed and used from any thread.
|
||||
@interface OWSIdentityManager : NSObject <IdentityKeyStore>
|
||||
@ -33,7 +33,7 @@ extern const NSUInteger kIdentityKeyLength;
|
||||
- (void)setVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
isUserInitiatedChange:(BOOL)isUserInitiatedChange;
|
||||
sendSyncMessage:(BOOL)sendSyncMessage;
|
||||
|
||||
- (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId;
|
||||
|
||||
@ -46,7 +46,10 @@ extern const NSUInteger kIdentityKeyLength;
|
||||
*/
|
||||
- (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId;
|
||||
|
||||
- (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified;
|
||||
// Will try to send a sync message with all verification states.
|
||||
- (void)syncAllVerificationStates;
|
||||
|
||||
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerification *> *)verifications;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -5,9 +5,7 @@
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "NotificationsProtocol.h"
|
||||
#import "OWSError.h"
|
||||
#import "OWSMessageSender.h"
|
||||
#import "OWSOutgoingNullMessage.h"
|
||||
#import "OWSRecipientIdentity.h"
|
||||
#import "OWSVerificationStateChangeMessage.h"
|
||||
#import "OWSVerificationStateSyncMessage.h"
|
||||
@ -16,11 +14,9 @@
|
||||
#import "TSErrorMessage.h"
|
||||
#import "TSGroupThread.h"
|
||||
#import "TSStorageManager+keyingMaterial.h"
|
||||
#import "TSStorageManager+sessionStore.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
#import <25519/Curve25519.h>
|
||||
#import <AxolotlKit/NSData+keyVersionByte.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -37,13 +33,7 @@ NSString *const OWSIdentityManager_QueuedVerificationStateSyncMessages =
|
||||
// Don't trust an identity for sending to unless they've been around for at least this long
|
||||
const NSTimeInterval kIdentityKeyStoreNonBlockingSecondsThreshold = 5.0;
|
||||
|
||||
// The canonical key includes 32 bytes of identity material plus one byte specifying the key type
|
||||
const NSUInteger kIdentityKeyLength = 33;
|
||||
|
||||
// Cryptographic operations do not use the "type" byte of the identity key, so, for legacy reasons we store just
|
||||
// the identity material.
|
||||
// TODO: migrate to storing the full 33 byte representation.
|
||||
const NSUInteger kStoredIdentityKeyLength = 32;
|
||||
const NSUInteger kIdentityKeyLength = 32;
|
||||
|
||||
NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationName_IdentityStateDidChange";
|
||||
|
||||
@ -93,8 +83,12 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
[self observeNotifications];
|
||||
|
||||
// We want to observe these notifications lazily to avoid accessing
|
||||
// the data store in [application: didFinishLaunchingWithOptions:].
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
[self observeNotifications];
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -139,8 +133,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
- (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(identityKey.length == kStoredIdentityKeyLength);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
OWSAssert(identityKey != nil);
|
||||
OWSAssert(recipientId != nil);
|
||||
|
||||
@synchronized(self)
|
||||
{
|
||||
@ -195,10 +189,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
createdAt:[NSDate new]
|
||||
verificationState:verificationState] save];
|
||||
|
||||
dispatch_async([OWSDispatch sessionStoreQueue], ^{
|
||||
[self.storageManager archiveAllSessionsForContact:recipientId];
|
||||
});
|
||||
|
||||
// Cancel any pending verification state sync messages for this recipient.
|
||||
[self clearSyncMessageForRecipientId:recipientId];
|
||||
|
||||
@ -207,6 +197,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
return YES;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ no changes for identity saved for recipient: %@", self.tag, recipientId);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@ -214,9 +205,9 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
- (void)setVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
isUserInitiatedChange:(BOOL)isUserInitiatedChange
|
||||
sendSyncMessage:(BOOL)sendSyncMessage
|
||||
{
|
||||
OWSAssert(identityKey.length == kStoredIdentityKeyLength);
|
||||
OWSAssert(identityKey.length > 0);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
@synchronized(self)
|
||||
@ -244,9 +235,12 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
[recipientIdentity updateWithVerificationState:verificationState];
|
||||
|
||||
if (isUserInitiatedChange) {
|
||||
if (sendSyncMessage) {
|
||||
[self enqueueSyncMessageForVerificationState:verificationState
|
||||
identityKey:identityKey
|
||||
recipientId:recipientId];
|
||||
|
||||
[self saveChangeMessagesForRecipientId:recipientId verificationState:verificationState isLocalChange:YES];
|
||||
[self enqueueSyncMessageForVerificationStateForRecipientId:recipientId];
|
||||
} else {
|
||||
// Cancel any pending verification state sync messages for this recipient.
|
||||
[self clearSyncMessageForRecipientId:recipientId];
|
||||
@ -320,8 +314,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
recipientId:(NSString *)recipientId
|
||||
direction:(TSMessageDirection)direction
|
||||
{
|
||||
OWSAssert(identityKey.length == kStoredIdentityKeyLength);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
OWSAssert(identityKey != nil);
|
||||
OWSAssert(recipientId != nil);
|
||||
OWSAssert(direction != TSMessageDirectionUnknown);
|
||||
|
||||
@synchronized(self)
|
||||
@ -359,21 +353,23 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
- (BOOL)isTrustedKey:(NSData *)identityKey forSendingToIdentity:(nullable OWSRecipientIdentity *)recipientIdentity
|
||||
{
|
||||
OWSAssert(identityKey.length == kStoredIdentityKeyLength);
|
||||
OWSAssert(identityKey.length == kIdentityKeyLength);
|
||||
|
||||
@synchronized(self)
|
||||
{
|
||||
if (recipientIdentity == nil) {
|
||||
DDLogDebug(@"%@ Trusting previously unknown recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
}
|
||||
|
||||
OWSAssert(recipientIdentity.identityKey.length == kStoredIdentityKeyLength);
|
||||
OWSAssert(recipientIdentity.identityKey.length == kIdentityKeyLength);
|
||||
if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
|
||||
DDLogWarn(@"%@ key mismatch for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([recipientIdentity isFirstKnownKey]) {
|
||||
DDLogDebug(@"%@ trusting first known key for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -385,10 +381,12 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
DDLogWarn(@"%@ not trusting new identity for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return NO;
|
||||
} else {
|
||||
DDLogWarn(@"%@ trusting existing identity for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
case OWSVerificationStateVerified:
|
||||
DDLogWarn(@"%@ trusting verified identity for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
case OWSVerificationStateNoLongerVerified:
|
||||
DDLogWarn(@"%@ not trusting no longer verified identity for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
@ -399,7 +397,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
- (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
OWSAssert(recipientId != nil);
|
||||
|
||||
NSMutableArray<TSMessage *> *messages = [NSMutableArray new];
|
||||
|
||||
@ -415,15 +413,18 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
[messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]];
|
||||
}
|
||||
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)enqueueSyncMessageForVerificationStateForRecipientId:(NSString *)recipientId
|
||||
- (void)enqueueSyncMessageForVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(identityKey.length > 0);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@ -434,29 +435,17 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
});
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)tryToSyncQueuedVerificationStates
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
|
||||
// Only try to sync if the app is active to avoid interfering with startup.
|
||||
//
|
||||
// applicationDidBecomeActive: will try to sync again when the app becomes active.
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
NSMutableArray<NSString *> *recipientIds = [NSMutableArray new];
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction enumerateKeysAndObjectsInCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages
|
||||
usingBlock:^(NSString *_Nonnull recipientId,
|
||||
id _Nonnull object,
|
||||
@ -464,26 +453,19 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
[recipientIds addObject:recipientId];
|
||||
}];
|
||||
}];
|
||||
|
||||
NSMutableArray<OWSVerificationStateSyncMessage *> *messages = [NSMutableArray new];
|
||||
|
||||
OWSVerificationStateSyncMessage *message =
|
||||
[OWSVerificationStateSyncMessage new];
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
|
||||
if (!recipientIdentity) {
|
||||
OWSFail(@"Could not load recipient identity for recipientId: %@", recipientId);
|
||||
continue;
|
||||
}
|
||||
if (recipientIdentity.recipientId.length < 1) {
|
||||
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) {
|
||||
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepend key type for transit.
|
||||
// TODO we should just be storing the key type so we don't have to juggle re-adding it.
|
||||
NSData *identityKey = [recipientIdentity.identityKey prependKeyType];
|
||||
if (identityKey.length != kIdentityKeyLength) {
|
||||
OWSFail(@"Invalid recipient identitykey for recipientId: %@ key: %@", recipientId, identityKey);
|
||||
continue;
|
||||
}
|
||||
if (recipientIdentity.verificationState == OWSVerificationStateNoLongerVerified) {
|
||||
// We don't want to sync "no longer verified" state. Other clients can
|
||||
// figure this out from the /profile/ endpoint, and this can cause data
|
||||
@ -493,18 +475,39 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
recipientId);
|
||||
continue;
|
||||
}
|
||||
OWSVerificationStateSyncMessage *message = [[OWSVerificationStateSyncMessage alloc]
|
||||
initWithVerificationState:recipientIdentity.verificationState
|
||||
identityKey:identityKey
|
||||
verificationForRecipientId:recipientIdentity.recipientId];
|
||||
[messages addObject:message];
|
||||
[message addVerificationState:recipientIdentity.verificationState
|
||||
identityKey:recipientIdentity.identityKey
|
||||
recipientId:recipientId];
|
||||
}
|
||||
if (messages.count > 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
for (OWSVerificationStateSyncMessage *message in messages) {
|
||||
[self sendSyncVerificationStateMessage:message];
|
||||
}
|
||||
});
|
||||
if (message.recipientIds.count > 0) {
|
||||
[self sendSyncVerificationStateMessage:message];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)syncAllVerificationStates
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
OWSVerificationStateSyncMessage *message =
|
||||
[OWSVerificationStateSyncMessage new];
|
||||
[OWSRecipientIdentity enumerateCollectionObjectsUsingBlock:^(OWSRecipientIdentity *recipientIdentity, BOOL *stop) {
|
||||
OWSAssert(recipientIdentity);
|
||||
OWSAssert(recipientIdentity.recipientId.length > 0);
|
||||
OWSAssert(recipientIdentity.identityKey.length > 0);
|
||||
|
||||
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) {
|
||||
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientIdentity.recipientId);
|
||||
return;
|
||||
}
|
||||
[message addVerificationState:recipientIdentity.verificationState
|
||||
identityKey:recipientIdentity.identityKey
|
||||
recipientId:recipientIdentity.recipientId];
|
||||
}];
|
||||
if (message.recipientIds.count > 0) {
|
||||
[self sendSyncVerificationStateMessage:message];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -513,41 +516,25 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
- (void)sendSyncVerificationStateMessage:(OWSVerificationStateSyncMessage *)message
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(message.verificationForRecipientId.length > 0);
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(message.recipientIds.count > 0);
|
||||
|
||||
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:message.verificationForRecipientId];
|
||||
|
||||
// Send null message to appear as though we're sending a normal message to cover the sync messsage sent
|
||||
// subsequently
|
||||
OWSOutgoingNullMessage *nullMessage = [[OWSOutgoingNullMessage alloc] initWithContactThread:contactThread
|
||||
verificationStateSyncMessage:message];
|
||||
[self.messageSender sendMessage:nullMessage
|
||||
if (YES) {
|
||||
// Don't actually transmit any verification state sync messages
|
||||
// until we finalize the proto schema changes.
|
||||
//
|
||||
// TODO: Remove.
|
||||
return;
|
||||
}
|
||||
|
||||
[self.messageSender sendMessage:message
|
||||
success:^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
DDLogInfo(@"%@ Successfully sent verification state NullMessage", self.tag);
|
||||
[self.messageSender sendMessage:message
|
||||
success:^{
|
||||
DDLogInfo(@"%@ Successfully sent verification state sync message", self.tag);
|
||||
DDLogInfo(@"%@ Successfully sent verification state sync message", self.tag);
|
||||
|
||||
// Record that this verification state was successfully synced.
|
||||
[self clearSyncMessageForRecipientId:message.verificationForRecipientId];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
DDLogError(
|
||||
@"%@ Failed to send verification state sync message with error: %@", self.tag, error);
|
||||
}];
|
||||
});
|
||||
// Record that this verification state was successfully synced.
|
||||
[self clearSyncMessageForRecipientIds:message.recipientIds];
|
||||
}
|
||||
failure:^(NSError *_Nonnull error) {
|
||||
DDLogError(@"%@ Failed to send verification state NullMessage with error: %@", self.tag, error);
|
||||
if (error.code == OWSErrorCodeNoSuchSignalRecipient) {
|
||||
DDLogInfo(@"%@ Removing retries for syncing verification state, since user is no longer registered: %@",
|
||||
self.tag,
|
||||
message.verificationForRecipientId);
|
||||
// Otherwise this will fail forever.
|
||||
[self clearSyncMessageForRecipientId:message.verificationForRecipientId];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
DDLogError(@"%@ Failed to send verification state sync message with error: %@", self.tag, error);
|
||||
}];
|
||||
}
|
||||
|
||||
@ -555,52 +542,57 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
[self clearSyncMessageForRecipientIds:@[recipientId]];
|
||||
}
|
||||
|
||||
- (void)clearSyncMessageForRecipientIds:(NSArray<NSString *> *)recipientIds
|
||||
{
|
||||
OWSAssert(recipientIds.count > 0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self.storageManager removeObjectForKey:recipientId
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
[self.storageManager removeObjectForKey:recipientId
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified
|
||||
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerification *> *)verifications
|
||||
{
|
||||
|
||||
NSString *recipientId = verified.destination;
|
||||
if (recipientId.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing recipientId.");
|
||||
return;
|
||||
for (OWSSignalServiceProtosSyncMessageVerification *verification in verifications) {
|
||||
NSString *recipientId = verification.destination;
|
||||
if (recipientId.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing recipientId.");
|
||||
continue;
|
||||
}
|
||||
NSData *identityKey = verification.identityKey;
|
||||
if (identityKey.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing identityKey: %@", recipientId);
|
||||
continue;
|
||||
}
|
||||
switch (verification.state) {
|
||||
case OWSSignalServiceProtosSyncMessageVerificationStateDefault:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:NO];
|
||||
break;
|
||||
case OWSSignalServiceProtosSyncMessageVerificationStateVerified:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:YES];
|
||||
break;
|
||||
case OWSSignalServiceProtosSyncMessageVerificationStateNoLongerVerified:
|
||||
OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.",
|
||||
recipientId,
|
||||
OWSVerificationStateToString(OWSVerificationStateNoLongerVerified));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
NSData *rawIdentityKey = verified.identityKey;
|
||||
if (rawIdentityKey.length != kIdentityKeyLength) {
|
||||
OWSFail(@"Verification state sync message for recipient: %@ with malformed identityKey: %@",
|
||||
recipientId,
|
||||
rawIdentityKey);
|
||||
return;
|
||||
}
|
||||
NSData *identityKey = [rawIdentityKey removeKeyType];
|
||||
|
||||
switch (verified.state) {
|
||||
case OWSSignalServiceProtosVerifiedStateDefault:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:NO];
|
||||
break;
|
||||
case OWSSignalServiceProtosVerifiedStateVerified:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:YES];
|
||||
break;
|
||||
case OWSSignalServiceProtosVerifiedStateUnverified:
|
||||
OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.",
|
||||
recipientId,
|
||||
OWSVerificationStateToString(OWSVerificationStateNoLongerVerified));
|
||||
return;
|
||||
}
|
||||
[self fireIdentityStateChangeNotification];
|
||||
}
|
||||
|
||||
- (void)tryToApplyVerificationStateFromSyncMessage:(OWSVerificationState)verificationState
|
||||
@ -612,12 +604,11 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
OWSFail(@"Verification state sync message missing recipientId.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (identityKey.length != kStoredIdentityKeyLength) {
|
||||
if (identityKey.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing identityKey: %@", recipientId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@synchronized(self)
|
||||
{
|
||||
OWSRecipientIdentity *_Nullable recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
|
||||
@ -742,7 +733,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
isLocalChange:isLocalChange]];
|
||||
}
|
||||
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
@ -755,11 +746,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
// We want to defer this so that we never call this method until
|
||||
// [UIApplicationDelegate applicationDidBecomeActive:] is complete.
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
});
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
@ -159,6 +159,7 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
@property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error);
|
||||
@property (nonatomic) OWSSendMessageOperationState operationState;
|
||||
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
|
||||
@property (nonatomic) BOOL hasCompleted;
|
||||
|
||||
@end
|
||||
|
||||
@ -190,10 +191,17 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure we call the success or failure handler exactly once.
|
||||
@synchronized(strongSelf)
|
||||
{
|
||||
OWSCAssert(!strongSelf.hasCompleted);
|
||||
strongSelf.hasCompleted = YES;
|
||||
}
|
||||
|
||||
[message updateWithMessageState:TSOutgoingMessageStateSentToService];
|
||||
|
||||
DDLogDebug(@"%@ succeeded.", strongSelf.tag);
|
||||
aSuccessHandler();
|
||||
|
||||
[strongSelf markAsComplete];
|
||||
};
|
||||
|
||||
@ -204,11 +212,17 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure we call the success or failure handler exactly once.
|
||||
@synchronized(strongSelf)
|
||||
{
|
||||
OWSCAssert(!strongSelf.hasCompleted);
|
||||
strongSelf.hasCompleted = YES;
|
||||
}
|
||||
|
||||
[strongSelf.message updateWithSendingError:error];
|
||||
|
||||
DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error);
|
||||
aFailureHandler(error);
|
||||
|
||||
[strongSelf markAsComplete];
|
||||
};
|
||||
|
||||
@ -280,10 +294,12 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
|
||||
- (void)tryWithRemainingRetries:(NSUInteger)remainingRetries
|
||||
{
|
||||
DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries);
|
||||
|
||||
// Use this flag to ensure a given operation only succeeds or fails once.
|
||||
__block BOOL onceFlag = NO;
|
||||
RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) {
|
||||
DDLogInfo(@"%@ Sending failed. Remaining retries: %lu", self.tag, (unsigned long)remainingRetries);
|
||||
DDLogInfo(@"%@ Sending failed.", self.tag);
|
||||
|
||||
OWSAssert(!onceFlag);
|
||||
onceFlag = YES;
|
||||
@ -317,15 +333,7 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
{
|
||||
[self willChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
|
||||
[self willChangeValueForKey:OWSSendMessageOperationKeyIsFinished];
|
||||
|
||||
// Ensure we call the success or failure handler exactly once.
|
||||
@synchronized(self)
|
||||
{
|
||||
OWSAssert(self.operationState != OWSSendMessageOperationStateFinished);
|
||||
|
||||
self.operationState = OWSSendMessageOperationStateFinished;
|
||||
}
|
||||
|
||||
self.operationState = OWSSendMessageOperationStateFinished;
|
||||
[self didChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
|
||||
[self didChangeValueForKey:OWSSendMessageOperationKeyIsFinished];
|
||||
|
||||
@ -447,6 +455,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
success:(void (^)())successHandler
|
||||
failure:(RetryableFailureHandler)failureHandler
|
||||
{
|
||||
DDLogDebug(@"%@ sending message: %@", self.tag, message.debugDescription);
|
||||
|
||||
[self ensureAnyAttachmentsUploaded:message
|
||||
success:^() {
|
||||
[self deliverMessage:message
|
||||
@ -467,6 +477,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
failure:(RetryableFailureHandler)failureHandler
|
||||
{
|
||||
if (!message.hasAttachments) {
|
||||
DDLogDebug(@"%@ No attachments for message: %@", self.tag, message);
|
||||
return successHandler();
|
||||
}
|
||||
|
||||
@ -903,22 +914,19 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
}
|
||||
|
||||
NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey;
|
||||
|
||||
if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) {
|
||||
OWSFail(@"%@ unexpected TSInvalidRecipientKey: %@", self.tag, newIdentityKeyWithVersion);
|
||||
failureHandler(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO migrate to storing the full 33 byte representation of the identity key.
|
||||
if (newIdentityKeyWithVersion.length != kIdentityKeyLength) {
|
||||
OWSFail(@"%@ unexpected key length: %lu", self.tag, (unsigned long)newIdentityKeyWithVersion.length);
|
||||
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
|
||||
if (newIdentityKey.length != kIdentityKeyLength) {
|
||||
OWSFail(@"%@ unexpected key length: %lu", self.tag, (unsigned long)newIdentityKey.length);
|
||||
failureHandler(error);
|
||||
return;
|
||||
}
|
||||
|
||||
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
|
||||
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId];
|
||||
|
||||
failureHandler(error);
|
||||
@ -1161,9 +1169,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
inThread:(TSThread *)thread
|
||||
{
|
||||
NSMutableArray *messagesArray = [NSMutableArray arrayWithCapacity:recipient.devices.count];
|
||||
|
||||
NSData *plainText = [message buildPlainTextData];
|
||||
DDLogDebug(@"%@ built message: %@ plainTextData.length: %lu", self.tag, [message class], plainText.length);
|
||||
|
||||
for (NSNumber *deviceNumber in recipient.devices) {
|
||||
@try {
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSOutgoingMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSVerificationStateSyncMessage;
|
||||
@class TSContactThread;
|
||||
|
||||
@interface OWSOutgoingNullMessage : TSOutgoingMessage
|
||||
|
||||
- (instancetype)initWithContactThread:(TSContactThread *)contactThread
|
||||
verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -1,76 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSOutgoingNullMessage.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "Cryptography.h"
|
||||
#import "OWSVerificationStateSyncMessage.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "TSContactThread.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSOutgoingNullMessage ()
|
||||
|
||||
@property (nonatomic, readonly) OWSVerificationStateSyncMessage *verificationStateSyncMessage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSOutgoingNullMessage
|
||||
|
||||
- (instancetype)initWithContactThread:(TSContactThread *)contactThread
|
||||
verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage
|
||||
{
|
||||
self = [super initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:contactThread];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_verificationStateSyncMessage = verificationStateSyncMessage;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - override TSOutgoingMessage
|
||||
|
||||
- (NSData *)buildPlainTextData
|
||||
{
|
||||
OWSSignalServiceProtosContentBuilder *contentBuilder = [OWSSignalServiceProtosContentBuilder new];
|
||||
OWSSignalServiceProtosNullMessageBuilder *nullMessageBuilder = [OWSSignalServiceProtosNullMessageBuilder new];
|
||||
|
||||
NSUInteger contentLength = self.verificationStateSyncMessage.unpaddedVerifiedLength;
|
||||
|
||||
OWSAssert(self.verificationStateSyncMessage.paddingBytesLength > 0);
|
||||
|
||||
// We add the same amount of padding in the VerificationStateSync message and it's coresponding NullMessage so that
|
||||
// the sync message is indistinguishable from an outgoing Sent transcript corresponding to the NullMessage. We pad
|
||||
// the NullMessage so as to obscure it's content. The sync message (like all sync messages) will be *additionally*
|
||||
// padded by the superclass while being sent. The end result is we send a NullMessage of a non-distinct size, and a
|
||||
// verification sync which is ~1-512 bytes larger then that.
|
||||
contentLength += self.verificationStateSyncMessage.paddingBytesLength;
|
||||
|
||||
OWSAssert(contentLength > 0)
|
||||
|
||||
nullMessageBuilder.padding = [Cryptography generateRandomBytes:contentLength];
|
||||
|
||||
contentBuilder.nullMessage = [nullMessageBuilder build];
|
||||
|
||||
return [contentBuilder build].data;
|
||||
}
|
||||
|
||||
- (BOOL)shouldSyncTranscript
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// No-op as we don't want to actually display this as an outgoing message in our thread.
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
|
||||
#import <ProtocolBuffers/ProtocolBuffers.h>
|
||||
|
||||
@ -36,8 +34,6 @@
|
||||
@class OWSSignalServiceProtosGroupDetailsAvatar;
|
||||
@class OWSSignalServiceProtosGroupDetailsAvatarBuilder;
|
||||
@class OWSSignalServiceProtosGroupDetailsBuilder;
|
||||
@class OWSSignalServiceProtosNullMessage;
|
||||
@class OWSSignalServiceProtosNullMessageBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessage;
|
||||
@class OWSSignalServiceProtosSyncMessageBlocked;
|
||||
@class OWSSignalServiceProtosSyncMessageBlockedBuilder;
|
||||
@ -52,8 +48,8 @@
|
||||
@class OWSSignalServiceProtosSyncMessageRequestBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessageSent;
|
||||
@class OWSSignalServiceProtosSyncMessageSentBuilder;
|
||||
@class OWSSignalServiceProtosVerified;
|
||||
@class OWSSignalServiceProtosVerifiedBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessageVerification;
|
||||
@class OWSSignalServiceProtosSyncMessageVerificationBuilder;
|
||||
@class ObjectiveCFileOptions;
|
||||
@class ObjectiveCFileOptionsBuilder;
|
||||
@class PBDescriptorProto;
|
||||
@ -111,15 +107,6 @@ typedef NS_ENUM(SInt32, OWSSignalServiceProtosEnvelopeType) {
|
||||
BOOL OWSSignalServiceProtosEnvelopeTypeIsValidValue(OWSSignalServiceProtosEnvelopeType value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosEnvelopeType(OWSSignalServiceProtosEnvelopeType value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosVerifiedState) {
|
||||
OWSSignalServiceProtosVerifiedStateDefault = 0,
|
||||
OWSSignalServiceProtosVerifiedStateVerified = 1,
|
||||
OWSSignalServiceProtosVerifiedStateUnverified = 2,
|
||||
};
|
||||
|
||||
BOOL OWSSignalServiceProtosVerifiedStateIsValidValue(OWSSignalServiceProtosVerifiedState value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosVerifiedState(OWSSignalServiceProtosVerifiedState value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosDataMessageFlags) {
|
||||
OWSSignalServiceProtosDataMessageFlagsEndSession = 1,
|
||||
OWSSignalServiceProtosDataMessageFlagsExpirationTimerUpdate = 2,
|
||||
@ -138,6 +125,15 @@ typedef NS_ENUM(SInt32, OWSSignalServiceProtosSyncMessageRequestType) {
|
||||
BOOL OWSSignalServiceProtosSyncMessageRequestTypeIsValidValue(OWSSignalServiceProtosSyncMessageRequestType value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosSyncMessageRequestType(OWSSignalServiceProtosSyncMessageRequestType value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosSyncMessageVerificationState) {
|
||||
OWSSignalServiceProtosSyncMessageVerificationStateDefault = 0,
|
||||
OWSSignalServiceProtosSyncMessageVerificationStateVerified = 1,
|
||||
OWSSignalServiceProtosSyncMessageVerificationStateNoLongerVerified = 2,
|
||||
};
|
||||
|
||||
BOOL OWSSignalServiceProtosSyncMessageVerificationStateIsValidValue(OWSSignalServiceProtosSyncMessageVerificationState value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosSyncMessageVerificationState(OWSSignalServiceProtosSyncMessageVerificationState value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosAttachmentPointerFlags) {
|
||||
OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage = 1,
|
||||
};
|
||||
@ -276,26 +272,21 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
#define Content_dataMessage @"dataMessage"
|
||||
#define Content_syncMessage @"syncMessage"
|
||||
#define Content_callMessage @"callMessage"
|
||||
#define Content_nullMessage @"nullMessage"
|
||||
@interface OWSSignalServiceProtosContent : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasDataMessage_:1;
|
||||
BOOL hasSyncMessage_:1;
|
||||
BOOL hasCallMessage_:1;
|
||||
BOOL hasNullMessage_:1;
|
||||
OWSSignalServiceProtosDataMessage* dataMessage;
|
||||
OWSSignalServiceProtosSyncMessage* syncMessage;
|
||||
OWSSignalServiceProtosCallMessage* callMessage;
|
||||
OWSSignalServiceProtosNullMessage* nullMessage;
|
||||
}
|
||||
- (BOOL) hasDataMessage;
|
||||
- (BOOL) hasSyncMessage;
|
||||
- (BOOL) hasCallMessage;
|
||||
- (BOOL) hasNullMessage;
|
||||
@property (readonly, strong) OWSSignalServiceProtosDataMessage* dataMessage;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessage* syncMessage;
|
||||
@property (readonly, strong) OWSSignalServiceProtosCallMessage* callMessage;
|
||||
@property (readonly, strong) OWSSignalServiceProtosNullMessage* nullMessage;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
@ -352,143 +343,6 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (OWSSignalServiceProtosContentBuilder*) setCallMessageBuilder:(OWSSignalServiceProtosCallMessageBuilder*) builderForValue;
|
||||
- (OWSSignalServiceProtosContentBuilder*) mergeCallMessage:(OWSSignalServiceProtosCallMessage*) value;
|
||||
- (OWSSignalServiceProtosContentBuilder*) clearCallMessage;
|
||||
|
||||
- (BOOL) hasNullMessage;
|
||||
- (OWSSignalServiceProtosNullMessage*) nullMessage;
|
||||
- (OWSSignalServiceProtosContentBuilder*) setNullMessage:(OWSSignalServiceProtosNullMessage*) value;
|
||||
- (OWSSignalServiceProtosContentBuilder*) setNullMessageBuilder:(OWSSignalServiceProtosNullMessageBuilder*) builderForValue;
|
||||
- (OWSSignalServiceProtosContentBuilder*) mergeNullMessage:(OWSSignalServiceProtosNullMessage*) value;
|
||||
- (OWSSignalServiceProtosContentBuilder*) clearNullMessage;
|
||||
@end
|
||||
|
||||
#define NullMessage_padding @"padding"
|
||||
@interface OWSSignalServiceProtosNullMessage : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasPadding_:1;
|
||||
NSData* padding;
|
||||
}
|
||||
- (BOOL) hasPadding;
|
||||
@property (readonly, strong) NSData* padding;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
|
||||
- (BOOL) isInitialized;
|
||||
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosNullMessageBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosNullMessageBuilder*) builderWithPrototype:(OWSSignalServiceProtosNullMessage*) prototype;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) toBuilder;
|
||||
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromData:(NSData*) data;
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromInputStream:(NSInputStream*) input;
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
+ (OWSSignalServiceProtosNullMessage*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosNullMessageBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosNullMessage* resultNullMessage;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosNullMessage*) defaultInstance;
|
||||
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) clear;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) clone;
|
||||
|
||||
- (OWSSignalServiceProtosNullMessage*) build;
|
||||
- (OWSSignalServiceProtosNullMessage*) buildPartial;
|
||||
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) mergeFrom:(OWSSignalServiceProtosNullMessage*) other;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
|
||||
- (BOOL) hasPadding;
|
||||
- (NSData*) padding;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) setPadding:(NSData*) value;
|
||||
- (OWSSignalServiceProtosNullMessageBuilder*) clearPadding;
|
||||
@end
|
||||
|
||||
#define Verified_destination @"destination"
|
||||
#define Verified_identityKey @"identityKey"
|
||||
#define Verified_state @"state"
|
||||
#define Verified_nullMessage @"nullMessage"
|
||||
@interface OWSSignalServiceProtosVerified : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasDestination_:1;
|
||||
BOOL hasIdentityKey_:1;
|
||||
BOOL hasNullMessage_:1;
|
||||
BOOL hasState_:1;
|
||||
NSString* destination;
|
||||
NSData* identityKey;
|
||||
NSData* nullMessage;
|
||||
OWSSignalServiceProtosVerifiedState state;
|
||||
}
|
||||
- (BOOL) hasDestination;
|
||||
- (BOOL) hasIdentityKey;
|
||||
- (BOOL) hasState;
|
||||
- (BOOL) hasNullMessage;
|
||||
@property (readonly, strong) NSString* destination;
|
||||
@property (readonly, strong) NSData* identityKey;
|
||||
@property (readonly) OWSSignalServiceProtosVerifiedState state;
|
||||
@property (readonly, strong) NSData* nullMessage;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
|
||||
- (BOOL) isInitialized;
|
||||
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosVerifiedBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosVerifiedBuilder*) builderWithPrototype:(OWSSignalServiceProtosVerified*) prototype;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) toBuilder;
|
||||
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromData:(NSData*) data;
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromInputStream:(NSInputStream*) input;
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
+ (OWSSignalServiceProtosVerified*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosVerifiedBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosVerified* resultVerified;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosVerified*) defaultInstance;
|
||||
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clear;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clone;
|
||||
|
||||
- (OWSSignalServiceProtosVerified*) build;
|
||||
- (OWSSignalServiceProtosVerified*) buildPartial;
|
||||
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) mergeFrom:(OWSSignalServiceProtosVerified*) other;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
|
||||
- (BOOL) hasDestination;
|
||||
- (NSString*) destination;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) setDestination:(NSString*) value;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clearDestination;
|
||||
|
||||
- (BOOL) hasIdentityKey;
|
||||
- (NSData*) identityKey;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) setIdentityKey:(NSData*) value;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clearIdentityKey;
|
||||
|
||||
- (BOOL) hasState;
|
||||
- (OWSSignalServiceProtosVerifiedState) state;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) setState:(OWSSignalServiceProtosVerifiedState) value;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clearState;
|
||||
|
||||
- (BOOL) hasNullMessage;
|
||||
- (NSData*) nullMessage;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) setNullMessage:(NSData*) value;
|
||||
- (OWSSignalServiceProtosVerifiedBuilder*) clearNullMessage;
|
||||
@end
|
||||
|
||||
#define CallMessage_offer @"offer"
|
||||
@ -987,8 +841,7 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
#define SyncMessage_request @"request"
|
||||
#define SyncMessage_read @"read"
|
||||
#define SyncMessage_blocked @"blocked"
|
||||
#define SyncMessage_verified @"verified"
|
||||
#define SyncMessage_padding @"padding"
|
||||
#define SyncMessage_verification @"verification"
|
||||
@interface OWSSignalServiceProtosSyncMessage : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasSent_:1;
|
||||
@ -996,33 +849,28 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
BOOL hasGroups_:1;
|
||||
BOOL hasRequest_:1;
|
||||
BOOL hasBlocked_:1;
|
||||
BOOL hasVerified_:1;
|
||||
BOOL hasPadding_:1;
|
||||
OWSSignalServiceProtosSyncMessageSent* sent;
|
||||
OWSSignalServiceProtosSyncMessageContacts* contacts;
|
||||
OWSSignalServiceProtosSyncMessageGroups* groups;
|
||||
OWSSignalServiceProtosSyncMessageRequest* request;
|
||||
OWSSignalServiceProtosSyncMessageBlocked* blocked;
|
||||
OWSSignalServiceProtosVerified* verified;
|
||||
NSData* padding;
|
||||
NSMutableArray * readArray;
|
||||
NSMutableArray * verificationArray;
|
||||
}
|
||||
- (BOOL) hasSent;
|
||||
- (BOOL) hasContacts;
|
||||
- (BOOL) hasGroups;
|
||||
- (BOOL) hasRequest;
|
||||
- (BOOL) hasBlocked;
|
||||
- (BOOL) hasVerified;
|
||||
- (BOOL) hasPadding;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageSent* sent;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageContacts* contacts;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageGroups* groups;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageRequest* request;
|
||||
@property (readonly, strong) NSArray<OWSSignalServiceProtosSyncMessageRead*> * read;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageBlocked* blocked;
|
||||
@property (readonly, strong) OWSSignalServiceProtosVerified* verified;
|
||||
@property (readonly, strong) NSData* padding;
|
||||
@property (readonly, strong) NSArray<OWSSignalServiceProtosSyncMessageVerification*> * verification;
|
||||
- (OWSSignalServiceProtosSyncMessageRead*)readAtIndex:(NSUInteger)index;
|
||||
- (OWSSignalServiceProtosSyncMessageVerification*)verificationAtIndex:(NSUInteger)index;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
@ -1398,6 +1246,76 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (OWSSignalServiceProtosSyncMessageReadBuilder*) clearTimestamp;
|
||||
@end
|
||||
|
||||
#define Verification_state @"state"
|
||||
#define Verification_destination @"destination"
|
||||
#define Verification_identityKey @"identityKey"
|
||||
@interface OWSSignalServiceProtosSyncMessageVerification : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasDestination_:1;
|
||||
BOOL hasIdentityKey_:1;
|
||||
BOOL hasState_:1;
|
||||
NSString* destination;
|
||||
NSData* identityKey;
|
||||
OWSSignalServiceProtosSyncMessageVerificationState state;
|
||||
}
|
||||
- (BOOL) hasState;
|
||||
- (BOOL) hasDestination;
|
||||
- (BOOL) hasIdentityKey;
|
||||
@property (readonly) OWSSignalServiceProtosSyncMessageVerificationState state;
|
||||
@property (readonly, strong) NSString* destination;
|
||||
@property (readonly, strong) NSData* identityKey;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
|
||||
- (BOOL) isInitialized;
|
||||
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerificationBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerificationBuilder*) builderWithPrototype:(OWSSignalServiceProtosSyncMessageVerification*) prototype;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) toBuilder;
|
||||
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromData:(NSData*) data;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromInputStream:(NSInputStream*) input;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerification*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosSyncMessageVerificationBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosSyncMessageVerification* resultVerification;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerification*) defaultInstance;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) clear;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) clone;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerification*) build;
|
||||
- (OWSSignalServiceProtosSyncMessageVerification*) buildPartial;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) mergeFrom:(OWSSignalServiceProtosSyncMessageVerification*) other;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
|
||||
- (BOOL) hasState;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationState) state;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) setState:(OWSSignalServiceProtosSyncMessageVerificationState) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) clearState;
|
||||
|
||||
- (BOOL) hasDestination;
|
||||
- (NSString*) destination;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) setDestination:(NSString*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) clearDestination;
|
||||
|
||||
- (BOOL) hasIdentityKey;
|
||||
- (NSData*) identityKey;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) setIdentityKey:(NSData*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerificationBuilder*) clearIdentityKey;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosSyncMessageBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosSyncMessage* resultSyncMessage;
|
||||
@ -1456,17 +1374,11 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) mergeBlocked:(OWSSignalServiceProtosSyncMessageBlocked*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) clearBlocked;
|
||||
|
||||
- (BOOL) hasVerified;
|
||||
- (OWSSignalServiceProtosVerified*) verified;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) setVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) setVerifiedBuilder:(OWSSignalServiceProtosVerifiedBuilder*) builderForValue;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) mergeVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) clearVerified;
|
||||
|
||||
- (BOOL) hasPadding;
|
||||
- (NSData*) padding;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) setPadding:(NSData*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) clearPadding;
|
||||
- (NSMutableArray<OWSSignalServiceProtosSyncMessageVerification*> *)verification;
|
||||
- (OWSSignalServiceProtosSyncMessageVerification*)verificationAtIndex:(NSUInteger)index;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)addVerification:(OWSSignalServiceProtosSyncMessageVerification*)value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)setVerificationArray:(NSArray<OWSSignalServiceProtosSyncMessageVerification*> *)array;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)clearVerification;
|
||||
@end
|
||||
|
||||
#define AttachmentPointer_id @"id"
|
||||
@ -1685,30 +1597,25 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
#define ContactDetails_name @"name"
|
||||
#define ContactDetails_avatar @"avatar"
|
||||
#define ContactDetails_color @"color"
|
||||
#define ContactDetails_verified @"verified"
|
||||
@interface OWSSignalServiceProtosContactDetails : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasNumber_:1;
|
||||
BOOL hasName_:1;
|
||||
BOOL hasColor_:1;
|
||||
BOOL hasAvatar_:1;
|
||||
BOOL hasVerified_:1;
|
||||
NSString* number;
|
||||
NSString* name;
|
||||
NSString* color;
|
||||
OWSSignalServiceProtosContactDetailsAvatar* avatar;
|
||||
OWSSignalServiceProtosVerified* verified;
|
||||
}
|
||||
- (BOOL) hasNumber;
|
||||
- (BOOL) hasName;
|
||||
- (BOOL) hasAvatar;
|
||||
- (BOOL) hasColor;
|
||||
- (BOOL) hasVerified;
|
||||
@property (readonly, strong) NSString* number;
|
||||
@property (readonly, strong) NSString* name;
|
||||
@property (readonly, strong) OWSSignalServiceProtosContactDetailsAvatar* avatar;
|
||||
@property (readonly, strong) NSString* color;
|
||||
@property (readonly, strong) OWSSignalServiceProtosVerified* verified;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
@ -1826,13 +1733,6 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (NSString*) color;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) setColor:(NSString*) value;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) clearColor;
|
||||
|
||||
- (BOOL) hasVerified;
|
||||
- (OWSSignalServiceProtosVerified*) verified;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) setVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) setVerifiedBuilder:(OWSSignalServiceProtosVerifiedBuilder*) builderForValue;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) mergeVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosContactDetailsBuilder*) clearVerified;
|
||||
@end
|
||||
|
||||
#define GroupDetails_id @"id"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@ typedef enum {
|
||||
RPRecentCallTypeOutgoingIncomplete,
|
||||
RPRecentCallTypeIncomingIncomplete,
|
||||
RPRecentCallTypeMissedBecauseOfChangedIdentity,
|
||||
RPRecentCallTypeIncomingDeclined
|
||||
RPRecentCallTypeDeclined,
|
||||
} RPRecentCallType;
|
||||
|
||||
@interface TSCall : TSInteraction <OWSReadTracking>
|
||||
|
||||
@ -76,9 +76,9 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
|
||||
return NSLocalizedString(@"INCOMING_INCOMPLETE_CALL", @"");
|
||||
case RPRecentCallTypeMissedBecauseOfChangedIdentity:
|
||||
return NSLocalizedString(@"INFO_MESSAGE_MISSED_CALL_DUE_TO_CHANGED_IDENITY", @"info message text shown in conversation view");
|
||||
case RPRecentCallTypeIncomingDeclined:
|
||||
return NSLocalizedString(@"INCOMING_DECLINED_CALL",
|
||||
@"info message recorded in conversation history when local user declined a call");
|
||||
case RPRecentCallTypeDeclined:
|
||||
return NSLocalizedString(@"INFO_MESSAGE_CALL_DECLINED",
|
||||
@"Message in conversation history that indicates a declined incoming call.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,12 +99,14 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
|
||||
_read = YES;
|
||||
[self saveWithTransaction:transaction];
|
||||
[self touchThreadWithTransaction:transaction];
|
||||
|
||||
// Ignore sendReadReceipt and updateExpiration; they don't apply to calls.
|
||||
//
|
||||
// TODO: Should we update expiration of calls?
|
||||
}
|
||||
|
||||
#pragma mark - Methods
|
||||
@ -119,7 +121,7 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
|
||||
|
||||
_callType = callType;
|
||||
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
|
||||
// redraw any thread-related unread count UI.
|
||||
|
||||
@ -50,7 +50,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
@property (nonatomic, readonly) OWSIncomingMessageFinder *incomingMessageFinder;
|
||||
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
|
||||
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
|
||||
|
||||
@end
|
||||
|
||||
@ -74,16 +73,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
id<ContactsManagerProtocol> contactsManager = [TextSecureKitEnv sharedEnv].contactsManager;
|
||||
id<OWSCallMessageHandler> callMessageHandler = [TextSecureKitEnv sharedEnv].callMessageHandler;
|
||||
ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater];
|
||||
OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager];
|
||||
OWSMessageSender *messageSender = [TextSecureKitEnv sharedEnv].messageSender;
|
||||
|
||||
|
||||
return [self initWithNetworkManager:networkManager
|
||||
storageManager:storageManager
|
||||
callMessageHandler:callMessageHandler
|
||||
contactsManager:contactsManager
|
||||
contactsUpdater:contactsUpdater
|
||||
identityManager:identityManager
|
||||
messageSender:messageSender];
|
||||
}
|
||||
|
||||
@ -92,7 +88,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
callMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
messageSender:(OWSMessageSender *)messageSender
|
||||
{
|
||||
self = [super init];
|
||||
@ -106,7 +101,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
_callMessageHandler = callMessageHandler;
|
||||
_contactsManager = contactsManager;
|
||||
_contactsUpdater = contactsUpdater;
|
||||
_identityManager = identityManager;
|
||||
_messageSender = messageSender;
|
||||
|
||||
_dbConnection = storageManager.newDatabaseConnection;
|
||||
@ -115,24 +109,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
[self startObserving];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startObserving
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(yapDatabaseModified:)
|
||||
name:YapDatabaseModifiedNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)yapDatabaseModified:(NSNotification *)notification
|
||||
{
|
||||
[self updateApplicationBadgeCount];
|
||||
}
|
||||
|
||||
#pragma mark - Debugging
|
||||
|
||||
- (NSString *)descriptionForEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
@ -186,8 +165,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return [NSString stringWithFormat:@"<DataMessage: %@ />", [self descriptionForDataMessage:content.dataMessage]];
|
||||
} else if (content.hasCallMessage) {
|
||||
return [NSString stringWithFormat:@"<CallMessage: %@ />", content.callMessage];
|
||||
} else if (content.hasNullMessage) {
|
||||
return [NSString stringWithFormat:@"<NullMessage: %@ />", content.nullMessage];
|
||||
} else {
|
||||
OWSAssert(NO);
|
||||
return @"UnknownContent";
|
||||
@ -242,10 +219,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[description appendString:@"Blocked"];
|
||||
} else if (syncMessage.read.count > 0) {
|
||||
[description appendString:@"ReadReceipt"];
|
||||
} else if (syncMessage.hasVerified) {
|
||||
NSString *verifiedString =
|
||||
[NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination];
|
||||
[description appendString:verifiedString];
|
||||
} else {
|
||||
// Shouldn't happen
|
||||
OWSAssert(NO);
|
||||
@ -387,7 +360,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:self.identityManager
|
||||
identityKeyStore:[OWSIdentityManager sharedManager]
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
@ -439,7 +412,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:self.identityManager
|
||||
identityKeyStore:[OWSIdentityManager sharedManager]
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
@ -473,7 +446,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
sourceId:envelope.source
|
||||
sourceDeviceId:envelope.sourceDevice];
|
||||
if (duplicateEnvelope) {
|
||||
DDLogInfo(@"%@ Ignoring previously received envelope from %@.%d with timestamp: %llu", self.tag, envelope.source, (unsigned int)envelope.sourceDevice, envelope.timestamp);
|
||||
DDLogInfo(@"%@ Ignoring previously received envelope with timestamp: %llu", self.tag, envelope.timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -486,8 +459,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[self handleIncomingEnvelope:envelope withDataMessage:content.dataMessage];
|
||||
} else if (content.hasCallMessage) {
|
||||
[self handleIncomingEnvelope:envelope withCallMessage:content.callMessage];
|
||||
} else if (content.hasNullMessage) {
|
||||
DDLogInfo(@"%@ Received null message.", self.tag);
|
||||
} else {
|
||||
DDLogWarn(@"%@ Ignoring envelope. Content with no known payload", self.tag);
|
||||
}
|
||||
@ -525,7 +496,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSString *recipientId = incomingEnvelope.source;
|
||||
|
||||
__block TSThread *thread;
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
[[TSStorageManager sharedManager].dbConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
||||
}];
|
||||
@ -674,8 +645,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
} else if (syncMessage.hasRequest) {
|
||||
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
|
||||
OWSSyncContactsMessage *syncContactsMessage =
|
||||
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager
|
||||
identityManager:self.identityManager];
|
||||
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager];
|
||||
|
||||
[self.messageSender sendTemporaryAttachmentData:[syncContactsMessage buildPlainTextAttachmentData]
|
||||
contentType:OWSMimeTypeApplicationOctetStream
|
||||
@ -686,6 +656,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
failure:^(NSError *error) {
|
||||
DDLogError(@"%@ Failed to send Contacts response syncMessage with error: %@", self.tag, error);
|
||||
}];
|
||||
|
||||
// Also sync all verification state after syncing contacts.
|
||||
[[OWSIdentityManager sharedManager] syncAllVerificationStates];
|
||||
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
|
||||
OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init];
|
||||
|
||||
@ -711,9 +684,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[OWSReadReceiptsProcessor alloc] initWithReadReceiptProtos:syncMessage.read
|
||||
storageManager:self.storageManager];
|
||||
[readReceiptsProcessor process];
|
||||
} else if (syncMessage.hasVerified) {
|
||||
DDLogInfo(@"%@ Received verification state for %@", self.tag, syncMessage.verified.destination);
|
||||
[self.identityManager processIncomingSyncMessage:syncMessage.verified];
|
||||
} else if (syncMessage.verification.count > 0) {
|
||||
DDLogInfo(@"%@ Received %ld verification state(s)", self.tag, (u_long)syncMessage.verification.count);
|
||||
|
||||
[[OWSIdentityManager sharedManager] processIncomingSyncMessage:syncMessage.verification];
|
||||
} else {
|
||||
DDLogWarn(@"%@ Ignoring unsupported sync message.", self.tag);
|
||||
}
|
||||
@ -1083,12 +1057,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return numberOfItems;
|
||||
}
|
||||
|
||||
- (void)updateApplicationBadgeCount
|
||||
{
|
||||
NSUInteger numberOfItems = [self unreadMessagesCount];
|
||||
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:numberOfItems];
|
||||
}
|
||||
|
||||
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread {
|
||||
__block NSUInteger numberOfItems;
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
|
||||
@ -30,7 +30,7 @@ extern NSString *const TSNetworkManagerDomain;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
+ (id)sharedManager;
|
||||
|
||||
- (void)makeRequest:(TSRequest *)request
|
||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
|
||||
@ -22,8 +22,7 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
|
||||
|
||||
#pragma mark Singleton implementation
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
+ (id)sharedManager {
|
||||
static TSNetworkManager *sharedMyManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
||||
@ -160,6 +160,7 @@ NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange =
|
||||
DDLogInfo(@"%@ using reflector HTTPSessionManager", self.tag);
|
||||
return self.reflectorHTTPSessionManager;
|
||||
} else {
|
||||
DDLogDebug(@"%@ using default HTTPSessionManager", self.tag);
|
||||
return self.defaultHTTPSessionManager;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,6 +156,7 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
|
||||
if (self.websocket) {
|
||||
switch ([self.websocket readyState]) {
|
||||
case SR_OPEN:
|
||||
DDLogVerbose(@"WebSocket already open on connection request");
|
||||
self.state = SocketManagerStateOpen;
|
||||
return;
|
||||
case SR_CONNECTING:
|
||||
@ -233,7 +234,7 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogWarn(@"%@ Socket state: %@ -> %@",
|
||||
DDLogWarn(@"%@ Socket state change: %@ -> %@",
|
||||
self.tag,
|
||||
[self stringFromSocketManagerState:_state],
|
||||
[self stringFromSocketManagerState:state]);
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import <SignalServiceKit/TSYapDatabaseObject.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -14,7 +13,6 @@ typedef NS_ENUM(NSUInteger, OWSVerificationState) {
|
||||
};
|
||||
|
||||
NSString *OWSVerificationStateToString(OWSVerificationState verificationState);
|
||||
OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState);
|
||||
|
||||
@interface OWSRecipientIdentity : TSYapDatabaseObject
|
||||
|
||||
|
||||
@ -20,18 +20,6 @@ NSString *OWSVerificationStateToString(OWSVerificationState verificationState)
|
||||
}
|
||||
}
|
||||
|
||||
OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState)
|
||||
{
|
||||
switch (verificationState) {
|
||||
case OWSVerificationStateDefault:
|
||||
return OWSSignalServiceProtosVerifiedStateDefault;
|
||||
case OWSVerificationStateVerified:
|
||||
return OWSSignalServiceProtosVerifiedStateVerified;
|
||||
case OWSVerificationStateNoLongerVerified:
|
||||
return OWSSignalServiceProtosVerifiedStateUnverified;
|
||||
}
|
||||
}
|
||||
|
||||
@interface OWSRecipientIdentity ()
|
||||
|
||||
@property (atomic) OWSVerificationState verificationState;
|
||||
@ -91,7 +79,7 @@ OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerifica
|
||||
{
|
||||
changeBlock(self);
|
||||
|
||||
[[self class].dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[[self class].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
OWSRecipientIdentity *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
|
||||
if (latest == nil) {
|
||||
[self saveWithTransaction:transaction];
|
||||
|
||||
@ -170,6 +170,7 @@ void AssertIsOnSessionStoreQueue()
|
||||
sessionRecords =
|
||||
[transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
||||
|
||||
|
||||
for (id deviceId in sessionRecords) {
|
||||
id object = sessionRecords[deviceId];
|
||||
if (![object isKindOfClass:[SessionRecord class]]) {
|
||||
|
||||
@ -148,7 +148,7 @@ NSString *const TSStorageManagerKeyPrekeyCurrentSignedPrekeyId = @"currentSigned
|
||||
NSDate *firstPrekeyUpdateFailureDate = [self firstPrekeyUpdateFailureDate];
|
||||
NSUInteger prekeyUpdateFailureCount = [self prekeyUpdateFailureCount];
|
||||
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
__block int i = 0;
|
||||
|
||||
DDLogInfo(@"%@ SignedPreKeys Report:", tag);
|
||||
|
||||
@ -1,30 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// Notes:
|
||||
//
|
||||
// * On disk, we only bother cleaning up files, not directories.
|
||||
// * For code simplicity, we don't guarantee that everything is
|
||||
// cleaned up in a single pass. If an interaction is cleaned up,
|
||||
// it's attachments might not be cleaned up until the next pass.
|
||||
// If an attachment is cleaned up, it's file on disk might not
|
||||
// be cleaned up until the next pass.
|
||||
@interface OWSOrphanedDataCleaner : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (void)auditAsync;
|
||||
|
||||
// completion, if present, will be invoked on the main thread.
|
||||
+ (void)auditAndCleanupAsync:(void (^_Nullable)())completion;
|
||||
|
||||
+ (NSSet<NSString *> *)filePathsInAttachmentsFolder;
|
||||
|
||||
+ (long long)fileSizeOfFilePaths:(NSArray<NSString *> *)filePaths;
|
||||
/**
|
||||
* Remove any inaccessible data left behind due to application bugs.
|
||||
*/
|
||||
- (void)removeOrphanedData;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSOrphanedDataCleaner.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -9,256 +7,84 @@
|
||||
#import "TSStorageManager.h"
|
||||
#import "TSThread.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#ifdef SSK_BUILDING_FOR_TESTS
|
||||
#define CleanupLogDebug NSLog
|
||||
#define CleanupLogInfo NSLog
|
||||
#else
|
||||
#define CleanupLogDebug DDLogDebug
|
||||
#define CleanupLogInfo DDLogInfo
|
||||
#endif
|
||||
|
||||
@implementation OWSOrphanedDataCleaner
|
||||
|
||||
+ (void)auditAsync
|
||||
- (void)removeOrphanedData
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[OWSOrphanedDataCleaner auditAndCleanup:NO completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)auditAndCleanupAsync:(void (^_Nullable)())completion
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[OWSOrphanedDataCleaner auditAndCleanup:YES completion:completion];
|
||||
});
|
||||
}
|
||||
|
||||
// This method finds and optionally cleans up:
|
||||
//
|
||||
// * Orphan messages (with no thread).
|
||||
// * Orphan attachments (with no message).
|
||||
// * Orphan attachment files (with no attachment).
|
||||
// * Missing attachment files (cannot be cleaned up).
|
||||
// These are attachments which have no file on disk. They should be extremely rare -
|
||||
// the only cases I have seen are probably due to debugging.
|
||||
// They can't be cleaned up - we don't want to delete the TSAttachmentStream or
|
||||
// its corresponding message. Better that the broken message shows up in the
|
||||
// conversation view.
|
||||
+ (void)auditAndCleanup:(BOOL)shouldCleanup completion:(void (^_Nullable)())completion
|
||||
{
|
||||
NSSet<NSString *> *diskFilePaths = [self filePathsInAttachmentsFolder];
|
||||
long long totalFileSize = [self fileSizeOfFilePaths:diskFilePaths.allObjects];
|
||||
NSUInteger fileCount = diskFilePaths.count;
|
||||
|
||||
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
||||
YapDatabaseConnection *databaseConnection = storageManager.newDatabaseConnection;
|
||||
|
||||
__block int attachmentStreamCount = 0;
|
||||
NSMutableSet<NSString *> *attachmentFilePaths = [NSMutableSet new];
|
||||
NSMutableSet<NSString *> *attachmentIds = [NSMutableSet new];
|
||||
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[transaction enumerateKeysAndObjectsInCollection:TSAttachmentStream.collection
|
||||
usingBlock:^(NSString *key, TSAttachment *attachment, BOOL *stop) {
|
||||
[attachmentIds addObject:attachment.uniqueId];
|
||||
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
return;
|
||||
}
|
||||
TSAttachmentStream *attachmentStream
|
||||
= (TSAttachmentStream *)attachment;
|
||||
attachmentStreamCount++;
|
||||
NSString *_Nullable filePath = [attachmentStream filePath];
|
||||
OWSAssert(filePath);
|
||||
[attachmentFilePaths addObject:filePath];
|
||||
}];
|
||||
}];
|
||||
|
||||
CleanupLogDebug(@"fileCount: %zd", fileCount);
|
||||
CleanupLogDebug(@"totalFileSize: %lld", totalFileSize);
|
||||
CleanupLogDebug(@"attachmentStreams: %d", attachmentStreamCount);
|
||||
CleanupLogDebug(@"attachmentStreams with file paths: %zd", attachmentFilePaths.count);
|
||||
|
||||
NSMutableSet<NSString *> *orphanDiskFilePaths = [diskFilePaths mutableCopy];
|
||||
[orphanDiskFilePaths minusSet:attachmentFilePaths];
|
||||
NSMutableSet<NSString *> *missingAttachmentFilePaths = [attachmentFilePaths mutableCopy];
|
||||
[missingAttachmentFilePaths minusSet:diskFilePaths];
|
||||
|
||||
CleanupLogDebug(@"orphan disk file paths: %zd", orphanDiskFilePaths.count);
|
||||
CleanupLogDebug(@"missing attachment file paths: %zd", missingAttachmentFilePaths.count);
|
||||
|
||||
[self printPaths:orphanDiskFilePaths.allObjects label:@"orphan disk file paths"];
|
||||
[self printPaths:missingAttachmentFilePaths.allObjects label:@"missing attachment file paths"];
|
||||
|
||||
NSMutableSet *threadIds = [NSMutableSet new];
|
||||
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[transaction enumerateKeysInCollection:TSThread.collection
|
||||
usingBlock:^(NSString *_Nonnull key, BOOL *_Nonnull stop) {
|
||||
[threadIds addObject:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
NSMutableSet<NSString *> *orphanInteractionIds = [NSMutableSet new];
|
||||
NSMutableSet<NSString *> *messageAttachmentIds = [NSMutableSet new];
|
||||
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[transaction enumerateKeysAndObjectsInCollection:TSMessage.collection
|
||||
usingBlock:^(NSString *key, TSInteraction *interaction, BOOL *stop) {
|
||||
if (![threadIds containsObject:interaction.uniqueThreadId]) {
|
||||
[orphanInteractionIds addObject:interaction.uniqueId];
|
||||
}
|
||||
|
||||
if (![interaction isKindOfClass:[TSMessage class]]) {
|
||||
return;
|
||||
}
|
||||
TSMessage *message = (TSMessage *)interaction;
|
||||
if (message.attachmentIds.count > 0) {
|
||||
[messageAttachmentIds addObjectsFromArray:message.attachmentIds];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
CleanupLogDebug(@"attachmentIds: %zd", attachmentIds.count);
|
||||
CleanupLogDebug(@"messageAttachmentIds: %zd", messageAttachmentIds.count);
|
||||
|
||||
NSMutableSet<NSString *> *orphanAttachmentIds = [attachmentIds mutableCopy];
|
||||
[orphanAttachmentIds minusSet:messageAttachmentIds];
|
||||
NSMutableSet<NSString *> *missingAttachmentIds = [messageAttachmentIds mutableCopy];
|
||||
[missingAttachmentIds minusSet:attachmentIds];
|
||||
|
||||
CleanupLogDebug(@"orphan attachmentIds: %zd", orphanAttachmentIds.count);
|
||||
CleanupLogDebug(@"missing attachmentIds: %zd", missingAttachmentIds.count);
|
||||
CleanupLogDebug(@"orphan interactions: %zd", orphanInteractionIds.count);
|
||||
|
||||
// We need to avoid cleaning up new attachments and files that are still in the process of
|
||||
// being created/written, so we don't clean up anything recent.
|
||||
#ifdef SSK_BUILDING_FOR_TESTS
|
||||
const NSTimeInterval kMinimumOrphanAge = 0.f;
|
||||
#else
|
||||
const NSTimeInterval kMinimumOrphanAge = 15 * 60.f;
|
||||
#endif
|
||||
|
||||
if (!shouldCleanup) {
|
||||
return;
|
||||
// Remove interactions whose threads have been deleted
|
||||
for (NSString *interactionId in [self orphanedInteractionIds]) {
|
||||
DDLogWarn(@"Removing orphaned interaction with id: %@", interactionId);
|
||||
TSInteraction *interaction = [TSInteraction fetchObjectWithUniqueID:interactionId];
|
||||
[interaction remove];
|
||||
}
|
||||
|
||||
[databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
for (NSString *interactionId in orphanInteractionIds) {
|
||||
TSInteraction *interaction = [TSInteraction fetchObjectWithUniqueID:interactionId transaction:transaction];
|
||||
if (!interaction) {
|
||||
// This could just be a race condition, but it should be very unlikely.
|
||||
OWSFail(@"Could not load interaction: %@", interactionId);
|
||||
continue;
|
||||
}
|
||||
CleanupLogInfo(@"Removing orphan message: %@", interaction.uniqueId);
|
||||
[interaction removeWithTransaction:transaction];
|
||||
}
|
||||
for (NSString *attachmentId in orphanAttachmentIds) {
|
||||
TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction];
|
||||
if (!attachment) {
|
||||
// This could just be a race condition, but it should be very unlikely.
|
||||
OWSFail(@"Could not load attachment: %@", attachmentId);
|
||||
continue;
|
||||
}
|
||||
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
continue;
|
||||
}
|
||||
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
|
||||
// Don't delete attachments which were created in the last N minutes.
|
||||
if (fabs([attachmentStream.creationTimestamp timeIntervalSinceNow]) < kMinimumOrphanAge) {
|
||||
CleanupLogInfo(@"Skipping orphan attachment due to age: %f",
|
||||
fabs([attachmentStream.creationTimestamp timeIntervalSinceNow]));
|
||||
continue;
|
||||
}
|
||||
CleanupLogInfo(@"Removing orphan attachment: %@", attachmentStream.uniqueId);
|
||||
[attachmentStream removeWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
for (NSString *filePath in orphanDiskFilePaths) {
|
||||
// Remove any lingering attachments
|
||||
for (NSString *path in [self orphanedFilePaths]) {
|
||||
DDLogWarn(@"Removing orphaned file attachment at path: %@", path);
|
||||
NSError *error;
|
||||
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error];
|
||||
if (!attributes || error) {
|
||||
OWSFail(@"Could not get attributes of file at: %@", filePath);
|
||||
continue;
|
||||
}
|
||||
// Don't delete files which were created in the last N minutes.
|
||||
if (fabs([attributes.fileModificationDate timeIntervalSinceNow]) < kMinimumOrphanAge) {
|
||||
CleanupLogInfo(@"Skipping orphan attachment file due to age: %f",
|
||||
fabs([attributes.fileModificationDate timeIntervalSinceNow]));
|
||||
continue;
|
||||
}
|
||||
|
||||
CleanupLogInfo(@"Removing orphan attachment file: %@", filePath);
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
||||
if (error) {
|
||||
OWSFail(@"Could not remove orphan file at: %@", filePath);
|
||||
DDLogError(@"Unable to remove orphaned file attachment at path:%@", path);
|
||||
}
|
||||
}
|
||||
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)printPaths:(NSArray<NSString *> *)paths label:(NSString *)label
|
||||
- (NSArray<NSString *> *)orphanedInteractionIds
|
||||
{
|
||||
for (NSString *path in [paths sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
CleanupLogDebug(@"%@: %@", label, path);
|
||||
}
|
||||
NSMutableArray *interactionIds = [NSMutableArray new];
|
||||
[[TSInteraction dbConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[TSInteraction enumerateCollectionObjectsWithTransaction:transaction
|
||||
usingBlock:^(TSInteraction *interaction, BOOL *stop) {
|
||||
TSThread *thread = [TSThread
|
||||
fetchObjectWithUniqueID:interaction.uniqueThreadId
|
||||
transaction:transaction];
|
||||
if (!thread) {
|
||||
[interactionIds addObject:interaction.uniqueId];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
|
||||
return [interactionIds copy];
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)filePathsInAttachmentsFolder
|
||||
- (NSArray<NSString *> *)orphanedFilePaths
|
||||
{
|
||||
NSString *attachmentsFolder = [TSAttachmentStream attachmentsFolder];
|
||||
CleanupLogDebug(@"attachmentsFolder: %@", attachmentsFolder);
|
||||
|
||||
return [self filePathsInDirectory:attachmentsFolder];
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)filePathsInDirectory:(NSString *)dirPath
|
||||
{
|
||||
NSMutableSet *filePaths = [NSMutableSet new];
|
||||
NSError *error;
|
||||
NSArray<NSString *> *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dirPath error:&error];
|
||||
NSMutableArray<NSString *> *filenames =
|
||||
[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[TSAttachmentStream attachmentsFolder] error:&error]
|
||||
mutableCopy];
|
||||
if (error) {
|
||||
OWSFail(@"contentsOfDirectoryAtPath error: %@", error);
|
||||
return [NSSet new];
|
||||
DDLogError(@"error getting orphanedFilePaths:%@", error);
|
||||
return @[];
|
||||
}
|
||||
for (NSString *fileName in fileNames) {
|
||||
NSString *filePath = [dirPath stringByAppendingPathComponent:fileName];
|
||||
BOOL isDirectory;
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory];
|
||||
if (isDirectory) {
|
||||
[filePaths addObjectsFromArray:[self filePathsInDirectory:filePath].allObjects];
|
||||
} else {
|
||||
[filePaths addObject:filePath];
|
||||
|
||||
NSMutableDictionary<NSString *, NSString *> *attachmentIdFilenames = [NSMutableDictionary new];
|
||||
for (NSString *filename in filenames) {
|
||||
// Remove extension from (e.g.) 1234.png to get the attachmentId "1234"
|
||||
NSString *attachmentId = [filename stringByDeletingPathExtension];
|
||||
attachmentIdFilenames[attachmentId] = filename;
|
||||
}
|
||||
|
||||
[TSInteraction enumerateCollectionObjectsUsingBlock:^(TSInteraction *interaction, BOOL *stop) {
|
||||
if ([interaction isKindOfClass:[TSMessage class]]) {
|
||||
TSMessage *message = (TSMessage *)interaction;
|
||||
if ([message hasAttachments]) {
|
||||
for (NSString *attachmentId in message.attachmentIds) {
|
||||
[attachmentIdFilenames removeObjectForKey:attachmentId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
}];
|
||||
|
||||
+ (long long)fileSizeOfFilePath:(NSString *)filePath
|
||||
{
|
||||
NSError *error;
|
||||
NSNumber *fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error][NSFileSize];
|
||||
if (error) {
|
||||
OWSFail(@"attributesOfItemAtPath: %@ error: %@", filePath, error);
|
||||
return 0;
|
||||
NSArray<NSString *> *filenamesToDelete = [attachmentIdFilenames allValues];
|
||||
NSMutableArray<NSString *> *absolutePathsToDelete = [NSMutableArray arrayWithCapacity:[filenamesToDelete count]];
|
||||
for (NSString *filename in filenamesToDelete) {
|
||||
NSString *absolutePath = [[TSAttachmentStream attachmentsFolder] stringByAppendingFormat:@"/%@", filename];
|
||||
[absolutePathsToDelete addObject:absolutePath];
|
||||
}
|
||||
return fileSize.longLongValue;
|
||||
}
|
||||
|
||||
+ (long long)fileSizeOfFilePaths:(NSArray<NSString *> *)filePaths
|
||||
{
|
||||
long long result = 0;
|
||||
for (NSString *filePath in filePaths) {
|
||||
result += [self fileSizeOfFilePath:filePath];
|
||||
}
|
||||
return result;
|
||||
return [absolutePathsToDelete copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// TSDatabaseSecondaryIndexes.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 26/01/15.
|
||||
// Copyright (c) 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSDatabaseSecondaryIndexes.h"
|
||||
@ -39,5 +43,4 @@
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
|
||||
[[transaction ext:@"idx"] enumerateKeysMatchingQuery:query usingBlock:block];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -5,56 +5,36 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <YapDatabase/YapDatabaseViewTransaction.h>
|
||||
|
||||
extern NSString *const kNSNotificationName_DatabaseViewRegistrationComplete;
|
||||
|
||||
extern NSString *const TSInboxGroup;
|
||||
extern NSString *const TSArchiveGroup;
|
||||
extern NSString *const TSUnreadIncomingMessagesGroup;
|
||||
extern NSString *const TSSecondaryDevicesGroup;
|
||||
|
||||
extern NSString *const TSThreadDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSMessageDatabaseViewExtensionName;
|
||||
extern NSString *const TSUnreadDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSSecondaryDevicesDatabaseViewExtensionName;
|
||||
|
||||
@interface TSDatabaseView : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
extern NSString *TSInboxGroup;
|
||||
extern NSString *TSArchiveGroup;
|
||||
extern NSString *TSUnreadIncomingMessagesGroup;
|
||||
extern NSString *TSSecondaryDevicesGroup;
|
||||
|
||||
+ (BOOL)hasPendingViewRegistrations;
|
||||
extern NSString *TSThreadDatabaseViewExtensionName;
|
||||
extern NSString *TSMessageDatabaseViewExtensionName;
|
||||
extern NSString *TSThreadOutgoingMessageDatabaseViewExtensionName;
|
||||
extern NSString *TSUnreadDatabaseViewExtensionName;
|
||||
extern NSString *TSUnseenDatabaseViewExtensionName;
|
||||
extern NSString *TSThreadSpecialMessagesDatabaseViewExtensionName;
|
||||
extern NSString *TSSecondaryDevicesDatabaseViewExtensionName;
|
||||
|
||||
+ (void)registerThreadDatabaseView;
|
||||
|
||||
+ (void)registerThreadInteractionsDatabaseView;
|
||||
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView;
|
||||
+ (BOOL)registerThreadDatabaseView;
|
||||
+ (BOOL)registerThreadInteractionsDatabaseView;
|
||||
+ (BOOL)registerThreadOutgoingMessagesDatabaseView;
|
||||
|
||||
// Instances of OWSReadTracking for wasRead is NO and shouldAffectUnreadCounts is YES.
|
||||
//
|
||||
// Should be used for "unread message counts".
|
||||
+ (void)registerUnreadDatabaseView;
|
||||
+ (BOOL)registerUnreadDatabaseView;
|
||||
|
||||
// Should be used for "unread indicator".
|
||||
//
|
||||
// Instances of OWSReadTracking for wasRead is NO.
|
||||
+ (void)asyncRegisterUnseenDatabaseView;
|
||||
|
||||
+ (void)asyncRegisterThreadSpecialMessagesDatabaseView;
|
||||
+ (BOOL)registerUnseenDatabaseView;
|
||||
|
||||
+ (BOOL)registerThreadSpecialMessagesDatabaseView;
|
||||
+ (void)asyncRegisterSecondaryDevicesDatabaseView;
|
||||
|
||||
// Returns the "unseen" database view if it is ready;
|
||||
// otherwise it returns the "unread" database view.
|
||||
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
// NOTE: It is not safe to call this method while hasPendingViewRegistrations is YES.
|
||||
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
// NOTE: It is not safe to call this method while hasPendingViewRegistrations is YES.
|
||||
+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
// This method should be called _after_ all async database registrations have been started.
|
||||
+ (void)asyncRegistrationCompletion;
|
||||
|
||||
@end
|
||||
|
||||
@ -12,77 +12,32 @@
|
||||
#import "TSThread.h"
|
||||
#import <YapDatabase/YapDatabaseView.h>
|
||||
|
||||
NSString *const kNSNotificationName_DatabaseViewRegistrationComplete =
|
||||
@"kNSNotificationName_DatabaseViewRegistrationComplete";
|
||||
NSString *TSInboxGroup = @"TSInboxGroup";
|
||||
NSString *TSArchiveGroup = @"TSArchiveGroup";
|
||||
|
||||
NSString *const TSInboxGroup = @"TSInboxGroup";
|
||||
NSString *const TSArchiveGroup = @"TSArchiveGroup";
|
||||
NSString *TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
|
||||
NSString *TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
|
||||
|
||||
NSString *const TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
|
||||
NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
|
||||
|
||||
// YAPDB BUG: when changing from non-persistent to persistent view, we had to rename TSThreadDatabaseViewExtensionName
|
||||
// -> TSThreadDatabaseViewExtensionName2 to work around https://github.com/yapstudios/YapDatabase/issues/324
|
||||
NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName2";
|
||||
NSString *const TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName";
|
||||
NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName";
|
||||
NSString *const TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
|
||||
NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
|
||||
NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName";
|
||||
NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
|
||||
|
||||
@interface TSDatabaseView ()
|
||||
|
||||
@property (nonatomic) BOOL areAllAsyncRegistrationsComplete;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
NSString *TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName";
|
||||
NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName";
|
||||
NSString *TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName";
|
||||
NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
|
||||
NSString *TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
|
||||
NSString *TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName";
|
||||
NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
|
||||
|
||||
@implementation TSDatabaseView
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static TSDatabaseView *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] initDefault];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)initDefault
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)hasPendingViewRegistrations
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
return ![TSDatabaseView sharedInstance].areAllAsyncRegistrationsComplete;
|
||||
}
|
||||
|
||||
+ (void)registerMessageDatabaseViewWithName:(NSString *)viewName
|
||||
+ (BOOL)registerMessageDatabaseViewWithName:(NSString *)viewName
|
||||
viewGrouping:(YapDatabaseViewGrouping *)viewGrouping
|
||||
version:(NSString *)version
|
||||
async:(BOOL)async
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(viewName.length > 0);
|
||||
OWSAssert((viewGrouping));
|
||||
|
||||
YapDatabaseView *existingView = [[TSStorageManager sharedManager].database registeredExtension:viewName];
|
||||
if (existingView) {
|
||||
return;
|
||||
return YES;
|
||||
}
|
||||
|
||||
YapDatabaseViewSorting *viewSorting = [self messagesSorting];
|
||||
@ -95,21 +50,10 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
YapDatabaseView *view =
|
||||
[[YapDatabaseView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:version options:options];
|
||||
|
||||
if (async) {
|
||||
[[TSStorageManager sharedManager].database
|
||||
asyncRegisterExtension:view
|
||||
withName:viewName
|
||||
completionBlock:^(BOOL ready) {
|
||||
OWSCAssert(ready);
|
||||
|
||||
DDLogInfo(@"%@ asyncRegisterExtension: %@ -> %d", self.tag, viewName, ready);
|
||||
}];
|
||||
} else {
|
||||
[[TSStorageManager sharedManager].database registerExtension:view withName:viewName];
|
||||
}
|
||||
return [[TSStorageManager sharedManager].database registerExtension:view withName:viewName];
|
||||
}
|
||||
|
||||
+ (void)registerUnreadDatabaseView
|
||||
+ (BOOL)registerUnreadDatabaseView
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
@ -122,13 +66,12 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
return nil;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:NO];
|
||||
return [self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterUnseenDatabaseView
|
||||
+ (BOOL)registerUnseenDatabaseView
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
@ -141,13 +84,12 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
return nil;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:YES];
|
||||
return [self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterThreadSpecialMessagesDatabaseView
|
||||
+ (BOOL)registerThreadSpecialMessagesDatabaseView
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
@ -168,13 +110,12 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
return nil;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSThreadSpecialMessagesDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:YES];
|
||||
return [self registerMessageDatabaseViewWithName:TSThreadSpecialMessagesDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"];
|
||||
}
|
||||
|
||||
+ (void)registerThreadInteractionsDatabaseView
|
||||
+ (BOOL)registerThreadInteractionsDatabaseView
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
@ -184,13 +125,12 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
return interaction.uniqueThreadId;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:NO];
|
||||
return [self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView
|
||||
+ (BOOL)registerThreadOutgoingMessagesDatabaseView
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
@ -200,18 +140,16 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
return nil;
|
||||
}];
|
||||
|
||||
[self registerMessageDatabaseViewWithName:TSThreadOutgoingMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"2"
|
||||
async:YES];
|
||||
return [self registerMessageDatabaseViewWithName:TSThreadOutgoingMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"2"];
|
||||
}
|
||||
|
||||
+ (void)registerThreadDatabaseView
|
||||
{
|
||||
+ (BOOL)registerThreadDatabaseView {
|
||||
YapDatabaseView *threadView =
|
||||
[[TSStorageManager sharedManager].database registeredExtension:TSThreadDatabaseViewExtensionName];
|
||||
if (threadView) {
|
||||
return;
|
||||
return YES;
|
||||
}
|
||||
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping
|
||||
@ -233,15 +171,16 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
YapDatabaseViewSorting *viewSorting = [self threadSorting];
|
||||
|
||||
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
||||
options.isPersistent = YES;
|
||||
options.isPersistent = NO;
|
||||
options.allowedCollections =
|
||||
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
|
||||
|
||||
YapDatabaseView *databaseView =
|
||||
[[YapDatabaseView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options];
|
||||
|
||||
[[TSStorageManager sharedManager].database registerExtension:databaseView
|
||||
withName:TSThreadDatabaseViewExtensionName];
|
||||
return [[TSStorageManager sharedManager]
|
||||
.database registerExtension:databaseView
|
||||
withName:TSThreadDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,57 +305,6 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
}];
|
||||
}
|
||||
|
||||
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
id result = [transaction ext:TSUnseenDatabaseViewExtensionName];
|
||||
|
||||
if (!result) {
|
||||
result = [transaction ext:TSUnreadDatabaseViewExtensionName];
|
||||
OWSAssert(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
id result = [transaction ext:TSThreadOutgoingMessageDatabaseViewExtensionName];
|
||||
OWSAssert(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
|
||||
id result = [transaction ext:TSThreadSpecialMessagesDatabaseViewExtensionName];
|
||||
OWSAssert(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (void)asyncRegistrationCompletion
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
// All async registrations are complete when writes are unblocked.
|
||||
[[TSStorageManager sharedManager].newDatabaseConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
TSDatabaseView.sharedInstance.areAllAsyncRegistrationsComplete = YES;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:kNSNotificationName_DatabaseViewRegistrationComplete
|
||||
object:nil
|
||||
userInfo:nil];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
- (void)storePhoneNumber:(NSString *)phoneNumber
|
||||
{
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:phoneNumber
|
||||
forKey:TSStorageRegisteredNumberKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
@ -61,12 +61,13 @@
|
||||
}
|
||||
|
||||
+ (void)storeServerToken:(NSString *)authToken signalingKey:(NSString *)signalingKey {
|
||||
TSStorageManager *sharedManager = self.sharedManager;
|
||||
[sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:authToken forKey:TSStorageServerAuthToken inCollection:TSStorageUserAccountCollection];
|
||||
[transaction setObject:signalingKey
|
||||
forKey:TSStorageServerSignalingKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
YapDatabaseConnection *dbConn = [[self sharedManager] dbConnection];
|
||||
|
||||
[dbConn readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:authToken forKey:TSStorageServerAuthToken inCollection:TSStorageUserAccountCollection];
|
||||
[transaction setObject:signalingKey
|
||||
forKey:TSStorageServerSignalingKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
@ -27,16 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
+ (BOOL)isDatabasePasswordAccessible;
|
||||
|
||||
/**
|
||||
* The safeBlockingMigrationsBlock block will
|
||||
* run any outstanding version migrations that are a) blocking and b) safe
|
||||
* to be run before the environment and storage is completely configured.
|
||||
*
|
||||
* Specifically, these migration should not depend on or affect the data
|
||||
* of any database view.
|
||||
*/
|
||||
- (void)setupDatabaseWithSafeBlockingMigrations:(void (^_Nonnull)())safeBlockingMigrationsBlock;
|
||||
|
||||
- (void)setupDatabase;
|
||||
- (void)deleteThreadsAndMessages;
|
||||
- (void)resetSignalStorage;
|
||||
|
||||
@ -61,8 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (nullable SignedPreKeyRecord *)signedPreKeyRecordForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)purgeCollection:(NSString *)collection;
|
||||
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -156,8 +156,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
if (!_database) {
|
||||
return NO;
|
||||
}
|
||||
_dbReadConnection = self.newDatabaseConnection;
|
||||
_dbReadWriteConnection = self.newDatabaseConnection;
|
||||
_dbConnection = self.newDatabaseConnection;
|
||||
|
||||
return YES;
|
||||
}
|
||||
@ -192,45 +191,28 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
};
|
||||
}
|
||||
|
||||
- (void)setupDatabaseWithSafeBlockingMigrations:(void (^_Nonnull)())safeBlockingMigrationsBlock
|
||||
- (void)setupDatabase
|
||||
{
|
||||
// Synchronously register extensions which are essential for views.
|
||||
[TSDatabaseView registerThreadDatabaseView];
|
||||
[TSDatabaseView registerThreadInteractionsDatabaseView];
|
||||
[TSDatabaseView registerThreadOutgoingMessagesDatabaseView];
|
||||
[TSDatabaseView registerUnreadDatabaseView];
|
||||
[TSDatabaseView registerUnseenDatabaseView];
|
||||
[TSDatabaseView registerThreadSpecialMessagesDatabaseView];
|
||||
[self.database registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
|
||||
|
||||
// Run the blocking migrations.
|
||||
//
|
||||
// These need to run _before_ the async registered database views or
|
||||
// they will block on them, which (in the upgrade case) can block
|
||||
// return of appDidFinishLaunching... which in term can cause the
|
||||
// app to crash on launch.
|
||||
safeBlockingMigrationsBlock();
|
||||
|
||||
// Asynchronously register other extensions.
|
||||
//
|
||||
// All sync registrations must be done before all async registrations,
|
||||
// or the sync registrations will block on the async registrations.
|
||||
[TSDatabaseView asyncRegisterUnseenDatabaseView];
|
||||
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView];
|
||||
[TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView];
|
||||
|
||||
// Register extensions which aren't essential for rendering threads async
|
||||
[[OWSIncomingMessageFinder new] asyncRegisterExtension];
|
||||
[TSDatabaseView asyncRegisterSecondaryDevicesDatabaseView];
|
||||
[OWSReadReceipt asyncRegisterIndexOnSenderIdAndTimestampWithDatabase:self.database];
|
||||
[OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self];
|
||||
OWSDisappearingMessagesFinder *finder = [[OWSDisappearingMessagesFinder alloc] initWithStorageManager:self];
|
||||
[finder asyncRegisterDatabaseExtensions];
|
||||
OWSFailedMessagesJob *failedMessagesJob = [[OWSFailedMessagesJob alloc] initWithStorageManager:self];
|
||||
[failedMessagesJob asyncRegisterDatabaseExtensions];
|
||||
OWSFailedAttachmentDownloadsJob *failedAttachmentDownloadsMessagesJob =
|
||||
[[OWSFailedAttachmentDownloadsJob alloc] initWithStorageManager:self];
|
||||
[failedAttachmentDownloadsMessagesJob asyncRegisterDatabaseExtensions];
|
||||
|
||||
// NOTE: [TSDatabaseView asyncRegistrationCompletion] ensures that
|
||||
// kNSNotificationName_DatabaseViewRegistrationComplete is not fired until all
|
||||
// of the async registrations are complete.
|
||||
[TSDatabaseView asyncRegistrationCompletion];
|
||||
}
|
||||
|
||||
- (void)protectSignalFiles {
|
||||
@ -389,19 +371,19 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
#pragma mark - convenience methods
|
||||
|
||||
- (void)purgeCollection:(NSString *)collection {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:collection];
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:object forKey:key inCollection:collection];
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:object forKey:key inCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(NSString *)string inCollection:(NSString *)collection {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeObjectForKey:string inCollection:collection];
|
||||
}];
|
||||
}
|
||||
@ -409,8 +391,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (id)objectForKey:(NSString *)key inCollection:(NSString *)collection {
|
||||
__block NSString *object;
|
||||
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
}];
|
||||
|
||||
return object;
|
||||
@ -420,8 +402,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
{
|
||||
__block NSDictionary *object;
|
||||
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
}];
|
||||
|
||||
return object;
|
||||
@ -480,7 +462,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
__block int value = 0;
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
value = [[transaction objectForKey:key inCollection:collection] intValue];
|
||||
value++;
|
||||
[transaction setObject:@(value) forKey:key inCollection:collection];
|
||||
@ -504,11 +486,11 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
}
|
||||
|
||||
- (void)deleteThreadsAndMessages {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[TSThread collection]];
|
||||
[transaction removeAllObjectsInCollection:[SignalRecipient collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSInteraction collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSAttachment collection]];
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[TSThread collection]];
|
||||
[transaction removeAllObjectsInCollection:[SignalRecipient collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSInteraction collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSAttachment collection]];
|
||||
}];
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
}
|
||||
@ -530,8 +512,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (void)resetSignalStorage
|
||||
{
|
||||
self.database = nil;
|
||||
_dbReadConnection = nil;
|
||||
_dbReadWriteConnection = nil;
|
||||
_dbConnection = nil;
|
||||
|
||||
[self deletePasswordFromKeychain];
|
||||
|
||||
|
||||
@ -58,12 +58,10 @@
|
||||
usingBlock:(void (^)(id object, BOOL *stop))block;
|
||||
|
||||
/**
|
||||
* @return Shared database connections for reading and writing.
|
||||
* @return A shared database connection.
|
||||
*/
|
||||
- (YapDatabaseConnection *)dbReadConnection;
|
||||
+ (YapDatabaseConnection *)dbReadConnection;
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
- (YapDatabaseConnection *)dbConnection;
|
||||
+ (YapDatabaseConnection *)dbConnection;
|
||||
|
||||
- (TSStorageManager *)storageManager;
|
||||
+ (TSStorageManager *)storageManager;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Frederic Jacobs on 16/11/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import "TSStorageManager.h"
|
||||
@ -32,7 +31,7 @@
|
||||
|
||||
- (void)save
|
||||
{
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -44,7 +43,7 @@
|
||||
|
||||
- (void)touch
|
||||
{
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self touchWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -56,19 +55,14 @@
|
||||
|
||||
- (void)remove
|
||||
{
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self removeWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
- (YapDatabaseConnection *)dbConnection
|
||||
{
|
||||
return [[self class] dbReadConnection];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return [[self class] dbReadWriteConnection];
|
||||
return [[self class] dbConnection];
|
||||
}
|
||||
|
||||
- (TSStorageManager *)storageManager
|
||||
@ -78,26 +72,9 @@
|
||||
|
||||
#pragma mark Class Methods
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadConnection
|
||||
+ (YapDatabaseConnection *)dbConnection
|
||||
{
|
||||
// We use TSYapDatabaseObject's dbReadWriteConnection (not TSStorageManager's
|
||||
// dbReadConnection) for consistency, since we tend to [TSYapDatabaseObject
|
||||
// save] and want to write to the same connection we read from. To get true
|
||||
// consistency, we'd want to update entities by reading & writing from within
|
||||
// the same transaction, but that'll be a big refactor.
|
||||
|
||||
return self.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
// Use a dedicated connection for model reads & writes.
|
||||
static YapDatabaseConnection *dbReadWriteConnection = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dbReadWriteConnection = [self storageManager].newDatabaseConnection;
|
||||
});
|
||||
return dbReadWriteConnection;
|
||||
return [self storageManager].dbConnection;
|
||||
}
|
||||
|
||||
+ (TSStorageManager *)storageManager
|
||||
@ -113,7 +90,7 @@
|
||||
+ (NSUInteger)numberOfKeysInCollection
|
||||
{
|
||||
__block NSUInteger count;
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
count = [self numberOfKeysInCollectionWithTransaction:transaction];
|
||||
}];
|
||||
return count;
|
||||
@ -135,7 +112,7 @@
|
||||
|
||||
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id object, BOOL *stop))block
|
||||
{
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self enumerateCollectionObjectsWithTransaction:transaction usingBlock:block];
|
||||
}];
|
||||
}
|
||||
@ -154,7 +131,7 @@
|
||||
|
||||
+ (void)removeAllObjectsInCollection
|
||||
{
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[self collection]];
|
||||
}];
|
||||
}
|
||||
@ -167,7 +144,7 @@
|
||||
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
|
||||
{
|
||||
__block id object;
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:uniqueID inCollection:[self collection]];
|
||||
}];
|
||||
return object;
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
//
|
||||
// AppVersion.h
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@ -8,14 +10,6 @@
|
||||
@property (nonatomic, readonly) NSString *lastAppVersion;
|
||||
@property (nonatomic, readonly) NSString *currentAppVersion;
|
||||
|
||||
// Unlike lastAppVersion, this property isn't updated until
|
||||
// appLaunchDidComplete is called.
|
||||
@property (nonatomic, readonly) NSString *lastCompletedLaunchAppVersion;
|
||||
|
||||
+ (instancetype)instance;
|
||||
|
||||
- (void)appLaunchDidComplete;
|
||||
|
||||
- (BOOL)isFirstLaunch;
|
||||
|
||||
@end
|
||||
|
||||
@ -1,19 +1,16 @@
|
||||
//
|
||||
// AppVersion.m
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppVersion.h"
|
||||
|
||||
NSString *const kNSUserDefaults_FirstAppVersion = @"kNSUserDefaults_FirstAppVersion";
|
||||
NSString *const kNSUserDefaults_LastAppVersion = @"kNSUserDefaults_LastVersion";
|
||||
NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefaults_LastCompletedLaunchAppVersion";
|
||||
|
||||
@interface AppVersion ()
|
||||
|
||||
@property (nonatomic) NSString *firstAppVersion;
|
||||
@property (nonatomic) NSString *lastAppVersion;
|
||||
@property (nonatomic) NSString *currentAppVersion;
|
||||
@property (nonatomic) NSString *lastCompletedLaunchAppVersion;
|
||||
|
||||
@end
|
||||
|
||||
@ -34,15 +31,19 @@ NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefault
|
||||
- (void)configure {
|
||||
self.currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
|
||||
NSString *kNSUserDefaults_FirstAppVersion = @"kNSUserDefaults_FirstAppVersion";
|
||||
NSString *kNSUserDefaults_LastAppVersion = @"kNSUserDefaults_LastVersion";
|
||||
|
||||
// The version of the app when it was first launched.
|
||||
// nil if the app has never been launched before.
|
||||
self.firstAppVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_FirstAppVersion];
|
||||
// The version of the app the last time it was launched.
|
||||
// nil if the app has never been launched before.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
self.lastAppVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_LastAppVersion];
|
||||
self.lastCompletedLaunchAppVersion =
|
||||
[[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion];
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// Ensure the value for the "first launched version".
|
||||
if (!self.firstAppVersion) {
|
||||
self.firstAppVersion = self.currentAppVersion;
|
||||
@ -58,24 +59,6 @@ NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefault
|
||||
DDLogInfo(@"firstAppVersion: %@", self.firstAppVersion);
|
||||
DDLogInfo(@"lastAppVersion: %@", self.lastAppVersion);
|
||||
DDLogInfo(@"currentAppVersion: %@", self.currentAppVersion);
|
||||
DDLogInfo(@"lastCompletedLaunchAppVersion: %@", self.lastCompletedLaunchAppVersion);
|
||||
}
|
||||
|
||||
- (void)appLaunchDidComplete
|
||||
{
|
||||
DDLogInfo(@"appLaunchDidComplete");
|
||||
|
||||
self.lastCompletedLaunchAppVersion = self.currentAppVersion;
|
||||
|
||||
// Update the value for the "most recently launch-completed version".
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.currentAppVersion
|
||||
forKey:kNSUserDefaults_LastCompletedLaunchAppVersion];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (BOOL)isFirstLaunch
|
||||
{
|
||||
return self.firstAppVersion != nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -40,11 +40,12 @@
|
||||
|
||||
#define OWSCFail(message, ...) \
|
||||
{ \
|
||||
NSString *formattedMessage = [NSString stringWithFormat:message, ##__VA_ARGS__]; \
|
||||
DDLogError(@"%s %@", __PRETTY_FUNCTION__, formattedMessage); \
|
||||
[DDLog flushLog]; \
|
||||
NSCAssert(0, formattedMessage); \
|
||||
}
|
||||
if (!(X)) { \
|
||||
NSString *formattedMessage = [NSString stringWithFormat:message, ##__VA_ARGS__]; \
|
||||
DDLogError(@"%s %@", __PRETTY_FUNCTION__, formattedMessage); \
|
||||
[DDLog flushLog]; \
|
||||
NSCAssert(0, formattedMessage); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@ -70,17 +71,8 @@
|
||||
//
|
||||
// 1. Use OWSSingletonAssertFlag() outside the class definition.
|
||||
// 2. Use OWSSingletonAssertInit() in each initializer.
|
||||
|
||||
#ifndef SSK_BUILDING_FOR_TESTS
|
||||
#ifdef DEBUG
|
||||
|
||||
#define ENFORCE_SINGLETONS
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENFORCE_SINGLETONS
|
||||
|
||||
#define OWSSingletonAssertFlag() static BOOL _isSingletonCreated = NO;
|
||||
|
||||
#define OWSSingletonAssertInit() \
|
||||
|
||||
@ -18,16 +18,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation Cryptography
|
||||
|
||||
#pragma mark random bytes methods
|
||||
|
||||
#pragma mark random bytes methods
|
||||
+ (NSMutableData *)generateRandomBytes:(NSUInteger)numberBytes {
|
||||
/* used to generate db master key, and to generate signaling key, both at install */
|
||||
NSMutableData *randomBytes = [NSMutableData dataWithLength:numberBytes];
|
||||
int err = SecRandomCopyBytes(kSecRandomDefault, numberBytes, [randomBytes mutableBytes]);
|
||||
int err = 0;
|
||||
err = SecRandomCopyBytes(kSecRandomDefault, numberBytes, [randomBytes mutableBytes]);
|
||||
if (err != noErr) {
|
||||
DDLogError(@"Error in generateRandomBytes: %d", err);
|
||||
@throw
|
||||
[NSException exceptionWithName:@"random problem" reason:@"problem generating random bytes." userInfo:nil];
|
||||
@throw [NSException exceptionWithName:@"random problem" reason:@"problem generating the random " userInfo:nil];
|
||||
}
|
||||
return randomBytes;
|
||||
}
|
||||
@ -153,6 +152,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
DDLogWarn(@"%@ Bad digest on decrypting payload. Their digest: %@, our digest: %@", self.tag, digest, ourDigest);
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
DDLogVerbose(@"%@ %s no digest to verify", self.tag, __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
// decrypt
|
||||
|
||||
@ -420,12 +420,6 @@ NSString *const OWSMimeTypeUnknownForTests = @"unknown/mimetype";
|
||||
|
||||
+ (nullable NSString *)fileExtensionForUTIType:(NSString *)utiType
|
||||
{
|
||||
// Special-case the "aac" filetype we use for voice messages (for legacy reasons)
|
||||
// to use a .m4a file extension, not .aac, since AVAudioPlayer can't handle .aac
|
||||
// properly. Doesn't affect file contents.
|
||||
if ([utiType isEqualToString:@"public.aac-audio"]) {
|
||||
return @"m4a";
|
||||
}
|
||||
CFStringRef fileExtension
|
||||
= UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)utiType, kUTTagClassFilenameExtension);
|
||||
return (__bridge_transfer NSString *)fileExtension;
|
||||
|
||||
@ -30,10 +30,9 @@
|
||||
}
|
||||
|
||||
- (void)testSignedPreKeyDeletion {
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int days = 20;
|
||||
int lastPreKeyId = days;
|
||||
@ -70,10 +69,9 @@
|
||||
|
||||
- (void)testSignedPreKeyDeletionKeepsSomeOldKeys
|
||||
{
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int lastPreKeyId = 10;
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
@ -115,11 +113,10 @@
|
||||
}
|
||||
|
||||
- (void)testOlderRecordsNotDeletedIfNoReplacement {
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int days = 3;
|
||||
int lastPreKeyId = days;
|
||||
|
||||
|
||||
@ -26,7 +26,10 @@
|
||||
{
|
||||
// Sanity Check
|
||||
XCTAssertNotNil(self.localNumber);
|
||||
[[[SignalRecipient alloc] initWithTextSecureIdentifier:self.localNumber relay:nil] save];
|
||||
[[[SignalRecipient alloc] initWithTextSecureIdentifier:self.localNumber
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES] save];
|
||||
XCTAssertNotNil([SignalRecipient recipientWithTextSecureIdentifier:self.localNumber]);
|
||||
|
||||
SignalRecipient *me = [SignalRecipient selfRecipient];
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 11/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "TSContactThread.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
#import "TSStorageManager+identityKeyStore.h"
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@ -19,9 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[OWSUnitTestEnvironment ensureSetup];
|
||||
self.contactThread = [TSContactThread getOrCreateThreadWithContactId:@"fake-contact-id"];
|
||||
[OWSRecipientIdentity removeAllObjectsInCollection];
|
||||
[self.contactThread.storageManager removeIdentityKeyForRecipient:self.contactThread.contactIdentifier];
|
||||
}
|
||||
|
||||
- (void)testHasSafetyNumbersWithoutRemoteIdentity
|
||||
@ -31,8 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testHasSafetyNumbersWithRemoteIdentity
|
||||
{
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:[NSData new]
|
||||
recipientId:self.contactThread.contactIdentifier];
|
||||
[self.contactThread.storageManager saveRemoteIdentity:[NSData new]
|
||||
recipientId:self.contactThread.contactIdentifier];
|
||||
XCTAssert(self.contactThread.hasSafetyNumbers);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
[super setUp];
|
||||
|
||||
// Register views, etc.
|
||||
[[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{}];
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
@ -66,8 +66,7 @@
|
||||
XCTAssertEqual(0, [thread numberOfInteractions]);
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *incomingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
sourceFilename:nil];
|
||||
TSAttachmentStream *incomingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[incomingAttachment writeData:[NSData new] error:&error];
|
||||
[incomingAttachment save];
|
||||
|
||||
@ -84,8 +83,7 @@
|
||||
expiresInSeconds:0];
|
||||
[incomingMessage save];
|
||||
|
||||
TSAttachmentStream *outgoingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
sourceFilename:nil];
|
||||
TSAttachmentStream *outgoingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[outgoingAttachment writeData:[NSData new] error:&error];
|
||||
[outgoingAttachment save];
|
||||
|
||||
@ -96,7 +94,7 @@
|
||||
TSOutgoingMessage *outgoingMessage = [[TSOutgoingMessage alloc] initWithTimestamp:10000
|
||||
inThread:thread
|
||||
messageBody:@"outgoing message body"
|
||||
attachmentIds:[@[ outgoingAttachment.uniqueId ] mutableCopy]];
|
||||
attachmentIds:@[ outgoingAttachment.uniqueId ]];
|
||||
[outgoingMessage save];
|
||||
|
||||
// Sanity check
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -77,7 +75,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testDescriptionWithPhotoAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -91,7 +89,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testDescriptionWithVideoAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4" sourceFilename:nil];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4"];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -102,9 +100,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTAssertEqualObjects(@"📽 ATTACHMENT", actualDescription);
|
||||
}
|
||||
|
||||
|
||||
- (void)testDescriptionWithAudioAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:@"some-file.mp3"];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -115,22 +114,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTAssertEqualObjects(@"📻 ATTACHMENT", actualDescription);
|
||||
}
|
||||
|
||||
- (void)testDescriptionWithVoiceMessageAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:nil];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
inThread:self.thread
|
||||
messageBody:@"My message body"
|
||||
attachmentIds:@[ attachment.uniqueId ]];
|
||||
NSString *actualDescription = [message description];
|
||||
XCTAssertEqualObjects(@"🎤 ATTACHMENT_TYPE_VOICE_MESSAGE", actualDescription);
|
||||
}
|
||||
|
||||
- (void)testDescriptionWithUnkownAudioContentType
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"non/sense" sourceFilename:nil];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"non/sense"];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 10/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "TSContactThread.h"
|
||||
#import "TSOutgoingMessage.h"
|
||||
@ -35,7 +34,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
[message updateWithMessageState:TSOutgoingMessageStateSentToService];
|
||||
message.messageState = TSOutgoingMessageStateSent;
|
||||
XCTAssert(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
- (void)testShouldStartExpireTimerWithDeliveredMessage
|
||||
{
|
||||
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:100
|
||||
inThread:self.thread
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
message.messageState = TSOutgoingMessageStateDelivered;
|
||||
XCTAssert(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
@ -46,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
[message updateWithMessageState:TSOutgoingMessageStateUnsent];
|
||||
message.messageState = TSOutgoingMessageStateUnsent;
|
||||
XCTAssertFalse(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
@ -57,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut];
|
||||
message.messageState = TSOutgoingMessageStateAttemptingOut;
|
||||
XCTAssertFalse(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSDisappearingMessagesFinder.h"
|
||||
@ -13,18 +12,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSDisappearingMessagesFinder (Testing)
|
||||
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (NSArray<TSMessage *> *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessages;
|
||||
- (NSArray<TSMessage *> *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface OWSDisappearingMessageFinderTest : XCTestCase
|
||||
|
||||
@property YapDatabaseConnection *dbConnection;
|
||||
@property OWSDisappearingMessagesFinder *finder;
|
||||
@property TSStorageManager *storageManager;
|
||||
@property OWSDisappearingMessagesFinder *finder;
|
||||
@property TSThread *thread;
|
||||
@property uint64_t now;
|
||||
|
||||
@ -38,14 +35,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[TSMessage removeAllObjectsInCollection];
|
||||
|
||||
self.storageManager = [TSStorageManager sharedManager];
|
||||
self.dbConnection = self.storageManager.newDatabaseConnection;
|
||||
self.thread = [TSThread new];
|
||||
[self.thread save];
|
||||
self.now = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
// Test subject
|
||||
self.finder = [OWSDisappearingMessagesFinder new];
|
||||
[OWSDisappearingMessagesFinder blockingRegisterDatabaseExtensions:self.storageManager];
|
||||
self.finder = [[OWSDisappearingMessagesFinder alloc] initWithStorageManager:self.storageManager];
|
||||
[self.finder blockingRegisterDatabaseExtensions];
|
||||
}
|
||||
|
||||
- (void)testExpiredMessages
|
||||
@ -94,11 +90,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"];
|
||||
[unExpiringMessage2 save];
|
||||
|
||||
__block NSArray<TSMessage *> *actualMessages;
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
actualMessages = [self.finder fetchExpiredMessagesWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
NSArray<TSMessage *> *actualMessages = [self.finder fetchExpiredMessages];
|
||||
NSArray<TSMessage *> *expectedMessages = @[ expiredMessage1, expiredMessage2 ];
|
||||
XCTAssertEqualObjects(expectedMessages, actualMessages);
|
||||
}
|
||||
@ -141,33 +133,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"];
|
||||
[unExpiringMessage2 save];
|
||||
|
||||
__block NSArray<TSMessage *> *actualMessages;
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
actualMessages = [self.finder fetchUnstartedExpiringMessagesInThread:self.thread
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
NSArray<TSMessage *> *actualMessages = [self.finder fetchUnstartedExpiringMessagesInThread:self.thread];
|
||||
NSArray<TSMessage *> *expectedMessages = @[ unreadExpiringMessage ];
|
||||
XCTAssertEqualObjects(expectedMessages, actualMessages);
|
||||
}
|
||||
|
||||
- (NSNumber *)nextExpirationTimestamp
|
||||
{
|
||||
__block NSNumber *nextExpirationTimestamp;
|
||||
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
XCTAssertNotNil(self.finder);
|
||||
nextExpirationTimestamp = [self.finder nextExpirationTimestampWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
return nextExpirationTimestamp;
|
||||
}
|
||||
|
||||
- (void)testNextExpirationTimestampNilWhenNoExpiringMessages
|
||||
{
|
||||
// Sanity check.
|
||||
|
||||
XCTAssertNil(self.nextExpirationTimestamp);
|
||||
XCTAssertNil(self.finder.nextExpirationTimestamp);
|
||||
|
||||
TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1
|
||||
inThread:self.thread
|
||||
@ -176,7 +150,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expiresInSeconds:0
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
XCTAssertNil(self.nextExpirationTimestamp);
|
||||
XCTAssertNil(self.finder.nextExpirationTimestamp);
|
||||
}
|
||||
|
||||
- (void)testNextExpirationTimestampNotNilWithUpcomingExpiringMessages
|
||||
@ -189,8 +163,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:self.now - 9000];
|
||||
[soonToExpireMessage save];
|
||||
|
||||
XCTAssertNotNil(self.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now + 1000, [self.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
XCTAssertNotNil(self.finder.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now + 1000, [self.finder.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
|
||||
// expired message should take precedence
|
||||
TSMessage *expiredMessage = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -201,10 +175,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:self.now - 11000];
|
||||
[expiredMessage save];
|
||||
|
||||
//FIXME remove sleep hack in favor of expiringMessage completion handler
|
||||
// sleep(2);
|
||||
XCTAssertNotNil(self.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now - 1000, [self.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
XCTAssertNotNil(self.finder.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now - 1000, [self.finder.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSDisappearingMessagesConfiguration.h"
|
||||
@ -14,14 +13,6 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSDisappearingMessagesJob (Testing)
|
||||
|
||||
- (void)run;
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
|
||||
@end
|
||||
|
||||
@interface OWSDisappearingMessagesJobTest : XCTestCase
|
||||
|
||||
@end
|
||||
@ -70,15 +61,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
|
||||
|
||||
OWSDisappearingMessagesJob *job = [OWSDisappearingMessagesJob sharedJob];
|
||||
OWSDisappearingMessagesJob *job =
|
||||
[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
|
||||
// Sanity Check.
|
||||
XCTAssertEqual(4, [TSMessage numberOfKeysInCollection]);
|
||||
[job run];
|
||||
|
||||
//FIXME remove sleep hack in favor of expiringMessage completion handler
|
||||
sleep(4);
|
||||
XCTAssertEqual(2, [TSMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
@ -87,8 +75,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
TSThread *thread = [[TSThread alloc] initWithUniqueId:@"fake-thread-id"];
|
||||
[thread save];
|
||||
|
||||
OWSDisappearingMessagesJob *job = [OWSDisappearingMessagesJob sharedJob];
|
||||
|
||||
OWSDisappearingMessagesJob *job =
|
||||
[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
|
||||
OWSDisappearingMessagesConfiguration *configuration =
|
||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
[configuration remove];
|
||||
@ -101,6 +90,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:0];
|
||||
[expiringMessage save];
|
||||
|
||||
|
||||
[job becomeConsistentWithConfigurationForMessage:expiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
configuration = [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
|
||||
@ -114,10 +104,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
TSThread *thread = [[TSThread alloc] initWithUniqueId:@"fake-thread-id"];
|
||||
[thread save];
|
||||
|
||||
OWSDisappearingMessagesJob *job =
|
||||
[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
|
||||
OWSDisappearingMessagesConfiguration *configuration =
|
||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
[configuration remove];
|
||||
|
||||
|
||||
TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1
|
||||
inThread:thread
|
||||
messageBody:@"unexpiringMessage"
|
||||
@ -125,7 +119,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expiresInSeconds:0
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
[OWSDisappearingMessagesJob becomeConsistentWithConfigurationForMessage:unExpiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
[job becomeConsistentWithConfigurationForMessage:unExpiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
XCTAssertNil([OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]);
|
||||
}
|
||||
|
||||
|
||||
@ -94,10 +94,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (self.shouldSucceed) {
|
||||
successHandler();
|
||||
} else {
|
||||
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
[error setIsRetryable:NO];
|
||||
|
||||
failureHandler(error);
|
||||
failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError());
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +130,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSMessageSenderFakeNetworkManager : OWSFakeNetworkManager
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithSuccess:(BOOL)shouldSucceed NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, readonly) BOOL shouldSucceed;
|
||||
@ -144,7 +141,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (instancetype)initWithSuccess:(BOOL)shouldSucceed
|
||||
{
|
||||
self = [self init];
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
@ -243,8 +240,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *messageStartedExpiration = [self expectationWithDescription:@"messageStartedExpiration"];
|
||||
[messageSender sendMessage:self.expiringMessage
|
||||
success:^() {
|
||||
//FIXME remove sleep hack in favor of expiringMessage completion handler
|
||||
sleep(2);
|
||||
if (self.expiringMessage.expiresAt > 0) {
|
||||
[messageStartedExpiration fulfill];
|
||||
} else {
|
||||
@ -321,7 +316,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendMessage:message
|
||||
success:^() {
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -346,10 +341,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendAttachmentData:[NSData new]
|
||||
contentType:@"image/gif"
|
||||
sourceFilename:nil
|
||||
inMessage:message
|
||||
success:^() {
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -400,7 +394,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsUnsent = [self expectationWithDescription:@"markedAsUnsent"];
|
||||
[messageSender sendAttachmentData:[NSData new]
|
||||
contentType:@"image/gif"
|
||||
sourceFilename:nil
|
||||
inMessage:message
|
||||
success:^{
|
||||
XCTFail(@"sendMessage should fail.");
|
||||
@ -429,7 +422,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsUnsent = [self expectationWithDescription:@"markedAsUnsent"];
|
||||
[messageSender sendAttachmentData:[NSData new]
|
||||
contentType:@"image/gif"
|
||||
sourceFilename:nil
|
||||
inMessage:message
|
||||
success:^{
|
||||
XCTFail(@"sendMessage should fail.");
|
||||
@ -452,9 +444,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSData *groupIdData = [Cryptography generateRandomBytes:32];
|
||||
SignalRecipient *successfulRecipient =
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id" relay:nil];
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
SignalRecipient *successfulRecipient2 =
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id2" relay:nil];
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id2"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
|
||||
TSGroupModel *groupModel = [[TSGroupModel alloc]
|
||||
initWithTitle:@"group title"
|
||||
@ -469,7 +467,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendMessage:message
|
||||
success:^{
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -485,7 +483,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testGetRecipients
|
||||
{
|
||||
SignalRecipient *recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id" relay:nil];
|
||||
SignalRecipient *recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
[recipient save];
|
||||
|
||||
OWSMessageSender *messageSender = self.successfulMessageSender;
|
||||
|
||||
@ -17,9 +17,7 @@
|
||||
#import "TSGroupThread.h"
|
||||
#import "TSMessagesManager.h"
|
||||
#import "TSNetworkManager.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -32,7 +30,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
callMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
messageSender:(OWSMessageSender *)messageSender;
|
||||
|
||||
// private method we are testing
|
||||
@ -57,17 +54,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
callMessageHandler:[OWSFakeCallMessageHandler new]
|
||||
contactsManager:[OWSFakeContactsManager new]
|
||||
contactsUpdater:[OWSFakeContactsUpdater new]
|
||||
identityManager:[OWSIdentityManager sharedManager]
|
||||
messageSender:messageSender];
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
[OWSUnitTestEnvironment ensureSetup];
|
||||
}
|
||||
|
||||
- (void)testIncomingSyncContactMessage
|
||||
{
|
||||
XCTestExpectation *messageWasSent = [self expectationWithDescription:@"message was sent"];
|
||||
|
||||
@ -14,19 +14,17 @@
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSOrphanedDataCleanerTest
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Register views, etc.
|
||||
[[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{}];
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
|
||||
// Set up initial conditions & Sanity check
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
[TSAttachmentStream removeAllObjectsInCollection];
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfKeysInCollection]);
|
||||
[TSIncomingMessage removeAllObjectsInCollection];
|
||||
@ -40,11 +38,6 @@
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfItemsInAttachmentsFolder
|
||||
{
|
||||
return [OWSOrphanedDataCleaner filePathsInAttachmentsFolder].count;
|
||||
}
|
||||
|
||||
- (void)testInteractionsWithoutThreadAreDeleted
|
||||
{
|
||||
// This thread is intentionally not saved. It's meant to recreate a situation we've seen where interactions exist
|
||||
@ -60,17 +53,7 @@
|
||||
[incomingMessage save];
|
||||
XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
XCTAssertEqual(0, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
@ -87,51 +70,25 @@
|
||||
[incomingMessage save];
|
||||
XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithoutInteractionsAreDeleted
|
||||
{
|
||||
// sanity check
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[attachmentStream writeData:[NSData new] error:&error];
|
||||
[attachmentStream save];
|
||||
NSString *orphanedFilePath = [attachmentStream filePath];
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
// Do multiple cleanup passes.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
}
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssertFalse(fileExists);
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithInteractionsAreNotDeleted
|
||||
@ -140,7 +97,7 @@
|
||||
[savedThread save];
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[attachmentStream writeData:[NSData new] error:&error];
|
||||
[attachmentStream save];
|
||||
|
||||
@ -156,50 +113,32 @@
|
||||
NSString *attachmentFilePath = [attachmentStream filePath];
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithoutAttachmentStreamsAreDeleted
|
||||
{
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
[attachmentStream writeData:[NSData new] error:&error];
|
||||
// Intentionally not saved, because we want a lingering file.
|
||||
|
||||
|
||||
NSString *orphanedFilePath = [attachmentStream filePath];
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssertFalse(fileExists);
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -27,14 +27,13 @@
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
self.thread = [TSContactThread getOrCreateThreadWithContactId:@"aStupidId" transaction:transaction];
|
||||
|
||||
[self.thread saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
self.thread = [TSContactThread getOrCreateThreadWithContactId:@"aStupidId" transaction:transaction];
|
||||
|
||||
[self.thread saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
TSStorageManager *manager = [TSStorageManager sharedManager];
|
||||
[manager purgeCollection:[TSMessage collection]];
|
||||
}
|
||||
@ -155,8 +154,7 @@
|
||||
NSString *body = @"A child born today will grow up with no conception of privacy at all. They’ll never know what it means to have a private moment to themselves an unrecorded, unanalyzed thought. And that’s a problem because privacy matters; privacy is what allows us to determine who we are and who we want to be.";
|
||||
|
||||
__block TSGroupThread *thread;
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:[[TSGroupModel alloc] initWithTitle:@"fdsfsd"
|
||||
memberIds:[@[] mutableCopy]
|
||||
image:nil
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// TSStorageIdentityKeyStoreTests.m
|
||||
// TextSecureKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 06/11/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
@ -7,8 +11,8 @@
|
||||
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
#import "SecurityUtils.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "OWSRecipientIdentity.h"
|
||||
#import "TSPrivacyPreferences.h"
|
||||
#import "TSStorageManager+IdentityKeyStore.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
|
||||
@ -20,9 +24,8 @@
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
[[TSStorageManager sharedManager] purgeCollection:@"TSStorageManagerTrustedKeysCollection"];
|
||||
[OWSRecipientIdentity removeAllObjectsInCollection];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
@ -34,42 +37,61 @@
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
}
|
||||
|
||||
- (void)testAlreadyRegisteredKey {
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
}
|
||||
|
||||
|
||||
- (void)testChangedKey
|
||||
- (void)testChangedKeyWithBlockingIdentityChanges
|
||||
{
|
||||
NSData *originalKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@protonmail.com";
|
||||
TSPrivacyPreferences *preferences = [TSPrivacyPreferences sharedInstance];
|
||||
preferences.shouldBlockOnIdentityChange = YES;
|
||||
[preferences save];
|
||||
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:originalKey recipientId:recipientId];
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
|
||||
NSData *otherKey = [SecurityUtils generateRandomBytes:32];
|
||||
|
||||
XCTAssertFalse([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
XCTAssertFalse([[TSStorageManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId]);
|
||||
}
|
||||
|
||||
|
||||
- (void)testChangedKeyWithNonBlockingIdentityChanges
|
||||
{
|
||||
TSPrivacyPreferences *preferences = [TSPrivacyPreferences sharedInstance];
|
||||
preferences.shouldBlockOnIdentityChange = NO;
|
||||
[preferences save];
|
||||
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
|
||||
NSData *otherKey = [SecurityUtils generateRandomBytes:32];
|
||||
|
||||
[TextSecureKitEnv setSharedEnv:[OWSUnitTestEnvironment new]];
|
||||
XCTAssertTrue([[TSStorageManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId]);
|
||||
}
|
||||
|
||||
- (void)testIdentityKey {
|
||||
[[OWSIdentityManager sharedManager] generateNewIdentityKey];
|
||||
[[TSStorageManager sharedManager] generateNewIdentityKey];
|
||||
|
||||
XCTAssert([[[OWSIdentityManager sharedManager] identityKeyPair].publicKey length] == 32);
|
||||
XCTAssert([[[TSStorageManager sharedManager] identityKeyPair].publicKey length] == 32);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 10/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSFakeContactsManager.h"
|
||||
|
||||
@ -15,12 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return @"Fake name";
|
||||
}
|
||||
|
||||
- (NSArray<Contact *> *)signalContacts
|
||||
{
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (NSArray<SignalAccount *> *)signalAccounts
|
||||
- (NSArray<Contact *> * _Nonnull)signalContacts
|
||||
{
|
||||
return @[];
|
||||
}
|
||||
|
||||
@ -13,7 +13,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
{
|
||||
NSLog(@"[OWSFakeContactsUpdater] Faking contact lookup.");
|
||||
return [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id"
|
||||
relay:nil];
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -9,7 +9,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSFakeMessageSender : OWSMessageSender
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithExpectation:(XCTestExpectation *)expectation;
|
||||
|
||||
@property (nonatomic, readonly) XCTestExpectation *expectation;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 12/18/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSFakeNotificationsManager.h"
|
||||
|
||||
@ -9,8 +8,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@implementation OWSFakeNotificationsManager
|
||||
|
||||
- (void)notifyUserForIncomingMessage:(TSIncomingMessage *)incomingMessage
|
||||
from:(NSString *)name
|
||||
inThread:(TSThread *)thread
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
NSLog(@"%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Created by Michael Kirk on 12/18/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "TextSecureKitEnv.h"
|
||||
|
||||
@ -8,7 +7,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSUnitTestEnvironment : TextSecureKitEnv
|
||||
|
||||
+ (void)ensureSetup;
|
||||
- (instancetype)initDefault;
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user