Compare commits

...

60 Commits

Author SHA1 Message Date
Michael Kirk
5c3b30104a Merge branch 'mkirk/moving-repo' 2017-07-21 15:53:34 -04:00
Michael Kirk
1499840de5 update README and podspec to direct upgrading users to proper source
// FREEBIE
2017-07-21 15:09:14 -04:00
Matthew Chen
d98c07ecff Merge branch 'charlesmchen/countryNameVsiOS8' 2017-07-20 09:14:49 -04:00
Matthew Chen
493aaca242 Avoid nil country names on iOS 8.
// FREEBIE
2017-07-19 14:21:54 -04:00
Matthew Chen
e20d63240b Merge branch 'mkirk/cleanup-with-transaction' 2017-07-14 09:26:35 -04:00
Michael Kirk
faeb7100b9 use existing transaction in cleanup
// FREEBIE
2017-07-14 09:26:28 -04:00
Matthew Chen
fe0f01daec Merge branch 'charlesmchen/pasteVoiceMessages' 2017-07-13 17:22:18 -04:00
Matthew Chen
c255504959 Fix copy and paste of voice messages.
// FREEBIE
2017-07-13 14:31:12 -04:00
Matthew Chen
640ec13b2e Merge branch 'charlesmchen/orphanCleanup' 2017-07-12 12:13:14 -04:00
Matthew Chen
6fa3fac4ae Fix broken tests.
// FREEBIE
2017-07-12 12:12:59 -04:00
Matthew Chen
7a50d6b996 Fix broken tests.
// FREEBIE
2017-07-12 12:12:59 -04:00
Matthew Chen
762f915179 Respond to CR.
// FREEBIE
2017-07-12 12:12:59 -04:00
Matthew Chen
96da091e9b Run orphan cleanup on startup.
// FREEBIE
2017-07-12 12:12:59 -04:00
Michael Kirk
9115a1f973 Merge branch 'mkirk/update-ci-gems' 2017-07-12 11:36:38 -04:00
Michael Kirk
57b90e1462 update ci gems
// FREEBIE
2017-07-12 11:36:33 -04:00
Michael Kirk
e0f805f80f Merge branch 'mkirk/fix-persistence-upgrade' 2017-07-11 15:26:11 -04:00
Michael Kirk
ab6c1fb3b8 Fix persist view for upgrade scenarios
// FREEBIE
2017-07-11 13:22:23 -04:00
Michael Kirk
9d3175b5cf Merge branch 'mkirk/cleanup-logging' 2017-07-11 13:19:51 -04:00
Michael Kirk
957979585c remove unhelpful logging
// FREEBIE
2017-07-10 12:37:03 -05:00
Michael Kirk
8361ffb818 Merge branch 'mkirk/persist-thread-view' 2017-07-10 11:52:45 -05:00
Michael Kirk
ea681a61e2 persist thread view
// FREEBIE
2017-07-10 11:52:37 -05:00
Matthew Chen
c1e1247eff Merge branch 'charlesmchen/identityManagerVsStartup' 2017-07-06 14:38:52 -04:00
Matthew Chen
92276157dc Don’t sync verification state until app has finished becoming active.
// FREEBIE
2017-07-06 12:34:08 -04:00
Michael Kirk
2216c2d413 Merge pull request #295 from WhisperSystems/mkirk/fix-tests
fix tests
2017-07-06 10:28:28 -05:00
Michael Kirk
a23b4871e0 fix tests
// FREEBIE
2017-07-06 09:37:12 -05:00
Michael Kirk
72e893d5f7 Merge commit 'e24f18320d3aefe87d2532c9f0520348c4598cb2' 2017-07-06 09:08:02 -05:00
Matthew Chen
e24f18320d Merge branch 'charlesmchen/modelConnection' into hotfix/2.13.3.0 2017-07-05 19:06:30 -04:00
Matthew Chen
58fb86b8e0 Use a dedicated connection for model reads & writes.
// FREEBIE
2017-07-05 18:54:48 -04:00
Matthew Chen
065017cafd Merge branch 'charlesmchen/sharedReadAndWriteConnections' into hotfix/2.13.3.0 2017-07-05 17:23:03 -04:00
Matthew Chen
daae31d30e Modify TSStorageManager to use separate shared read and write connections.
// FREEBIE
2017-07-05 16:58:39 -04:00
Michael Kirk
8714a8f37c Merge branch 'mkirk/no-sync-to-unregistered-number' 2017-07-05 13:00:35 -05:00
Michael Kirk
deff1fa4e7 FIX: verifiying unregistered user prints "no longer registered" error on
every launch

