Compare commits
73 Commits
charlesmch
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c3b30104a | ||
|
|
1499840de5 | ||
|
|
d98c07ecff | ||
|
|
493aaca242 | ||
|
|
e20d63240b | ||
|
|
faeb7100b9 | ||
|
|
fe0f01daec | ||
|
|
c255504959 | ||
|
|
640ec13b2e | ||
|
|
6fa3fac4ae | ||
|
|
7a50d6b996 | ||
|
|
762f915179 | ||
|
|
96da091e9b | ||
|
|
9115a1f973 | ||
|
|
57b90e1462 | ||
|
|
e0f805f80f | ||
|
|
ab6c1fb3b8 | ||
|
|
9d3175b5cf | ||
|
|
957979585c | ||
|
|
8361ffb818 | ||
|
|
ea681a61e2 | ||
|
|
c1e1247eff | ||
|
|
92276157dc | ||
|
|
2216c2d413 | ||
|
|
a23b4871e0 | ||
|
|
72e893d5f7 | ||
|
|
e24f18320d | ||
|
|
58fb86b8e0 | ||
|
|
065017cafd | ||
|
|
daae31d30e | ||
|
|
8714a8f37c | ||
|
|
deff1fa4e7 | ||
|
|
1fc5f77286 | ||
|
|
fd625dff50 | ||
|
|
89f86c4fd2 | ||
|
|
04ef06ce95 | ||
|
|
f59779c118 | ||
|
|
85fe68d3c4 | ||
|
|
d6c5497f64 | ||
|
|
0b33ef6161 | ||
|
|
acf31db4b3 | ||
|
|
a8ea2428c6 | ||
|
|
605db6b788 | ||
|
|
1d71ca5e50 | ||
|
|
8f9af85cca | ||
|
|
1b9aae2ea6 | ||
|
|
e652dff4b4 | ||
|
|
edf5852e82 | ||
|
|
1fb9fa79df | ||
|
|
13c5bdb8c5 | ||
|
|
2addb9e81d | ||
|
|
c711b4a66d | ||
|
|
b2f9abbc7c | ||
|
|
14c64239a3 | ||
|
|
e9219743ff | ||
|
|
793a7449b0 | ||
|
|
5da7dc1fd3 | ||
|
|
07e0291377 | ||
|
|
e8e7b6bcba | ||
|
|
8fda18a8e3 | ||
|
|
5a2169fa78 | ||
|
|
4c22f371a9 | ||
|
|
6dea4c9fef | ||
|
|
a5660f4db4 | ||
|
|
d927cba5ce | ||
|
|
badaa54327 | ||
|
|
12bfae10ed | ||
|
|
35ee92f38f | ||
|
|
99cd8fc27d | ||
|
|
f653bc36a8 | ||
|
|
48b3f498a9 | ||
|
|
f526a372c9 | ||
|
|
6566ea694c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@ DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
xcshareddata
|
||||
|
||||
Pods/
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
language: objective-c
|
||||
|
||||
osx_image: xcode8
|
||||
osx_image: xcode8.3
|
||||
|
||||
env:
|
||||
-EARLY_START_SIMULATOR=1 # early starting simulator reduces false negatives due to test timeouts
|
||||
|
||||
before_install:
|
||||
- brew update
|
||||
- gem install cocoapods xcpretty --no-ri --no-rdoc
|
||||
- pod repo update --silent
|
||||
- bundle
|
||||
- bundle exec pod repo update --silent
|
||||
|
||||
after_failure:
|
||||
- sleep 10 # This prevents the occasional output truncation that happens when piping to xcpretty.
|
||||
|
||||
script: make
|
||||
script: make scan_test
|
||||
|
||||
|
||||
@ -11,3 +11,19 @@ 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,6 +17,7 @@ PODS:
|
||||
- AFNetworking/NSURLSession
|
||||
- AxolotlKit (0.8.1):
|
||||
- 25519 (~> 2.0.1)
|
||||
- CocoaLumberjack
|
||||
- HKDFKit (~> 0.0.3)
|
||||
- ProtocolBuffers (~> 1.9.8)
|
||||
- CocoaLumberjack (2.4.0):
|
||||
@ -28,12 +29,11 @@ PODS:
|
||||
- CocoaLumberjack/Extensions (2.4.0):
|
||||
- CocoaLumberjack/Default
|
||||
- HKDFKit (0.0.3)
|
||||
- libPhoneNumber-iOS (0.9.4)
|
||||
- libPhoneNumber-iOS (0.9.10)
|
||||
- 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
|
||||
- YapDatabase/SQLCipher (~> 2.9.3)
|
||||
- SocketRocket (0.5.1)
|
||||
- SQLCipher/common (3.4.1)
|
||||
- SQLCipher/fts (3.4.1):
|
||||
@ -53,54 +53,53 @@ PODS:
|
||||
- TwistedOakCollapsingFutures (1.0.0):
|
||||
- UnionFind (~> 1.0)
|
||||
- UnionFind (1.0.1)
|
||||
- YapDatabase/SQLCipher (2.9.2):
|
||||
- YapDatabase/SQLCipher/Core (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Extensions (= 2.9.2)
|
||||
- YapDatabase/SQLCipher/Core (2.9.2):
|
||||
- YapDatabase/SQLCipher (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Extensions (= 2.9.3)
|
||||
- YapDatabase/SQLCipher/Core (2.9.3):
|
||||
- CocoaLumberjack (~> 2)
|
||||
- SQLCipher/fts
|
||||
- YapDatabase/SQLCipher/Extensions (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- 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/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/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/CloudKit (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/ConnectionProxy (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/CrossProcessNotification (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/FilteredViews (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/Hooks (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/Relationships (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/RTreeIndex (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/SearchResults (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/FullTextSearch
|
||||
- YapDatabase/SQLCipher/Extensions/Views
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/SecondaryIndex (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
- YapDatabase/SQLCipher/Extensions/Views (2.9.2):
|
||||
- YapDatabase/SQLCipher/Extensions/Views (2.9.3):
|
||||
- YapDatabase/SQLCipher/Core
|
||||
|
||||
DEPENDENCIES:
|
||||
@ -112,13 +111,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: a3c843cc8a423c5924c663490978f81dba34d04e
|
||||
:commit: 28afe5c1dbcfdea73d147e464c53d191d1e3ea50
|
||||
:git: https://github.com/WhisperSystems/SignalProtocolKit.git
|
||||
SocketRocket:
|
||||
:commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf
|
||||
@ -127,21 +126,20 @@ CHECKOUT OPTIONS:
|
||||
SPEC CHECKSUMS:
|
||||
'25519': dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
|
||||
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
|
||||
AxolotlKit: 240c7d761e4b1be9c6de78ebec498aaeedc978f4
|
||||
AxolotlKit: a9530d6835baae0f204b1f6b9dd79b7901176f0d
|
||||
CocoaLumberjack: aa9dcab71bdf9eaf2a63bbd9ddc87863efe45457
|
||||
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
|
||||
libPhoneNumber-iOS: 63bab980d1fc9783d82d955800ac9d7c1d81fde3
|
||||
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
|
||||
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
|
||||
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
|
||||
SignalServiceKit: 59a79a51b89b963ba94db30cc99ed5212da0bb9f
|
||||
SignalServiceKit: 2ad8d86da055e24ac3ea0354ec1d4b13251af28f
|
||||
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
|
||||
SQLCipher: 43d12c0eb9c57fb438749618fc3ce0065509a559
|
||||
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
|
||||
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
|
||||
YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f
|
||||
YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266
|
||||
|
||||
PODFILE CHECKSUM: 1a7633963dbcaa43f298949d83c42c1cd1dce940
|
||||
PODFILE CHECKSUM: a0f4507b6b4e6f9da3250901b06187a67236e083
|
||||
|
||||
COCOAPODS: 1.2.0
|
||||
COCOAPODS: 1.2.1
|
||||
|
||||
@ -457,7 +457,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
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";
|
||||
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";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
276B029791E679B0E87877B7 /* [CP] Copy Pods Resources */ = {
|
||||
@ -532,7 +532,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
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";
|
||||
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";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1D0826C97B09E58C83B3C228FBC535FA"
|
||||
BlueprintIdentifier = "FF3F51F81980908EDE1836B76AA3A1EC"
|
||||
BuildableName = "libSignalServiceKit.a"
|
||||
BlueprintName = "SignalServiceKit"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
|
||||
5
Gemfile
Normal file
5
Gemfile
Normal file
@ -0,0 +1,5 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'fastlane'
|
||||
gem 'cocoapods'
|
||||
|
||||
189
Gemfile.lock
Normal file
189
Gemfile.lock
Normal file
@ -0,0 +1,189 @@
|
||||
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,9 +14,11 @@ default: test
|
||||
|
||||
test: pod_install retest
|
||||
|
||||
scan_test: pod_install scan
|
||||
|
||||
pod_install:
|
||||
cd $(WORKING_DIR) && \
|
||||
pod install
|
||||
bundle exec pod install
|
||||
|
||||
build: pod_install
|
||||
cd $(WORKING_DIR) && \
|
||||
@ -28,6 +30,9 @@ 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,3 +1,27 @@
|
||||
# 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,15 +17,37 @@ An Objective-C library for communicating with the Signal messaging service.
|
||||
|
||||
s.homepage = "https://github.com/WhisperSystems/SignalServiceKit"
|
||||
s.license = 'GPLv3'
|
||||
s.author = { "Frederic Jacobs" => "github@fredericjacobs.com" }
|
||||
s.author = { "Whisper Systems" => "ios@whispersystems.com" }
|
||||
s.source = { :git => "https://github.com/WhisperSystems/SignalServiceKit.git", :tag => s.version.to_s }
|
||||
s.social_media_url = 'https://twitter.com/FredericJacobs'
|
||||
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.platform = :ios, '8.0'
|
||||
#s.ios.deployment_target = '8.0'
|
||||
#s.osx.deployment_target = '10.9'
|
||||
s.requires_arc = true
|
||||
s.source_files = 'src/**/*.{h,m,mm}'
|
||||
|
||||
# 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.resources = ['src/Security/PinningCertificate/textsecure.cer',
|
||||
'src/Security/PinningCertificate/GIAG2.crt']
|
||||
|
||||
1
fastlane/.gitignore
vendored
Normal file
1
fastlane/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test_output
|
||||
8
fastlane/Scanfile
Normal file
8
fastlane/Scanfile
Normal file
@ -0,0 +1,8 @@
|
||||
# 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,6 +34,24 @@ 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 {
|
||||
@ -124,25 +142,13 @@ message SyncMessage {
|
||||
optional uint64 timestamp = 2;
|
||||
}
|
||||
|
||||
message Verified {
|
||||
enum State {
|
||||
DEFAULT = 0;
|
||||
VERIFIED = 1;
|
||||
UNVERIFIED = 2;
|
||||
}
|
||||
|
||||
optional string destination = 1;
|
||||
optional bytes identityKey = 2;
|
||||
optional State state = 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 Verified verified = 7;
|
||||
optional Verified verified = 7;
|
||||
optional bytes padding = 8;
|
||||
}
|
||||
|
||||
@ -186,6 +192,7 @@ message ContactDetails {
|
||||
optional string name = 2;
|
||||
optional Avatar avatar = 3;
|
||||
optional string color = 4;
|
||||
optional Verified verified = 5;
|
||||
}
|
||||
|
||||
message GroupDetails {
|
||||
|
||||
@ -244,13 +244,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (NSArray<NSString *> *)textSecureIdentifiers {
|
||||
__block NSMutableArray *identifiers = [NSMutableArray array];
|
||||
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
if ([SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction]) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
[[TSStorageManager sharedManager].dbReadConnection 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]
|
||||
.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
||||
[recipientIds addObjectsFromArray:allRecipientKeys];
|
||||
}];
|
||||
[[TSStorageManager sharedManager].dbReadConnection
|
||||
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].dbConnection
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in recipientIds) {
|
||||
SignalRecipient *recipient =
|
||||
@ -185,23 +185,22 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
// Insert or update contact attributes
|
||||
[[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];
|
||||
}
|
||||
[[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];
|
||||
}
|
||||
|
||||
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,7 +22,6 @@ 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,6 +85,9 @@
|
||||
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.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
recipient = [self recipientWithTextSecureIdentifier:textSecureIdentifier withTransaction:transaction];
|
||||
}];
|
||||
return recipient;
|
||||
|
||||
@ -131,7 +131,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)enumerateInteractionsUsingBlock:(void (^)(TSInteraction *interaction))block
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection 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 dbConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
count = [interactionsByThread numberOfItemsInGroup:self.uniqueId];
|
||||
}];
|
||||
@ -237,7 +237,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (TSInteraction *) lastInteraction {
|
||||
__block TSInteraction *last;
|
||||
[TSStorageManager.sharedManager.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
||||
[TSStorageManager.sharedManager.dbReadConnection 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.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[TSStorageManager.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[transaction ext:TSMessageDatabaseViewExtensionName]
|
||||
enumerateRowsInGroup:self.uniqueId
|
||||
withOptions:NSEnumerationReverse
|
||||
@ -397,7 +397,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection 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 dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] 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 dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [self getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
}];
|
||||
return thread;
|
||||
|
||||
@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBlockedBuilder *blockedPhoneNumbersBuilder =
|
||||
[OWSSignalServiceProtosSyncMessageBlockedBuilder new];
|
||||
@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setBlocked:[blockedPhoneNumbersBuilder build]];
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
return syncMessageBuilder;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -7,10 +7,12 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAccount;
|
||||
@class OWSRecipientIdentity;
|
||||
|
||||
@interface OWSContactsOutputStream : OWSChunkedOutputStream
|
||||
|
||||
- (void)writeSignalAccount:(SignalAccount *)signalAccount;
|
||||
- (void)writeSignalAccount:(SignalAccount *)signalAccount
|
||||
recipientIdentity:(nullable OWSRecipientIdentity *)recipientIdentity;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#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>
|
||||
@ -14,14 +16,23 @@ 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,4 +1,6 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSReadReceipt.h"
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
@ -104,7 +106,7 @@ NSString *const OWSReadReceiptColumnSenderId = @"senderId";
|
||||
stringWithFormat:@"WHERE %@ = ? AND %@ = ?", OWSReadReceiptColumnSenderId, OWSReadReceiptColumnTimestamp];
|
||||
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:queryFormat, senderId, @(timestamp)];
|
||||
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[[transaction ext:OWSReadReceiptIndexOnSenderIdAndTimestamp]
|
||||
enumerateKeysAndObjectsMatchingQuery:query
|
||||
usingBlock:^(NSString *collection, NSString *key, id object, BOOL *stop) {
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSReadReceiptsMessage.h"
|
||||
#import "OWSReadReceipt.h"
|
||||
@ -26,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
for (OWSReadReceipt *readReceipt in self.readReceipts) {
|
||||
@ -37,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[syncMessageBuilder addRead:[readProtoBuilder build]];
|
||||
}
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
return syncMessageBuilder;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -94,7 +94,8 @@ NSString *const OWSReadReceiptsProcessorMarkedMessageAsReadNotification =
|
||||
// Always mark the message specified by the read receipt as read.
|
||||
[interactionsToMarkAsRead addObject:message];
|
||||
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[TSDatabaseView unseenDatabaseViewExtension:transaction]
|
||||
enumerateRowsInGroup:message.uniqueThreadId
|
||||
usingBlock:^(NSString *collection,
|
||||
|
||||
@ -9,12 +9,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSVerificationStateSyncMessage : OWSOutgoingSyncMessage
|
||||
|
||||
- (void)addVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId;
|
||||
- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
verificationForRecipientId:(NSString *)recipientId;
|
||||
|
||||
// Returns the list of recipient ids referenced in this message.
|
||||
- (NSArray<NSString *> *)recipientIds;
|
||||
// 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;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -9,25 +9,12 @@
|
||||
|
||||
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) NSMutableArray<OWSVerificationStateTuple *> *tuples;
|
||||
@property (nonatomic, readonly) OWSVerificationState verificationState;
|
||||
@property (nonatomic, readonly) NSData *identityKey;
|
||||
|
||||
@end
|
||||
|
||||
@ -35,72 +22,78 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OWSVerificationStateSyncMessage
|
||||
|
||||
- (instancetype)init
|
||||
- (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
verificationForRecipientId:(NSString *)verificationForRecipientId
|
||||
{
|
||||
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;
|
||||
|
||||
_tuples = [NSMutableArray new];
|
||||
|
||||
// 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;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addVerificationState:(OWSVerificationState)verificationState
|
||||
identityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSAssert(identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
OWSAssert(self.tuples);
|
||||
OWSAssert(self.identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(self.verificationForRecipientId.length > 0);
|
||||
|
||||
OWSVerificationStateTuple *tuple = [OWSVerificationStateTuple new];
|
||||
tuple.verificationState = verificationState;
|
||||
tuple.identityKey = identityKey;
|
||||
tuple.recipientId = recipientId;
|
||||
[self.tuples addObject:tuple];
|
||||
}
|
||||
// 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);
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
{
|
||||
OWSAssert(self.tuples.count > 0);
|
||||
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
for (OWSVerificationStateTuple *tuple in self.tuples) {
|
||||
OWSSignalServiceProtosSyncMessageVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosSyncMessageVerifiedBuilder new];
|
||||
verifiedBuilder.destination = tuple.recipientId;
|
||||
verifiedBuilder.identityKey = tuple.identityKey;
|
||||
switch (tuple.verificationState) {
|
||||
case OWSVerificationStateDefault:
|
||||
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateDefault;
|
||||
break;
|
||||
case OWSVerificationStateVerified:
|
||||
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateVerified;
|
||||
break;
|
||||
case OWSVerificationStateNoLongerVerified:
|
||||
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateUnverified;
|
||||
break;
|
||||
}
|
||||
[syncMessageBuilder addVerified:[verifiedBuilder build]];
|
||||
}
|
||||
|
||||
// Add 1-512 bytes of random padding bytes.
|
||||
size_t paddingLengthBytes = arc4random_uniform(512) + 1;
|
||||
[syncMessageBuilder setPadding:[Cryptography generateRandomBytes:paddingLengthBytes]];
|
||||
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
|
||||
verifiedBuilder.destination = self.verificationForRecipientId;
|
||||
verifiedBuilder.identityKey = self.identityKey;
|
||||
verifiedBuilder.state = OWSVerificationStateToProtoState(self.verificationState);
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
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;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)recipientIds
|
||||
- (size_t)unpaddedVerifiedLength
|
||||
{
|
||||
NSMutableArray<NSString *> *result = [NSMutableArray new];
|
||||
for (OWSVerificationStateTuple *tuple in self.tuples) {
|
||||
OWSAssert(tuple.recipientId.length > 0);
|
||||
[result addObject:tuple.recipientId];
|
||||
}
|
||||
OWSAssert(self.identityKey.length == kIdentityKeyLength);
|
||||
OWSAssert(self.verificationForRecipientId.length > 0);
|
||||
|
||||
return [result copy];
|
||||
// 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);
|
||||
|
||||
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
|
||||
verifiedBuilder.destination = self.verificationForRecipientId;
|
||||
verifiedBuilder.identityKey = self.identityKey;
|
||||
verifiedBuilder.state = OWSVerificationStateToProtoState(self.verificationState);
|
||||
|
||||
return [verifiedBuilder build].data.length;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -27,6 +27,8 @@ 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
|
||||
@ -44,7 +46,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (void)deleteAttachments;
|
||||
+ (NSString *)attachmentsFolder;
|
||||
+ (NSUInteger)numberOfItemsInAttachmentsFolder;
|
||||
|
||||
- (CGSize)imageSizeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (CGSize)imageSizeWithoutTransaction;
|
||||
|
||||
@ -41,6 +41,7 @@ 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];
|
||||
|
||||
@ -62,6 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// attachments which don't need to be uploaded.
|
||||
_isUploaded = YES;
|
||||
self.attachmentType = pointer.attachmentType;
|
||||
_creationTimestamp = [NSDate new];
|
||||
|
||||
[self ensureFilePath];
|
||||
|
||||
@ -75,8 +77,14 @@ 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];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -181,19 +189,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return attachmentsFolder;
|
||||
}
|
||||
|
||||
+ (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
|
||||
{
|
||||
if (!self.localRelativeFilePath) {
|
||||
@ -286,10 +281,28 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (void)deleteAttachments
|
||||
{
|
||||
NSError *error;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self attachmentsFolder] error:&error];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:self.attachmentsFolder];
|
||||
NSArray<NSURL *> *contents =
|
||||
[fileManager contentsOfDirectoryAtURL:fileURL includingPropertiesForKeys:nil options:0 error:&error];
|
||||
|
||||
if (error) {
|
||||
DDLogError(@"Failed to delete attachment folder with error: %@", error.debugDescription);
|
||||
OWSFail(@"failed to get contents of attachments folder: %@ with error: %@", self.attachmentsFolder, error);
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
@ -361,7 +374,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (transaction) {
|
||||
updateDataStore(transaction);
|
||||
} else {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
updateDataStore(transaction);
|
||||
}];
|
||||
}
|
||||
@ -432,7 +445,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (transaction) {
|
||||
updateDataStore(transaction);
|
||||
} else {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
updateDataStore(transaction);
|
||||
}];
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSOutgoingSentMessageTranscript.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
@ -37,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
|
||||
@ -49,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
[syncMessageBuilder setSentBuilder:sentBuilder];
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
return syncMessageBuilder;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#import "OWSOutgoingSyncMessage.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "Cryptography.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -21,13 +22,22 @@ 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
|
||||
{
|
||||
NSAssert(NO, @"buildSyncMessage must be overridden in subclass");
|
||||
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];
|
||||
}
|
||||
|
||||
// e.g.
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
return [syncMessageBuilder build];
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
OWSFail(@"Abstract method should be overridden in subclass.");
|
||||
return [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextData
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSOutgoingSyncMessage.h"
|
||||
|
||||
@ -6,10 +8,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
@protocol ContactsManagerProtocol;
|
||||
@class OWSIdentityManager;
|
||||
|
||||
@interface OWSSyncContactsMessage : OWSOutgoingSyncMessage
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
identityManager:(OWSIdentityManager *)identityManager;
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData;
|
||||
|
||||
@end
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSContactsOutputStream.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "SignalAccount.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -17,12 +18,14 @@ 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) {
|
||||
@ -30,11 +33,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
_contactsManager = contactsManager;
|
||||
_identityManager = identityManager;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
if (self.attachmentIds.count != 1) {
|
||||
DDLogError(@"expected sync contact message to have exactly one attachment, but found %lu",
|
||||
@ -53,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setContactsBuilder:contactsBuilder];
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
return syncMessageBuilder;
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData
|
||||
@ -66,7 +70,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSContactsOutputStream *contactsOutputStream = [OWSContactsOutputStream streamWithOutputStream:dataOutputStream];
|
||||
|
||||
for (SignalAccount *signalAccount in self.contactsManager.signalAccounts) {
|
||||
[contactsOutputStream writeSignalAccount:signalAccount];
|
||||
OWSRecipientIdentity *recipientIdentity = [self.identityManager recipientIdentityForRecipientId:signalAccount.recipientId];
|
||||
|
||||
[contactsOutputStream writeSignalAccount:signalAccount recipientIdentity:recipientIdentity];
|
||||
}
|
||||
|
||||
[contactsOutputStream flush];
|
||||
|
||||
@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return [super initWithTimestamp:[NSDate ows_millisecondTimeStamp]];
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)syncMessageBuilder
|
||||
{
|
||||
|
||||
if (self.attachmentIds.count != 1) {
|
||||
@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
|
||||
[syncMessageBuilder setGroupsBuilder:groupsBuilder];
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
return syncMessageBuilder;
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData
|
||||
|
||||
@ -78,7 +78,7 @@ NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingM
|
||||
+ (nullable instancetype)findMessageWithAuthorId:(NSString *)authorId timestamp:(uint64_t)timestamp
|
||||
{
|
||||
__block TSIncomingMessage *foundMessage;
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection 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
|
||||
|
||||
@ -245,7 +245,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
{
|
||||
OWSAssert(error);
|
||||
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:TSOutgoingMessageStateUnsent];
|
||||
@ -256,7 +256,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithMessageState:(TSOutgoingMessageState)messageState
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithMessageState:messageState transaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -274,7 +274,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setHasSyncedTranscript:hasSyncedTranscript];
|
||||
@ -295,7 +295,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithCustomMessage:(NSString *)customMessage
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithCustomMessage:customMessage transaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -312,14 +312,14 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithWasDelivered
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithWasDeliveredWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateWithWasSentAndDelivered
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self applyChangeToSelfAndLatestOutgoingMessage:transaction
|
||||
changeBlock:^(TSOutgoingMessage *message) {
|
||||
[message setMessageState:TSOutgoingMessageStateSentToService];
|
||||
@ -397,7 +397,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
|
||||
- (void)updateWithSentRecipient:(NSString *)contactId
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self updateWithSentRecipient:contactId transaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -455,8 +455,6 @@ 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];
|
||||
|
||||
@ -17,7 +17,7 @@ extern NSString *const kNSNotificationName_IdentityStateDidChange;
|
||||
extern const NSUInteger kIdentityKeyLength;
|
||||
|
||||
@class OWSRecipientIdentity;
|
||||
@class OWSSignalServiceProtosSyncMessageVerified;
|
||||
@class OWSSignalServiceProtosVerified;
|
||||
|
||||
// This class can be safely accessed and used from any thread.
|
||||
@interface OWSIdentityManager : NSObject <IdentityKeyStore>
|
||||
@ -46,10 +46,7 @@ extern const NSUInteger kIdentityKeyLength;
|
||||
*/
|
||||
- (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId;
|
||||
|
||||
// Will try to send a sync message with all verification states.
|
||||
- (void)syncAllVerificationStates;
|
||||
|
||||
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerified *> *)verifieds;
|
||||
- (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
#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"
|
||||
@ -14,6 +16,7 @@
|
||||
#import "TSErrorMessage.h"
|
||||
#import "TSGroupThread.h"
|
||||
#import "TSStorageManager+keyingMaterial.h"
|
||||
#import "TSStorageManager+sessionStore.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
#import <25519/Curve25519.h>
|
||||
@ -90,12 +93,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
// 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];
|
||||
});
|
||||
[self observeNotifications];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -196,6 +195,10 @@ 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];
|
||||
|
||||
@ -204,7 +207,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
return YES;
|
||||
}
|
||||
|
||||
DDLogDebug(@"%@ no changes for identity saved for recipient: %@", self.tag, recipientId);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@ -362,7 +364,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
@synchronized(self)
|
||||
{
|
||||
if (recipientIdentity == nil) {
|
||||
DDLogDebug(@"%@ Trusting previously unknown recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -373,7 +374,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
}
|
||||
|
||||
if ([recipientIdentity isFirstKnownKey]) {
|
||||
DDLogDebug(@"%@ trusting first known key for recipient: %@", self.tag, recipientIdentity.recipientId);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -385,12 +385,10 @@ 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);
|
||||
@ -417,7 +415,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
[messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]];
|
||||
}
|
||||
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
@ -436,17 +434,29 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
}
|
||||
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[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.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction enumerateKeysAndObjectsInCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages
|
||||
usingBlock:^(NSString *_Nonnull recipientId,
|
||||
id _Nonnull object,
|
||||
@ -455,7 +465,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
}];
|
||||
}];
|
||||
|
||||
OWSVerificationStateSyncMessage *message = [OWSVerificationStateSyncMessage new];
|
||||
NSMutableArray<OWSVerificationStateSyncMessage *> *messages = [NSMutableArray new];
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
|
||||
if (!recipientIdentity) {
|
||||
@ -483,53 +493,17 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
recipientId);
|
||||
continue;
|
||||
}
|
||||
[message addVerificationState:recipientIdentity.verificationState
|
||||
identityKey:identityKey
|
||||
recipientId:recipientId];
|
||||
OWSVerificationStateSyncMessage *message = [[OWSVerificationStateSyncMessage alloc]
|
||||
initWithVerificationState:recipientIdentity.verificationState
|
||||
identityKey:identityKey
|
||||
verificationForRecipientId:recipientIdentity.recipientId];
|
||||
[messages addObject:message];
|
||||
}
|
||||
if (message.recipientIds.count > 0) {
|
||||
if (messages.count > 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[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 == kStoredIdentityKeyLength);
|
||||
|
||||
if (recipientIdentity.recipientId.length < 1) {
|
||||
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientIdentity.recipientId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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: %@",
|
||||
recipientIdentity.recipientId,
|
||||
identityKey);
|
||||
return;
|
||||
}
|
||||
|
||||
[message addVerificationState:recipientIdentity.verificationState
|
||||
identityKey:identityKey
|
||||
recipientId:recipientIdentity.recipientId];
|
||||
}];
|
||||
if (message.recipientIds.count > 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self sendSyncVerificationStateMessage:message];
|
||||
for (OWSVerificationStateSyncMessage *message in messages) {
|
||||
[self sendSyncVerificationStateMessage:message];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -539,18 +513,41 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
- (void)sendSyncVerificationStateMessage:(OWSVerificationStateSyncMessage *)message
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(message.recipientIds.count > 0);
|
||||
OWSAssert(message.verificationForRecipientId.length > 0);
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self.messageSender sendMessage:message
|
||||
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
|
||||
success:^{
|
||||
DDLogInfo(@"%@ Successfully sent verification state sync message", self.tag);
|
||||
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);
|
||||
|
||||
// Record that this verification state was successfully synced.
|
||||
[self clearSyncMessageForRecipientIds:message.recipientIds];
|
||||
// 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);
|
||||
}];
|
||||
});
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
DDLogError(@"%@ Failed to send verification state sync message with error: %@", self.tag, error);
|
||||
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];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@ -558,65 +555,52 @@ 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)
|
||||
{
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
[self.storageManager removeObjectForKey:recipientId
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
}
|
||||
[self.storageManager removeObjectForKey:recipientId
|
||||
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerified *> *)verifieds
|
||||
- (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified
|
||||
{
|
||||
for (OWSSignalServiceProtosSyncMessageVerified *verified in verifieds) {
|
||||
NSString *recipientId = verified.destination;
|
||||
if (recipientId.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing recipientId.");
|
||||
continue;
|
||||
}
|
||||
NSData *rawIdentityKey = verified.identityKey;
|
||||
if (rawIdentityKey.length != kIdentityKeyLength) {
|
||||
OWSFail(@"Verification state sync message for recipient: %@ with malformed identityKey: %@",
|
||||
recipientId,
|
||||
rawIdentityKey);
|
||||
continue;
|
||||
}
|
||||
NSData *identityKey = [rawIdentityKey removeKeyType];
|
||||
|
||||
switch (verified.state) {
|
||||
case OWSSignalServiceProtosSyncMessageVerifiedStateDefault:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:NO];
|
||||
break;
|
||||
case OWSSignalServiceProtosSyncMessageVerifiedStateVerified:
|
||||
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified
|
||||
recipientId:recipientId
|
||||
identityKey:identityKey
|
||||
overwriteOnConflict:YES];
|
||||
break;
|
||||
case OWSSignalServiceProtosSyncMessageVerifiedStateUnverified:
|
||||
OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.",
|
||||
recipientId,
|
||||
OWSVerificationStateToString(OWSVerificationStateNoLongerVerified));
|
||||
continue;
|
||||
}
|
||||
NSString *recipientId = verified.destination;
|
||||
if (recipientId.length < 1) {
|
||||
OWSFail(@"Verification state sync message missing recipientId.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (verifieds.count > 0) {
|
||||
[self fireIdentityStateChangeNotification];
|
||||
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
|
||||
@ -758,7 +742,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
isLocalChange:isLocalChange]];
|
||||
}
|
||||
|
||||
[self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.storageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
@ -771,7 +755,11 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self tryToSyncQueuedVerificationStates];
|
||||
// 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];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
@ -192,7 +192,6 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
|
||||
|
||||
[message updateWithMessageState:TSOutgoingMessageStateSentToService];
|
||||
|
||||
DDLogDebug(@"%@ succeeded.", strongSelf.tag);
|
||||
aSuccessHandler();
|
||||
|
||||
[strongSelf markAsComplete];
|
||||
@ -281,12 +280,10 @@ 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.", self.tag);
|
||||
DDLogInfo(@"%@ Sending failed. Remaining retries: %lu", self.tag, (unsigned long)remainingRetries);
|
||||
|
||||
OWSAssert(!onceFlag);
|
||||
onceFlag = YES;
|
||||
@ -450,8 +447,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
success:(void (^)())successHandler
|
||||
failure:(RetryableFailureHandler)failureHandler
|
||||
{
|
||||
DDLogDebug(@"%@ sending message: %@", self.tag, message.debugDescription);
|
||||
|
||||
[self ensureAnyAttachmentsUploaded:message
|
||||
success:^() {
|
||||
[self deliverMessage:message
|
||||
@ -472,7 +467,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
failure:(RetryableFailureHandler)failureHandler
|
||||
{
|
||||
if (!message.hasAttachments) {
|
||||
DDLogDebug(@"%@ No attachments for message: %@", self.tag, message);
|
||||
return successHandler();
|
||||
}
|
||||
|
||||
@ -1167,7 +1161,9 @@ 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 {
|
||||
|
||||
19
src/Messages/OWSOutgoingNullMessage.h
Normal file
19
src/Messages/OWSOutgoingNullMessage.h
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// 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
|
||||
76
src/Messages/OWSOutgoingNullMessage.m
Normal file
76
src/Messages/OWSOutgoingNullMessage.m
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// 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
|
||||
@ -36,6 +36,8 @@
|
||||
@class OWSSignalServiceProtosGroupDetailsAvatar;
|
||||
@class OWSSignalServiceProtosGroupDetailsAvatarBuilder;
|
||||
@class OWSSignalServiceProtosGroupDetailsBuilder;
|
||||
@class OWSSignalServiceProtosNullMessage;
|
||||
@class OWSSignalServiceProtosNullMessageBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessage;
|
||||
@class OWSSignalServiceProtosSyncMessageBlocked;
|
||||
@class OWSSignalServiceProtosSyncMessageBlockedBuilder;
|
||||
@ -50,8 +52,8 @@
|
||||
@class OWSSignalServiceProtosSyncMessageRequestBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessageSent;
|
||||
@class OWSSignalServiceProtosSyncMessageSentBuilder;
|
||||
@class OWSSignalServiceProtosSyncMessageVerified;
|
||||
@class OWSSignalServiceProtosSyncMessageVerifiedBuilder;
|
||||
@class OWSSignalServiceProtosVerified;
|
||||
@class OWSSignalServiceProtosVerifiedBuilder;
|
||||
@class ObjectiveCFileOptions;
|
||||
@class ObjectiveCFileOptionsBuilder;
|
||||
@class PBDescriptorProto;
|
||||
@ -109,6 +111,15 @@ 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,
|
||||
@ -127,15 +138,6 @@ typedef NS_ENUM(SInt32, OWSSignalServiceProtosSyncMessageRequestType) {
|
||||
BOOL OWSSignalServiceProtosSyncMessageRequestTypeIsValidValue(OWSSignalServiceProtosSyncMessageRequestType value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosSyncMessageRequestType(OWSSignalServiceProtosSyncMessageRequestType value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosSyncMessageVerifiedState) {
|
||||
OWSSignalServiceProtosSyncMessageVerifiedStateDefault = 0,
|
||||
OWSSignalServiceProtosSyncMessageVerifiedStateVerified = 1,
|
||||
OWSSignalServiceProtosSyncMessageVerifiedStateUnverified = 2,
|
||||
};
|
||||
|
||||
BOOL OWSSignalServiceProtosSyncMessageVerifiedStateIsValidValue(OWSSignalServiceProtosSyncMessageVerifiedState value);
|
||||
NSString *NSStringFromOWSSignalServiceProtosSyncMessageVerifiedState(OWSSignalServiceProtosSyncMessageVerifiedState value);
|
||||
|
||||
typedef NS_ENUM(SInt32, OWSSignalServiceProtosAttachmentPointerFlags) {
|
||||
OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage = 1,
|
||||
};
|
||||
@ -274,21 +276,26 @@ 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;
|
||||
@ -345,6 +352,143 @@ 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"
|
||||
@ -852,21 +996,23 @@ 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 * verifiedArray;
|
||||
}
|
||||
- (BOOL) hasSent;
|
||||
- (BOOL) hasContacts;
|
||||
- (BOOL) hasGroups;
|
||||
- (BOOL) hasRequest;
|
||||
- (BOOL) hasBlocked;
|
||||
- (BOOL) hasVerified;
|
||||
- (BOOL) hasPadding;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageSent* sent;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageContacts* contacts;
|
||||
@ -874,10 +1020,9 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageRequest* request;
|
||||
@property (readonly, strong) NSArray<OWSSignalServiceProtosSyncMessageRead*> * read;
|
||||
@property (readonly, strong) OWSSignalServiceProtosSyncMessageBlocked* blocked;
|
||||
@property (readonly, strong) NSArray<OWSSignalServiceProtosSyncMessageVerified*> * verified;
|
||||
@property (readonly, strong) OWSSignalServiceProtosVerified* verified;
|
||||
@property (readonly, strong) NSData* padding;
|
||||
- (OWSSignalServiceProtosSyncMessageRead*)readAtIndex:(NSUInteger)index;
|
||||
- (OWSSignalServiceProtosSyncMessageVerified*)verifiedAtIndex:(NSUInteger)index;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
@ -1253,76 +1398,6 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (OWSSignalServiceProtosSyncMessageReadBuilder*) clearTimestamp;
|
||||
@end
|
||||
|
||||
#define Verified_destination @"destination"
|
||||
#define Verified_identityKey @"identityKey"
|
||||
#define Verified_state @"state"
|
||||
@interface OWSSignalServiceProtosSyncMessageVerified : PBGeneratedMessage<GeneratedMessageProtocol> {
|
||||
@private
|
||||
BOOL hasDestination_:1;
|
||||
BOOL hasIdentityKey_:1;
|
||||
BOOL hasState_:1;
|
||||
NSString* destination;
|
||||
NSData* identityKey;
|
||||
OWSSignalServiceProtosSyncMessageVerifiedState state;
|
||||
}
|
||||
- (BOOL) hasDestination;
|
||||
- (BOOL) hasIdentityKey;
|
||||
- (BOOL) hasState;
|
||||
@property (readonly, strong) NSString* destination;
|
||||
@property (readonly, strong) NSData* identityKey;
|
||||
@property (readonly) OWSSignalServiceProtosSyncMessageVerifiedState state;
|
||||
|
||||
+ (instancetype) defaultInstance;
|
||||
- (instancetype) defaultInstance;
|
||||
|
||||
- (BOOL) isInitialized;
|
||||
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) builder;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) builderWithPrototype:(OWSSignalServiceProtosSyncMessageVerified*) prototype;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) toBuilder;
|
||||
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromData:(NSData*) data;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromInputStream:(NSInputStream*) input;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
+ (OWSSignalServiceProtosSyncMessageVerified*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosSyncMessageVerifiedBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosSyncMessageVerified* resultVerified;
|
||||
}
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerified*) defaultInstance;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) clear;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) clone;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerified*) build;
|
||||
- (OWSSignalServiceProtosSyncMessageVerified*) buildPartial;
|
||||
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) mergeFrom:(OWSSignalServiceProtosSyncMessageVerified*) other;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
|
||||
|
||||
- (BOOL) hasDestination;
|
||||
- (NSString*) destination;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) setDestination:(NSString*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) clearDestination;
|
||||
|
||||
- (BOOL) hasIdentityKey;
|
||||
- (NSData*) identityKey;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) setIdentityKey:(NSData*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) clearIdentityKey;
|
||||
|
||||
- (BOOL) hasState;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedState) state;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) setState:(OWSSignalServiceProtosSyncMessageVerifiedState) value;
|
||||
- (OWSSignalServiceProtosSyncMessageVerifiedBuilder*) clearState;
|
||||
@end
|
||||
|
||||
@interface OWSSignalServiceProtosSyncMessageBuilder : PBGeneratedMessageBuilder {
|
||||
@private
|
||||
OWSSignalServiceProtosSyncMessage* resultSyncMessage;
|
||||
@ -1381,11 +1456,12 @@ NSString *NSStringFromOWSSignalServiceProtosGroupContextType(OWSSignalServicePro
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) mergeBlocked:(OWSSignalServiceProtosSyncMessageBlocked*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) clearBlocked;
|
||||
|
||||
- (NSMutableArray<OWSSignalServiceProtosSyncMessageVerified*> *)verified;
|
||||
- (OWSSignalServiceProtosSyncMessageVerified*)verifiedAtIndex:(NSUInteger)index;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)addVerified:(OWSSignalServiceProtosSyncMessageVerified*)value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)setVerifiedArray:(NSArray<OWSSignalServiceProtosSyncMessageVerified*> *)array;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder *)clearVerified;
|
||||
- (BOOL) hasVerified;
|
||||
- (OWSSignalServiceProtosVerified*) verified;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) setVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) setVerifiedBuilder:(OWSSignalServiceProtosVerifiedBuilder*) builderForValue;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) mergeVerified:(OWSSignalServiceProtosVerified*) value;
|
||||
- (OWSSignalServiceProtosSyncMessageBuilder*) clearVerified;
|
||||
|
||||
- (BOOL) hasPadding;
|
||||
- (NSData*) padding;
|
||||
@ -1609,25 +1685,30 @@ 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;
|
||||
@ -1745,6 +1826,13 @@ 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,6 +17,7 @@ typedef enum {
|
||||
RPRecentCallTypeOutgoingIncomplete,
|
||||
RPRecentCallTypeIncomingIncomplete,
|
||||
RPRecentCallTypeMissedBecauseOfChangedIdentity,
|
||||
RPRecentCallTypeIncomingDeclined
|
||||
} RPRecentCallType;
|
||||
|
||||
@interface TSCall : TSInteraction <OWSReadTracking>
|
||||
|
||||
@ -76,6 +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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +119,7 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
|
||||
|
||||
_callType = callType;
|
||||
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
|
||||
// redraw any thread-related unread count UI.
|
||||
|
||||
@ -50,6 +50,7 @@ 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
|
||||
|
||||
@ -73,13 +74,16 @@ 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];
|
||||
}
|
||||
|
||||
@ -88,6 +92,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
callMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
messageSender:(OWSMessageSender *)messageSender
|
||||
{
|
||||
self = [super init];
|
||||
@ -101,6 +106,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
_callMessageHandler = callMessageHandler;
|
||||
_contactsManager = contactsManager;
|
||||
_contactsUpdater = contactsUpdater;
|
||||
_identityManager = identityManager;
|
||||
_messageSender = messageSender;
|
||||
|
||||
_dbConnection = storageManager.newDatabaseConnection;
|
||||
@ -109,9 +115,24 @@ 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
|
||||
@ -165,6 +186,8 @@ 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";
|
||||
@ -219,8 +242,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[description appendString:@"Blocked"];
|
||||
} else if (syncMessage.read.count > 0) {
|
||||
[description appendString:@"ReadReceipt"];
|
||||
} else if (syncMessage.verified.count > 0){
|
||||
NSString *verifiedString = [NSString stringWithFormat:@"Verifications: (%lu)", (unsigned long)syncMessage.verified.count];
|
||||
} else if (syncMessage.hasVerified) {
|
||||
NSString *verifiedString =
|
||||
[NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination];
|
||||
[description appendString:verifiedString];
|
||||
} else {
|
||||
// Shouldn't happen
|
||||
@ -363,7 +387,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:[OWSIdentityManager sharedManager]
|
||||
identityKeyStore:self.identityManager
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
@ -415,7 +439,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:[OWSIdentityManager sharedManager]
|
||||
identityKeyStore:self.identityManager
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
@ -449,7 +473,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
sourceId:envelope.source
|
||||
sourceDeviceId:envelope.sourceDevice];
|
||||
if (duplicateEnvelope) {
|
||||
DDLogInfo(@"%@ Ignoring previously received envelope with timestamp: %llu", self.tag, envelope.timestamp);
|
||||
DDLogInfo(@"%@ Ignoring previously received envelope from %@.%d with timestamp: %llu", self.tag, envelope.source, (unsigned int)envelope.sourceDevice, envelope.timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -462,6 +486,8 @@ 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);
|
||||
}
|
||||
@ -499,7 +525,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSString *recipientId = incomingEnvelope.source;
|
||||
|
||||
__block TSThread *thread;
|
||||
[[TSStorageManager sharedManager].dbConnection
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
||||
}];
|
||||
@ -648,7 +674,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
} else if (syncMessage.hasRequest) {
|
||||
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
|
||||
OWSSyncContactsMessage *syncContactsMessage =
|
||||
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager];
|
||||
[[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager
|
||||
identityManager:self.identityManager];
|
||||
|
||||
[self.messageSender sendTemporaryAttachmentData:[syncContactsMessage buildPlainTextAttachmentData]
|
||||
contentType:OWSMimeTypeApplicationOctetStream
|
||||
@ -659,9 +686,6 @@ 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];
|
||||
|
||||
@ -687,10 +711,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[OWSReadReceiptsProcessor alloc] initWithReadReceiptProtos:syncMessage.read
|
||||
storageManager:self.storageManager];
|
||||
[readReceiptsProcessor process];
|
||||
} else if (syncMessage.verified.count > 0) {
|
||||
DDLogInfo(@"%@ Received %ld verification state(s)", self.tag, (u_long)syncMessage.verified.count);
|
||||
|
||||
[[OWSIdentityManager sharedManager] processIncomingSyncMessage:syncMessage.verified];
|
||||
} else if (syncMessage.hasVerified) {
|
||||
DDLogInfo(@"%@ Received verification state for %@", self.tag, syncMessage.verified.destination);
|
||||
[self.identityManager processIncomingSyncMessage:syncMessage.verified];
|
||||
} else {
|
||||
DDLogWarn(@"%@ Ignoring unsupported sync message.", self.tag);
|
||||
}
|
||||
@ -1060,6 +1083,12 @@ 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;
|
||||
|
||||
+ (id)sharedManager;
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
- (void)makeRequest:(TSRequest *)request
|
||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
|
||||
@ -22,7 +22,8 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
|
||||
|
||||
#pragma mark Singleton implementation
|
||||
|
||||
+ (id)sharedManager {
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static TSNetworkManager *sharedMyManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
||||
@ -160,7 +160,6 @@ NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange =
|
||||
DDLogInfo(@"%@ using reflector HTTPSessionManager", self.tag);
|
||||
return self.reflectorHTTPSessionManager;
|
||||
} else {
|
||||
DDLogDebug(@"%@ using default HTTPSessionManager", self.tag);
|
||||
return self.defaultHTTPSessionManager;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +156,6 @@ 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:
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalServiceKit/TSYapDatabaseObject.h>
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -13,6 +14,7 @@ typedef NS_ENUM(NSUInteger, OWSVerificationState) {
|
||||
};
|
||||
|
||||
NSString *OWSVerificationStateToString(OWSVerificationState verificationState);
|
||||
OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState);
|
||||
|
||||
@interface OWSRecipientIdentity : TSYapDatabaseObject
|
||||
|
||||
|
||||
@ -20,6 +20,18 @@ 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;
|
||||
@ -79,7 +91,7 @@ NSString *OWSVerificationStateToString(OWSVerificationState verificationState)
|
||||
{
|
||||
changeBlock(self);
|
||||
|
||||
[[self class].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[[self class].dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
OWSRecipientIdentity *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
|
||||
if (latest == nil) {
|
||||
[self saveWithTransaction:transaction];
|
||||
|
||||
@ -170,7 +170,6 @@ 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.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
__block int i = 0;
|
||||
|
||||
DDLogInfo(@"%@ SignedPreKeys Report:", tag);
|
||||
|
||||
@ -1,10 +1,30 @@
|
||||
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 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
|
||||
|
||||
/**
|
||||
* Remove any inaccessible data left behind due to application bugs.
|
||||
*/
|
||||
- (void)removeOrphanedData;
|
||||
- (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;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSOrphanedDataCleaner.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -7,84 +9,256 @@
|
||||
#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)removeOrphanedData
|
||||
+ (void)auditAsync
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
|
||||
// Remove any lingering attachments
|
||||
for (NSString *path in [self orphanedFilePaths]) {
|
||||
DDLogWarn(@"Removing orphaned file attachment at path: %@", path);
|
||||
NSError *error;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"Unable to remove orphaned file attachment at path:%@", path);
|
||||
}
|
||||
}
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[OWSOrphanedDataCleaner auditAndCleanup:NO completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)orphanedInteractionIds
|
||||
+ (void)auditAndCleanupAsync:(void (^_Nullable)())completion
|
||||
{
|
||||
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];
|
||||
}
|
||||
}];
|
||||
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);
|
||||
|
||||
return [interactionIds copy];
|
||||
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;
|
||||
}
|
||||
|
||||
[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) {
|
||||
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];
|
||||
if (error) {
|
||||
OWSFail(@"Could not remove orphan file at: %@", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)orphanedFilePaths
|
||||
+ (void)printPaths:(NSArray<NSString *> *)paths label:(NSString *)label
|
||||
{
|
||||
for (NSString *path in [paths sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
CleanupLogDebug(@"%@: %@", label, path);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)filePathsInAttachmentsFolder
|
||||
{
|
||||
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];
|
||||
if (error) {
|
||||
OWSFail(@"contentsOfDirectoryAtPath error: %@", error);
|
||||
return [NSSet new];
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
+ (long long)fileSizeOfFilePath:(NSString *)filePath
|
||||
{
|
||||
NSError *error;
|
||||
NSMutableArray<NSString *> *filenames =
|
||||
[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[TSAttachmentStream attachmentsFolder] error:&error]
|
||||
mutableCopy];
|
||||
NSNumber *fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error][NSFileSize];
|
||||
if (error) {
|
||||
DDLogError(@"error getting orphanedFilePaths:%@", error);
|
||||
return @[];
|
||||
OWSFail(@"attributesOfItemAtPath: %@ error: %@", filePath, error);
|
||||
return 0;
|
||||
}
|
||||
return fileSize.longLongValue;
|
||||
}
|
||||
|
||||
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;
|
||||
+ (long long)fileSizeOfFilePaths:(NSArray<NSString *> *)filePaths
|
||||
{
|
||||
long long result = 0;
|
||||
for (NSString *filePath in filePaths) {
|
||||
result += [self fileSizeOfFilePath:filePath];
|
||||
}
|
||||
|
||||
[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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
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 [absolutePathsToDelete copy];
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -21,7 +21,9 @@ NSString *const TSArchiveGroup = @"TSArchiveGroup";
|
||||
NSString *const TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
|
||||
NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
|
||||
|
||||
NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName";
|
||||
// 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";
|
||||
@ -231,7 +233,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
||||
YapDatabaseViewSorting *viewSorting = [self threadSorting];
|
||||
|
||||
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
||||
options.isPersistent = NO;
|
||||
options.isPersistent = YES;
|
||||
options.allowedCollections =
|
||||
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
- (void)storePhoneNumber:(NSString *)phoneNumber
|
||||
{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:phoneNumber
|
||||
forKey:TSStorageRegisteredNumberKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
@ -61,13 +61,12 @@
|
||||
}
|
||||
|
||||
+ (void)storeServerToken:(NSString *)authToken signalingKey:(NSString *)signalingKey {
|
||||
YapDatabaseConnection *dbConn = [[self sharedManager] dbConnection];
|
||||
|
||||
[dbConn readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:authToken forKey:TSStorageServerAuthToken inCollection:TSStorageUserAccountCollection];
|
||||
[transaction setObject:signalingKey
|
||||
forKey:TSStorageServerSignalingKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
TSStorageManager *sharedManager = self.sharedManager;
|
||||
[sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:authToken forKey:TSStorageServerAuthToken inCollection:TSStorageUserAccountCollection];
|
||||
[transaction setObject:signalingKey
|
||||
forKey:TSStorageServerSignalingKey
|
||||
inCollection:TSStorageUserAccountCollection];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
@ -61,7 +61,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (nullable SignedPreKeyRecord *)signedPreKeyRecordForKey:(NSString *)key inCollection:(NSString *)collection;
|
||||
- (void)purgeCollection:(NSString *)collection;
|
||||
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
|
||||
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -156,7 +156,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
if (!_database) {
|
||||
return NO;
|
||||
}
|
||||
_dbConnection = self.newDatabaseConnection;
|
||||
_dbReadConnection = self.newDatabaseConnection;
|
||||
_dbReadWriteConnection = self.newDatabaseConnection;
|
||||
|
||||
return YES;
|
||||
}
|
||||
@ -388,19 +389,19 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
#pragma mark - convenience methods
|
||||
|
||||
- (void)purgeCollection:(NSString *)collection {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:collection];
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:object forKey:key inCollection:collection];
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction setObject:object forKey:key inCollection:collection];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(NSString *)string inCollection:(NSString *)collection {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeObjectForKey:string inCollection:collection];
|
||||
}];
|
||||
}
|
||||
@ -408,8 +409,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (id)objectForKey:(NSString *)key inCollection:(NSString *)collection {
|
||||
__block NSString *object;
|
||||
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
}];
|
||||
|
||||
return object;
|
||||
@ -419,8 +420,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
{
|
||||
__block NSDictionary *object;
|
||||
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:key inCollection:collection];
|
||||
}];
|
||||
|
||||
return object;
|
||||
@ -479,7 +480,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection
|
||||
{
|
||||
__block int value = 0;
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
value = [[transaction objectForKey:key inCollection:collection] intValue];
|
||||
value++;
|
||||
[transaction setObject:@(value) forKey:key inCollection:collection];
|
||||
@ -503,11 +504,11 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
}
|
||||
|
||||
- (void)deleteThreadsAndMessages {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[TSThread collection]];
|
||||
[transaction removeAllObjectsInCollection:[SignalRecipient collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSInteraction collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSAttachment collection]];
|
||||
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[TSThread collection]];
|
||||
[transaction removeAllObjectsInCollection:[SignalRecipient collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSInteraction collection]];
|
||||
[transaction removeAllObjectsInCollection:[TSAttachment collection]];
|
||||
}];
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
}
|
||||
@ -529,7 +530,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
- (void)resetSignalStorage
|
||||
{
|
||||
self.database = nil;
|
||||
_dbConnection = nil;
|
||||
_dbReadConnection = nil;
|
||||
_dbReadWriteConnection = nil;
|
||||
|
||||
[self deletePasswordFromKeychain];
|
||||
|
||||
|
||||
@ -58,10 +58,12 @@
|
||||
usingBlock:(void (^)(id object, BOOL *stop))block;
|
||||
|
||||
/**
|
||||
* @return A shared database connection.
|
||||
* @return Shared database connections for reading and writing.
|
||||
*/
|
||||
- (YapDatabaseConnection *)dbConnection;
|
||||
+ (YapDatabaseConnection *)dbConnection;
|
||||
- (YapDatabaseConnection *)dbReadConnection;
|
||||
+ (YapDatabaseConnection *)dbReadConnection;
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection;
|
||||
|
||||
- (TSStorageManager *)storageManager;
|
||||
+ (TSStorageManager *)storageManager;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Frederic Jacobs on 16/11/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
#import "TSStorageManager.h"
|
||||
@ -31,7 +32,7 @@
|
||||
|
||||
- (void)save
|
||||
{
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -43,7 +44,7 @@
|
||||
|
||||
- (void)touch
|
||||
{
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self touchWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
@ -55,14 +56,19 @@
|
||||
|
||||
- (void)remove
|
||||
{
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self removeWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbConnection
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return [[self class] dbConnection];
|
||||
return [[self class] dbReadConnection];
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return [[self class] dbReadWriteConnection];
|
||||
}
|
||||
|
||||
- (TSStorageManager *)storageManager
|
||||
@ -72,9 +78,26 @@
|
||||
|
||||
#pragma mark Class Methods
|
||||
|
||||
+ (YapDatabaseConnection *)dbConnection
|
||||
+ (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return [self storageManager].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;
|
||||
}
|
||||
|
||||
+ (TSStorageManager *)storageManager
|
||||
@ -90,7 +113,7 @@
|
||||
+ (NSUInteger)numberOfKeysInCollection
|
||||
{
|
||||
__block NSUInteger count;
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
count = [self numberOfKeysInCollectionWithTransaction:transaction];
|
||||
}];
|
||||
return count;
|
||||
@ -112,7 +135,7 @@
|
||||
|
||||
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id object, BOOL *stop))block
|
||||
{
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self enumerateCollectionObjectsWithTransaction:transaction usingBlock:block];
|
||||
}];
|
||||
}
|
||||
@ -131,7 +154,7 @@
|
||||
|
||||
+ (void)removeAllObjectsInCollection
|
||||
{
|
||||
[[self dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[self dbReadWriteConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:[self collection]];
|
||||
}];
|
||||
}
|
||||
@ -144,7 +167,7 @@
|
||||
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
|
||||
{
|
||||
__block id object;
|
||||
[[self dbConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
object = [transaction objectForKey:uniqueID inCollection:[self collection]];
|
||||
}];
|
||||
return object;
|
||||
|
||||
@ -70,8 +70,17 @@
|
||||
//
|
||||
// 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() \
|
||||
|
||||
@ -153,8 +153,6 @@ 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,6 +420,12 @@ 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,9 +30,10 @@
|
||||
}
|
||||
|
||||
- (void)testSignedPreKeyDeletion {
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int days = 20;
|
||||
int lastPreKeyId = days;
|
||||
@ -69,9 +70,10 @@
|
||||
|
||||
- (void)testSignedPreKeyDeletionKeepsSomeOldKeys
|
||||
{
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int lastPreKeyId = 10;
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
@ -113,10 +115,11 @@
|
||||
}
|
||||
|
||||
- (void)testOlderRecordsNotDeletedIfNoReplacement {
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[transaction removeAllObjectsInCollection:TSStorageManagerSignedPreKeyStoreCollection];
|
||||
}];
|
||||
|
||||
int days = 3;
|
||||
int lastPreKeyId = days;
|
||||
|
||||
|
||||
@ -26,10 +26,7 @@
|
||||
{
|
||||
// Sanity Check
|
||||
XCTAssertNotNil(self.localNumber);
|
||||
[[[SignalRecipient alloc] initWithTextSecureIdentifier:self.localNumber
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES] save];
|
||||
[[[SignalRecipient alloc] initWithTextSecureIdentifier:self.localNumber relay:nil] save];
|
||||
XCTAssertNotNil([SignalRecipient recipientWithTextSecureIdentifier:self.localNumber]);
|
||||
|
||||
SignalRecipient *me = [SignalRecipient selfRecipient];
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
// Created by Michael Kirk on 11/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSContactThread.h"
|
||||
#import "TSStorageManager+identityKeyStore.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@ -17,8 +19,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[OWSUnitTestEnvironment ensureSetup];
|
||||
self.contactThread = [TSContactThread getOrCreateThreadWithContactId:@"fake-contact-id"];
|
||||
[self.contactThread.storageManager removeIdentityKeyForRecipient:self.contactThread.contactIdentifier];
|
||||
[OWSRecipientIdentity removeAllObjectsInCollection];
|
||||
}
|
||||
|
||||
- (void)testHasSafetyNumbersWithoutRemoteIdentity
|
||||
@ -28,8 +31,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testHasSafetyNumbersWithRemoteIdentity
|
||||
{
|
||||
[self.contactThread.storageManager saveRemoteIdentity:[NSData new]
|
||||
recipientId:self.contactThread.contactIdentifier];
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:[NSData new]
|
||||
recipientId:self.contactThread.contactIdentifier];
|
||||
XCTAssert(self.contactThread.hasSafetyNumbers);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
[super setUp];
|
||||
|
||||
// Register views, etc.
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
[[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{}];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
@ -66,7 +66,8 @@
|
||||
XCTAssertEqual(0, [thread numberOfInteractions]);
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *incomingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachmentStream *incomingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
sourceFilename:nil];
|
||||
[incomingAttachment writeData:[NSData new] error:&error];
|
||||
[incomingAttachment save];
|
||||
|
||||
@ -83,7 +84,8 @@
|
||||
expiresInSeconds:0];
|
||||
[incomingMessage save];
|
||||
|
||||
TSAttachmentStream *outgoingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachmentStream *outgoingAttachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
sourceFilename:nil];
|
||||
[outgoingAttachment writeData:[NSData new] error:&error];
|
||||
[outgoingAttachment save];
|
||||
|
||||
@ -94,7 +96,7 @@
|
||||
TSOutgoingMessage *outgoingMessage = [[TSOutgoingMessage alloc] initWithTimestamp:10000
|
||||
inThread:thread
|
||||
messageBody:@"outgoing message body"
|
||||
attachmentIds:@[ outgoingAttachment.uniqueId ]];
|
||||
attachmentIds:[@[ outgoingAttachment.uniqueId ] mutableCopy]];
|
||||
[outgoingMessage save];
|
||||
|
||||
// Sanity check
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
@ -75,7 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testDescriptionWithPhotoAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -89,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testDescriptionWithVideoAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4"];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4" sourceFilename:nil];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -100,10 +102,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTAssertEqualObjects(@"📽 ATTACHMENT", actualDescription);
|
||||
}
|
||||
|
||||
|
||||
- (void)testDescriptionWithAudioAttachmentId
|
||||
{
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:@"some-file.mp3"];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -114,9 +115,22 @@ 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"];
|
||||
TSAttachment *attachment = [[TSAttachmentStream alloc] initWithContentType:@"non/sense" sourceFilename:nil];
|
||||
[attachment save];
|
||||
|
||||
TSMessage *message = [[TSMessage alloc] initWithTimestamp:1
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Michael Kirk on 10/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSContactThread.h"
|
||||
#import "TSOutgoingMessage.h"
|
||||
@ -34,18 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
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;
|
||||
[message updateWithMessageState:TSOutgoingMessageStateSentToService];
|
||||
XCTAssert(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
@ -56,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
message.messageState = TSOutgoingMessageStateUnsent;
|
||||
[message updateWithMessageState:TSOutgoingMessageStateUnsent];
|
||||
XCTAssertFalse(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
@ -67,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
messageBody:nil
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:10];
|
||||
message.messageState = TSOutgoingMessageStateAttemptingOut;
|
||||
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut];
|
||||
XCTAssertFalse(message.shouldStartExpireTimer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSDisappearingMessagesFinder.h"
|
||||
@ -12,16 +13,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSDisappearingMessagesFinder (Testing)
|
||||
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessages;
|
||||
- (NSArray<TSMessage *> *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread;
|
||||
- (NSArray<TSMessage *> *)fetchExpiredMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (NSArray<TSMessage *> *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface OWSDisappearingMessageFinderTest : XCTestCase
|
||||
|
||||
@property TSStorageManager *storageManager;
|
||||
@property YapDatabaseConnection *dbConnection;
|
||||
@property OWSDisappearingMessagesFinder *finder;
|
||||
@property TSStorageManager *storageManager;
|
||||
@property TSThread *thread;
|
||||
@property uint64_t now;
|
||||
|
||||
@ -35,13 +38,14 @@ 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 alloc] initWithStorageManager:self.storageManager];
|
||||
[self.finder blockingRegisterDatabaseExtensions];
|
||||
self.finder = [OWSDisappearingMessagesFinder new];
|
||||
[OWSDisappearingMessagesFinder blockingRegisterDatabaseExtensions:self.storageManager];
|
||||
}
|
||||
|
||||
- (void)testExpiredMessages
|
||||
@ -90,7 +94,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"];
|
||||
[unExpiringMessage2 save];
|
||||
|
||||
NSArray<TSMessage *> *actualMessages = [self.finder fetchExpiredMessages];
|
||||
__block NSArray<TSMessage *> *actualMessages;
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
actualMessages = [self.finder fetchExpiredMessagesWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
NSArray<TSMessage *> *expectedMessages = @[ expiredMessage1, expiredMessage2 ];
|
||||
XCTAssertEqualObjects(expectedMessages, actualMessages);
|
||||
}
|
||||
@ -133,15 +141,33 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"];
|
||||
[unExpiringMessage2 save];
|
||||
|
||||
NSArray<TSMessage *> *actualMessages = [self.finder fetchUnstartedExpiringMessagesInThread:self.thread];
|
||||
__block NSArray<TSMessage *> *actualMessages;
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
actualMessages = [self.finder fetchUnstartedExpiringMessagesInThread:self.thread
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
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.finder.nextExpirationTimestamp);
|
||||
|
||||
XCTAssertNil(self.nextExpirationTimestamp);
|
||||
|
||||
TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1
|
||||
inThread:self.thread
|
||||
@ -150,7 +176,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expiresInSeconds:0
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
XCTAssertNil(self.finder.nextExpirationTimestamp);
|
||||
XCTAssertNil(self.nextExpirationTimestamp);
|
||||
}
|
||||
|
||||
- (void)testNextExpirationTimestampNotNilWithUpcomingExpiringMessages
|
||||
@ -163,8 +189,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:self.now - 9000];
|
||||
[soonToExpireMessage save];
|
||||
|
||||
XCTAssertNotNil(self.finder.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now + 1000, [self.finder.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
XCTAssertNotNil(self.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now + 1000, [self.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
|
||||
// expired message should take precedence
|
||||
TSMessage *expiredMessage = [[TSMessage alloc] initWithTimestamp:1
|
||||
@ -175,8 +201,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:self.now - 11000];
|
||||
[expiredMessage save];
|
||||
|
||||
XCTAssertNotNil(self.finder.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now - 1000, [self.finder.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
//FIXME remove sleep hack in favor of expiringMessage completion handler
|
||||
// sleep(2);
|
||||
XCTAssertNotNil(self.nextExpirationTimestamp);
|
||||
XCTAssertEqual(self.now - 1000, [self.nextExpirationTimestamp unsignedLongLongValue]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Michael Kirk on 9/23/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSDisappearingMessagesConfiguration.h"
|
||||
@ -13,6 +14,14 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSDisappearingMessagesJob (Testing)
|
||||
|
||||
- (void)run;
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
|
||||
@end
|
||||
|
||||
@interface OWSDisappearingMessagesJobTest : XCTestCase
|
||||
|
||||
@end
|
||||
@ -61,12 +70,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
|
||||
OWSDisappearingMessagesJob *job =
|
||||
[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
|
||||
OWSDisappearingMessagesJob *job = [OWSDisappearingMessagesJob sharedJob];
|
||||
|
||||
// Sanity Check.
|
||||
XCTAssertEqual(4, [TSMessage numberOfKeysInCollection]);
|
||||
[job run];
|
||||
|
||||
//FIXME remove sleep hack in favor of expiringMessage completion handler
|
||||
sleep(4);
|
||||
XCTAssertEqual(2, [TSMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
@ -75,9 +87,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
TSThread *thread = [[TSThread alloc] initWithUniqueId:@"fake-thread-id"];
|
||||
[thread save];
|
||||
|
||||
OWSDisappearingMessagesJob *job =
|
||||
[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]];
|
||||
|
||||
OWSDisappearingMessagesJob *job = [OWSDisappearingMessagesJob sharedJob];
|
||||
|
||||
OWSDisappearingMessagesConfiguration *configuration =
|
||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
[configuration remove];
|
||||
@ -90,7 +101,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expireStartedAt:0];
|
||||
[expiringMessage save];
|
||||
|
||||
|
||||
[job becomeConsistentWithConfigurationForMessage:expiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
configuration = [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
|
||||
@ -104,14 +114,10 @@ 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"
|
||||
@ -119,7 +125,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
expiresInSeconds:0
|
||||
expireStartedAt:0];
|
||||
[unExpiringMessage save];
|
||||
[job becomeConsistentWithConfigurationForMessage:unExpiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
[OWSDisappearingMessagesJob becomeConsistentWithConfigurationForMessage:unExpiringMessage contactsManager:[OWSFakeContactsManager new]];
|
||||
XCTAssertNil([OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId]);
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (self.shouldSucceed) {
|
||||
successHandler();
|
||||
} else {
|
||||
failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError());
|
||||
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
[error setIsRetryable:NO];
|
||||
|
||||
failureHandler(error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +133,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSMessageSenderFakeNetworkManager : OWSFakeNetworkManager
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithSuccess:(BOOL)shouldSucceed NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, readonly) BOOL shouldSucceed;
|
||||
@ -141,7 +144,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (instancetype)initWithSuccess:(BOOL)shouldSucceed
|
||||
{
|
||||
self = [super init];
|
||||
self = [self init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
@ -240,6 +243,8 @@ 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 {
|
||||
@ -316,7 +321,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendMessage:message
|
||||
success:^() {
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -341,9 +346,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendAttachmentData:[NSData new]
|
||||
contentType:@"image/gif"
|
||||
sourceFilename:nil
|
||||
inMessage:message
|
||||
success:^() {
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -394,6 +400,7 @@ 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.");
|
||||
@ -422,6 +429,7 @@ 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.");
|
||||
@ -444,15 +452,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSData *groupIdData = [Cryptography generateRandomBytes:32];
|
||||
SignalRecipient *successfulRecipient =
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id" relay:nil];
|
||||
SignalRecipient *successfulRecipient2 =
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id2"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:@"successful-recipient-id2" relay:nil];
|
||||
|
||||
TSGroupModel *groupModel = [[TSGroupModel alloc]
|
||||
initWithTitle:@"group title"
|
||||
@ -467,7 +469,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTestExpectation *markedAsSent = [self expectationWithDescription:@"markedAsSent"];
|
||||
[messageSender sendMessage:message
|
||||
success:^{
|
||||
if (message.messageState == TSOutgoingMessageStateSent) {
|
||||
if (message.messageState == TSOutgoingMessageStateSentToService) {
|
||||
[markedAsSent fulfill];
|
||||
} else {
|
||||
XCTFail(@"Unexpected message state");
|
||||
@ -483,10 +485,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)testGetRecipients
|
||||
{
|
||||
SignalRecipient *recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
SignalRecipient *recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id" relay:nil];
|
||||
[recipient save];
|
||||
|
||||
OWSMessageSender *messageSender = self.successfulMessageSender;
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
#import "TSGroupThread.h"
|
||||
#import "TSMessagesManager.h"
|
||||
#import "TSNetworkManager.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -30,6 +32,7 @@ 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
|
||||
@ -54,9 +57,17 @@ 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,17 +14,19 @@
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSOrphanedDataCleanerTest
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Register views, etc.
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
[[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{}];
|
||||
|
||||
// Set up initial conditions & Sanity check
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
[TSAttachmentStream removeAllObjectsInCollection];
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfKeysInCollection]);
|
||||
[TSIncomingMessage removeAllObjectsInCollection];
|
||||
@ -38,6 +40,11 @@
|
||||
[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
|
||||
@ -53,7 +60,17 @@
|
||||
[incomingMessage save];
|
||||
XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
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(0, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
@ -70,25 +87,51 @@
|
||||
[incomingMessage save];
|
||||
XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
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, [TSIncomingMessage numberOfKeysInCollection]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithoutInteractionsAreDeleted
|
||||
{
|
||||
// sanity check
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
[attachmentStream writeData:[NSData new] error:&error];
|
||||
[attachmentStream save];
|
||||
NSString *orphanedFilePath = [attachmentStream filePath];
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
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);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssertFalse(fileExists);
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithInteractionsAreNotDeleted
|
||||
@ -97,7 +140,7 @@
|
||||
[savedThread save];
|
||||
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
[attachmentStream writeData:[NSData new] error:&error];
|
||||
[attachmentStream save];
|
||||
|
||||
@ -113,32 +156,50 @@
|
||||
NSString *attachmentFilePath = [attachmentStream filePath];
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"];
|
||||
[OWSOrphanedDataCleaner auditAndCleanupAsync:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0
|
||||
handler:^(NSError *error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation Failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath];
|
||||
XCTAssert(fileExists);
|
||||
XCTAssertEqual(1, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
- (void)testFilesWithoutAttachmentStreamsAreDeleted
|
||||
{
|
||||
NSError *error;
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"];
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil];
|
||||
[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, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
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);
|
||||
}
|
||||
}];
|
||||
|
||||
[[OWSOrphanedDataCleaner new] removeOrphanedData];
|
||||
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanedFilePath];
|
||||
XCTAssertFalse(fileExists);
|
||||
XCTAssertEqual(0, [TSAttachmentStream numberOfItemsInAttachmentsFolder]);
|
||||
XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -27,13 +27,14 @@
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
self.thread = [TSContactThread getOrCreateThreadWithContactId:@"aStupidId" transaction:transaction];
|
||||
|
||||
[self.thread saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
self.thread = [TSContactThread getOrCreateThreadWithContactId:@"aStupidId" transaction:transaction];
|
||||
|
||||
[self.thread saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
TSStorageManager *manager = [TSStorageManager sharedManager];
|
||||
[manager purgeCollection:[TSMessage collection]];
|
||||
}
|
||||
@ -154,7 +155,8 @@
|
||||
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].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[[TSStorageManager sharedManager].dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:[[TSGroupModel alloc] initWithTitle:@"fdsfsd"
|
||||
memberIds:[@[] mutableCopy]
|
||||
image:nil
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
//
|
||||
// TSStorageIdentityKeyStoreTests.m
|
||||
// TextSecureKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 06/11/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
@ -11,8 +7,8 @@
|
||||
|
||||
#import "OWSUnitTestEnvironment.h"
|
||||
#import "SecurityUtils.h"
|
||||
#import "TSPrivacyPreferences.h"
|
||||
#import "TSStorageManager+IdentityKeyStore.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "OWSRecipientIdentity.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
|
||||
@ -24,8 +20,9 @@
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
[[TSStorageManager sharedManager] purgeCollection:@"TSStorageManagerTrustedKeysCollection"];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
[OWSRecipientIdentity removeAllObjectsInCollection];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
@ -37,61 +34,42 @@
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
}
|
||||
|
||||
- (void)testAlreadyRegisteredKey {
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
}
|
||||
|
||||
|
||||
- (void)testChangedKeyWithBlockingIdentityChanges
|
||||
- (void)testChangedKey
|
||||
{
|
||||
TSPrivacyPreferences *preferences = [TSPrivacyPreferences sharedInstance];
|
||||
preferences.shouldBlockOnIdentityChange = YES;
|
||||
[preferences save];
|
||||
NSData *originalKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@protonmail.com";
|
||||
|
||||
NSData *newKey = [SecurityUtils generateRandomBytes:32];
|
||||
NSString *recipientId = @"test@gmail.com";
|
||||
|
||||
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId];
|
||||
[[OWSIdentityManager sharedManager] saveRemoteIdentity:originalKey recipientId:recipientId];
|
||||
|
||||
XCTAssert([[TSStorageManager sharedManager] isTrustedIdentityKey:newKey recipientId:recipientId]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
|
||||
NSData *otherKey = [SecurityUtils generateRandomBytes:32];
|
||||
|
||||
XCTAssertFalse([[TSStorageManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId]);
|
||||
XCTAssertFalse([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId direction:TSMessageDirectionOutgoing]);
|
||||
XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey recipientId:recipientId direction:TSMessageDirectionIncoming]);
|
||||
}
|
||||
|
||||
|
||||
- (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 {
|
||||
[[TSStorageManager sharedManager] generateNewIdentityKey];
|
||||
[[OWSIdentityManager sharedManager] generateNewIdentityKey];
|
||||
|
||||
XCTAssert([[[TSStorageManager sharedManager] identityKeyPair].publicKey length] == 32);
|
||||
XCTAssert([[[OWSIdentityManager sharedManager] identityKeyPair].publicKey length] == 32);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Michael Kirk on 10/7/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSFakeContactsManager.h"
|
||||
|
||||
@ -14,7 +15,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return @"Fake name";
|
||||
}
|
||||
|
||||
- (NSArray<Contact *> * _Nonnull)signalContacts
|
||||
- (NSArray<Contact *> *)signalContacts
|
||||
{
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (NSArray<SignalAccount *> *)signalAccounts
|
||||
{
|
||||
return @[];
|
||||
}
|
||||
|
||||
@ -13,9 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
{
|
||||
NSLog(@"[OWSFakeContactsUpdater] Faking contact lookup.");
|
||||
return [[SignalRecipient alloc] initWithTextSecureIdentifier:@"fake-recipient-id"
|
||||
relay:nil
|
||||
supportsVoice:YES
|
||||
supportsWebRTC:YES];
|
||||
relay:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSFakeMessageSender : OWSMessageSender
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithExpectation:(XCTestExpectation *)expectation;
|
||||
|
||||
@property (nonatomic, readonly) XCTestExpectation *expectation;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Created by Michael Kirk on 12/18/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSFakeNotificationsManager.h"
|
||||
|
||||
@ -8,8 +9,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,5 +1,6 @@
|
||||
// Created by Michael Kirk on 12/18/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TextSecureKitEnv.h"
|
||||
|
||||
@ -7,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSUnitTestEnvironment : TextSecureKitEnv
|
||||
|
||||
+ (void)ensureSetup;
|
||||
- (instancetype)initDefault;
|
||||
|
||||
@end
|
||||
|
||||
@ -12,7 +12,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OWSUnitTestEnvironment
|
||||
|
||||
- (instancetype)init
|
||||
+ (void)ensureSetup
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[self setSharedEnv:[[self alloc] initDefault]];
|
||||
});
|
||||
}
|
||||
|
||||
- (instancetype)initDefault
|
||||
{
|
||||
return [super initWithCallMessageHandler:[OWSFakeCallMessageHandler new]
|
||||
contactsManager:[OWSFakeContactsManager new]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user