// FREEBIE
2017-07-05 12:59:53 -05:00
Michael Kirk
1fc5f77286 Merge branch 'mkirk/declined-call-notification' 2017-07-05 12:42:51 -05:00
Michael Kirk
fd625dff50 remove default case for better compiler warnings
// FREEBIE
2017-07-05 12:42:21 -05:00
Michael Kirk
89f86c4fd2 call type for declined call
// FREEBIE
2017-07-03 13:45:17 -05:00
Michael Kirk
04ef06ce95 Merge branch 'mkirk/fix-unread-badge' 2017-06-30 10:21:30 -10:00
Michael Kirk
f59779c118 message manager updates badge count
// FREEBIE
2017-06-30 06:13:26 -10:00
Michael Kirk
85fe68d3c4 Fix typo after rename
// FREEBIE
2017-06-28 19:09:04 -10:00
Michael Kirk
d6c5497f64 Merge branch 'mkirk/fix-tests' 2017-06-28 18:40:37 -10:00
Michael Kirk
0b33ef6161 try fastlane scan, since build is timing out.
// FREEBIE
2017-06-28 18:30:17 -10:00
Michael Kirk
acf31db4b3 bump travis image to 8.3
// FREEBIE
2017-06-28 18:04:25 -10:00
Michael Kirk
a8ea2428c6 gemfile for consistent build on dev/CI
// FREEBIE
2017-06-28 17:42:24 -10:00
Michael Kirk
605db6b788 Fix up deleteAttachments method since making attachmentFolder
dispatchOnce

// FREEBIE
2017-06-28 17:07:11 -10:00
Michael Kirk
1d71ca5e50 Fix some more tests.
Adapt to IdentityManager refactor
Adapt to DisappearingMessages refactor

// FREEBIE
2017-06-28 16:18:13 -10:00
Michael Kirk
8f9af85cca prefer hacks in test to hacks in code.
Adding a completion handler would be a bit gnarly since we're snaking
through a pretty long method chain.

// FREEBIE
2017-06-28 08:09:23 -10:00
Michael Kirk
1b9aae2ea6 CR: renaming var to be more general
// FREEBIE
2017-06-28 07:32:31 -10:00
Michael Kirk
e652dff4b4 Allow override of singleton enforcement in test app
We frequently build multiple instances of "singletons" for the purpose
of testing.

// FREEBIE
2017-06-28 07:30:02 -10:00
Michael Kirk
edf5852e82 set-expiration dispatches *sync* so we can test it.
// FREEBIE
2017-06-28 07:30:02 -10:00
Michael Kirk
1fb9fa79df Fix up some more tests.
// FREEBIE
2017-06-28 07:30:02 -10:00
Michael Kirk
13c5bdb8c5 fix disappearing messages test
// FREEBIE
2017-06-28 07:30:02 -10:00
Michael Kirk
2addb9e81d Fixed test build. Some tests still failing.
Executed 85 tests, with 22 failures (17 unexpected) in 7.416 (8.531) seconds

// FREEBIE
2017-06-28 07:30:02 -10:00
Michael Kirk
c711b4a66d Merge branch 'mkirk/key-version' 2017-06-23 15:16:17 -04:00
Michael Kirk
b2f9abbc7c transmit key version byte
// FREEBIE
2017-06-23 15:12:51 -04:00
Matthew Chen
14c64239a3 Merge branch 'charlesmchen/archiveSessionsOnSSQ' 2017-06-22 18:18:49 -04:00
Matthew Chen
e9219743ff Archive sessions on the 'session store' queue.
// FREEBIE
2017-06-22 18:14:21 -04:00
Michael Kirk
793a7449b0 Merge branch 'mkirk/archive-sessions-on-id-change' 2017-06-22 17:24:05 -04:00
Michael Kirk
5da7dc1fd3 Archive sessions upon identity change.
Session clearing must be in IdentityKeyStore implementation

Trying to do it in the protocol will not work with multiple devices,
because we'll only archive the session of the first sending device.

// FREEBIE
2017-06-22 17:23:57 -04:00
Matthew Chen
07e0291377 Merge branch 'charlesmchen/diskUsage' 2017-06-22 17:17:00 -04:00
Matthew Chen
e8e7b6bcba Add creation timestamp to attachment streams.
// FREEBIE
2017-06-22 17:09:36 -04:00
Michael Kirk
8fda18a8e3 Merge branch 'mkirk/verification-sync' 2017-06-22 15:19:59 -04:00
70 changed files with 1108 additions and 438 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
xcshareddata
Pods/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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
View File

@ -0,0 +1,5 @@
source 'https://rubygems.org'
gem 'fastlane'
gem 'cocoapods'

189
Gemfile.lock Normal file
View 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

View File

@ -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) \

View File

@ -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

View File

@ -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
View File

@ -0,0 +1 @@
test_output

8
fastlane/Scanfile Normal file
View 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"]

View File

@ -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];
}

View File

@ -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]);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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];

View File

@ -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];
}];

View File

@ -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;

View File

@ -5,9 +5,10 @@
#import "OWSContactsOutputStream.h"
#import "Contact.h"
#import "MIMETypeUtil.h"
#import "NSData+keyVersionByte.h"
#import "OWSRecipientIdentity.h"
#import "OWSSignalServiceProtos.pb.h"
#import "SignalAccount.h"
#import "OWSRecipientIdentity.h"
#import <ProtocolBuffers/CodedOutputStream.h>
NS_ASSUME_NONNULL_BEGIN
@ -27,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
if (recipientIdentity != nil) {
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
verifiedBuilder.destination = recipientIdentity.recipientId;
verifiedBuilder.identityKey = recipientIdentity.identityKey;
verifiedBuilder.identityKey = [recipientIdentity.identityKey prependKeyType];
verifiedBuilder.state = OWSVerificationStateToProtoState(recipientIdentity.verificationState);
contactBuilder.verifiedBuilder = verifiedBuilder;
}

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -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);
}];
}

View File

@ -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

View File

@ -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];
}];
}

View File

@ -5,9 +5,10 @@
#import "OWSIdentityManager.h"
#import "NSDate+millisecondTimeStamp.h"
#import "NotificationsProtocol.h"
#import "OWSError.h"
#import "OWSMessageSender.h"
#import "OWSRecipientIdentity.h"
#import "OWSOutgoingNullMessage.h"
#import "OWSRecipientIdentity.h"
#import "OWSVerificationStateChangeMessage.h"
#import "OWSVerificationStateSyncMessage.h"
#import "TSAccountManager.h"
@ -15,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>
@ -91,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;
}
@ -197,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];
@ -205,7 +207,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
return YES;
}
DDLogDebug(@"%@ no changes for identity saved for recipient: %@", self.tag, recipientId);
return NO;
}
}
@ -363,7 +364,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
@synchronized(self)
{
if (recipientIdentity == nil) {
DDLogDebug(@"%@ Trusting previously unknown recipient: %@", self.tag, recipientIdentity.recipientId);
return YES;
}
@ -374,7 +374,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
}
if ([recipientIdentity isFirstKnownKey]) {
DDLogDebug(@"%@ trusting first known key for recipient: %@", self.tag, recipientIdentity.recipientId);
return YES;
}
@ -386,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);
@ -418,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];
}
@ -437,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,
@ -532,6 +541,13 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
}
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];
}
}];
}
@ -726,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];
}
@ -739,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

View File

@ -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();
}
@ -1169,7 +1163,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSMutableArray *messagesArray = [NSMutableArray arrayWithCapacity:recipient.devices.count];
NSData *plainText = [message buildPlainTextData];
DDLogDebug(@"%@ message: %@ plainTextData.length: %lu", self.tag, [message class], plainText.length);
DDLogDebug(@"%@ built message: %@ plainTextData.length: %lu", self.tag, [message class], plainText.length);
for (NSNumber *deviceNumber in recipient.devices) {
@try {

View File

@ -17,6 +17,7 @@ typedef enum {
RPRecentCallTypeOutgoingIncomplete,
RPRecentCallTypeIncomingIncomplete,
RPRecentCallTypeMissedBecauseOfChangedIdentity,
RPRecentCallTypeIncomingDeclined
} RPRecentCallType;
@interface TSCall : TSInteraction <OWSReadTracking>

View File

@ -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.

View File

@ -115,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
@ -510,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];
}];
@ -1068,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) {

View File

@ -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

View File

@ -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, ^{

View File

@ -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;
}
}

View File

@ -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:

View File

@ -91,7 +91,7 @@ OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerifica
{
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];

View File

@ -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]]) {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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]]];

View File

@ -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];
}];
}

View File

@ -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

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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() \

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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]);
}

View File

@ -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;

View File

@ -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"];

View File

@ -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

View File

@ -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. Theyll never know what it means to have a private moment to themselves an unrecorded, unanalyzed thought. And thats 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

View File

@ -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

View File

@ -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 @[];
}

View File

@ -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

View File

@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSFakeMessageSender : OWSMessageSender
- (instancetype)init;
- (instancetype)initWithExpectation:(XCTestExpectation *)expectation;
@property (nonatomic, readonly) XCTestExpectation *expectation;

View File

@ -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__);
}

View File

@ -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

View File

@ -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]