Compare commits

..

181 Commits

Author SHA1 Message Date
akwizgran
9476782ced Bump version numbers for 1.1.1 release. 2018-09-14 13:16:17 +01:00
akwizgran
74445acb55 Merge branch '1379-startup-failure-error' into 'master'
Correct startup database failure error messages

Closes #1379

See merge request briar/briar!920
2018-09-14 12:01:52 +00:00
akwizgran
e32771f964 Merge branch '1359-conversation-progress' into 'master'
Fix progress feel over messages in Conversation view

Closes #1359

See merge request briar/briar!911
2018-09-14 11:59:42 +00:00
akwizgran
d7bf1ee374 Merge branch '1367-db-header-corrupt' into 'master'
Fix duplicate actions triggered by hardware keyboard

Closes #1367

See merge request briar/briar!921
2018-09-14 09:09:41 +00:00
Torsten Grote
10bee05856 Only sign-in once when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
fc626d0921 Only create one private group when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
30f87e626a Only create one forum when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
a0d91da569 Add TODO for not allowing double account creation 2018-09-13 18:19:15 -03:00
Torsten Grote
c90a72617e Do not create two accounts when pressing enter for account creation
Fixes #1367
2018-09-13 18:18:30 -03:00
Torsten Grote
8813bc36af Correct startup database failure error messages 2018-09-13 12:35:39 -03:00
akwizgran
049cf3ad27 Merge branch 'optional-tests' into 'master'
Specify optional tests with an environment variable

See merge request briar/briar!916
2018-09-13 14:36:59 +00:00
Torsten Grote
de8a6b23e5 Merge branch '1189-setup-activity' into 'master'
Launch SetupActivity in same task to prevent relaunching from recent apps

Closes #1189

See merge request briar/briar!919
2018-09-13 14:21:24 +00:00
akwizgran
30193a240b Start SetupActivity in same task, finish other activities. 2018-09-13 13:43:01 +01:00
akwizgran
a52ad8b4cc Bump version numbers for 1.1.0 release. 2018-09-12 17:10:52 +01:00
Torsten Grote
6a1a8b6872 Merge branch '1245-enable-pin-lock' into 'master'
Enable sign-in reminder, PIN lock and dark theme for release builds

See merge request briar/briar!917
2018-09-12 11:15:12 +00:00
Torsten Grote
50ad42a0a2 Update translations, adds Hungarian, sets inclusion threshold to 80% 2018-09-12 07:45:02 -03:00
akwizgran
08005bdf56 Enable PIN lock for release builds. 2018-09-12 11:44:27 +01:00
akwizgran
e32cc3af6d Enable dark theme for release builds. 2018-09-12 11:41:54 +01:00
akwizgran
28a68ff625 Enable sign-in reminder for release builds. 2018-09-12 11:39:54 +01:00
akwizgran
2bef2ac828 Merge branch '1249-sign-in-screenshots' into 'master'
Screenshots for account sign-in improvements and Tor settings

See merge request briar/briar!909
2018-09-06 13:40:03 +00:00
akwizgran
b2febbc6e9 Specify optional tests with an environment variable. 2018-09-06 10:34:04 +01:00
Torsten Grote
e12601dd08 Merge branch 'attach-updated-settings-to-event' into 'master'
Attach updated settings to SettingsUpdatedEvent

See merge request briar/briar!913
2018-09-05 11:22:05 +00:00
akwizgran
3388682dda Use updated settings from event. 2018-09-05 12:04:56 +01:00
akwizgran
8ad3047f87 Merge branch '1247-pin-lock-fingerprint' into 'master'
Implement fingerprint unlocking with BiometricPromptCompat

See merge request briar/briar!882
2018-09-05 08:39:54 +00:00
akwizgran
0cffaf8646 Merge branch 'move-tor-bridge-tests' into 'master'
Move Tor Bridge tests and rename bramble-j2se to bramble-java

See merge request briar/briar!907
2018-09-05 08:35:33 +00:00
akwizgran
7b116f15df Attach updated settings to SettingsUpdatedEvent. 2018-09-05 09:31:12 +01:00
Torsten Grote
ced0f72fba Fix progress feel over messages in Conversation view
Unlike with many other lists,
we are not clearing the list of private messages when restarting the activity.
We still load the messages from the database and add them to the view.
When there are no new message to add,
the usual insert observers do not trigger
and we do not call list.showData() although we should.
Doing so removes the progress bar as soon as messages have been loaded.
2018-09-04 12:31:16 -03:00
Torsten Grote
24c030f06f Remove button from UnlockActivity 2018-09-04 09:32:24 -03:00
Torsten Grote
a3fa15e90e Blank UnlockActivity when not using fingerprint unlock 2018-09-04 09:04:59 -03:00
Torsten Grote
57841be447 Remove BiometricPromptCompat library and limit feature to API 28 2018-09-04 09:04:58 -03:00
Torsten Grote
c5d374af04 ScreenLock: Implement fingerprint unlocking with BiometricPromptCompat 2018-09-04 09:04:33 -03:00
Torsten Grote
8d592ad2ee Take screenshot of Tor settings 2018-09-03 18:03:57 -03:00
Torsten Grote
055c381cc9 Take a screenshot of the Navigation Drawer with lock action 2018-09-03 16:32:39 -03:00
Torsten Grote
1d259bd51c Screenshots for Sign-in improvements
Screenshots for #1249
2018-09-03 16:32:39 -03:00
Torsten Grote
de63141997 Update translations 2018-09-03 15:02:34 -03:00
Torsten Grote
dee8f68477 Do not run Tor bridge test with every CI run 2018-09-03 13:02:54 -03:00
Torsten Grote
59048f106a Move Tor Bridge tests and rename bramble-j2se to bramble-java 2018-09-03 12:58:20 -03:00
akwizgran
da7cf4af28 Rename bramble-j2se to bramble-java. 2018-09-03 16:28:59 +01:00
akwizgran
0d4cf4db68 Merge branch 'java-tor-plugin' into 'master'
Add a LinuxTorPlugin

See merge request briar/briar!902
2018-09-03 15:23:20 +00:00
Torsten Grote
9efd2d113a Ignore file extension when retrieving resources on Android 2018-09-03 11:58:42 -03:00
Torsten Grote
8e6cd12f07 LinuxTorPlugin: Address review comments 2018-09-03 11:52:10 -03:00
Torsten Grote
3a49ca0d97 Add JavaTorPlugin 2018-09-03 11:52:10 -03:00
akwizgran
c03868e800 Merge branch '1343-vanniktech-emoji' into 'master'
Use vanniktech emoji library

Closes #1343, #1314, #940, #930, #749, and #684

See merge request briar/briar!857
2018-09-03 12:12:01 +00:00
akwizgran
d6c129e919 Hide emoji popup when hiding soft keyboard. 2018-08-28 16:45:04 +01:00
akwizgran
271efdd2bc Hide soft keyboard when reblogging post. 2018-08-28 15:57:55 +01:00
akwizgran
ad4e8d51e9 Hide soft keyboard when sending blog post. 2018-08-28 15:55:16 +01:00
akwizgran
eb19c6e08d Remove unused resources. 2018-08-28 15:55:16 +01:00
akwizgran
83bfeb9075 Initialise EmojiManager for UI tests. 2018-08-28 15:55:16 +01:00
akwizgran
428501cf5f Use vanniktech emoji library. 2018-08-28 15:55:16 +01:00
Torsten Grote
d8b04edcd0 Merge branch '1240-avoid-raw-messages' into 'master'
Avoid raw messages

See merge request briar/briar!906
2018-08-27 14:40:54 +00:00
akwizgran
0bc07cd0c1 Rename message length method. 2018-08-24 16:56:24 +01:00
akwizgran
cb3026959a Remove raw messages from SyncRecordWriter interface. 2018-08-24 16:56:24 +01:00
akwizgran
48933637d8 Remove raw messages from DB interface. 2018-08-24 16:56:24 +01:00
akwizgran
5626f3d761 Remove raw message method from DatabaseComponent interface. 2018-08-24 16:56:23 +01:00
akwizgran
0fce224d88 Add method for getting cooked message from DB. 2018-08-24 16:56:23 +01:00
Torsten Grote
3db35f7061 Merge branch 'network-interfaces-may-be-null' into 'master'
Check whether getNetworkInterfaces() returns null

See merge request briar/briar!903
2018-08-24 15:48:22 +00:00
Torsten Grote
751375035d Merge branch 'message-constructor' into 'master'
Minimise use of message constructor

See merge request briar/briar!905
2018-08-24 14:58:57 +00:00
akwizgran
27a169c6e2 Minimise use of message constructor. 2018-08-24 14:17:25 +01:00
akwizgran
d4a4351786 Merge branch '758-db-exception-for-deleted-messages' into 'master'
Throw an exception if a deleted message is requested from the DB

Closes #758

See merge request briar/briar!904
2018-08-24 09:21:05 +00:00
akwizgran
fbd38dbb94 Throw an exception if a raw message has been deleted. 2018-08-23 14:51:56 +01:00
akwizgran
cd4897e6c9 Check whether getNetworkInterfaces() returns null. 2018-08-23 14:16:18 +01:00
akwizgran
d84e176bb4 Merge branch 'fix_performance_test_db' into 'master'
Fix the database performance tests

See merge request briar/briar!893
2018-08-22 15:46:11 +00:00
Torsten Grote
da8b49bec2 Merge branch 'log-relay-names' into 'master'
Log Tor relay names to detect failing bridges

See merge request briar/briar!901
2018-08-22 14:27:58 +00:00
akwizgran
6c8cc79d87 Log Tor relay names to detect failing bridges. 2018-08-22 14:21:41 +01:00
akwizgran
a5271eee29 Merge branch 'switch-preference-android-4' into 'master'
Use Material style for SwitchPreference on Android 4

See merge request briar/briar!897
2018-08-20 19:40:56 +00:00
akwizgran
4dfc96996d Merge branch '1224-show-explanation-when-contact-exchange-fails' into 'master'
Show an error fragment when contact exchange fails

See merge request briar/briar!890
2018-08-20 19:40:36 +00:00
akwizgran
3139f308a2 Merge branch '1349-empty-state-ui' into 'master'
Implement new empty state icons

Closes #1349

See merge request briar/briar!898
2018-08-20 19:39:56 +00:00
Torsten Grote
cc6daffa61 Merge branch 'update-bridges' into 'master'
Replace two failing bridges

See merge request briar/briar!900
2018-08-20 18:36:07 +00:00
Torsten Grote
f08f441f5f Use Material style for SwitchPreference on Android 4 2018-08-20 15:22:55 -03:00
Torsten Grote
83886c78f1 Empty states: Address review comments 2018-08-20 15:14:53 -03:00
Torsten Grote
5ed0e9efec Implement new empty state icons 2018-08-20 15:14:53 -03:00
akwizgran
169c59349e Merge branch '1269-bridge-setting' into 'master'
Refactor Tor settings and add a setting for forcing the use bridges

Closes #1269

See merge request briar/briar!895
2018-08-20 17:56:56 +00:00
akwizgran
764f60b3fe Replace two failing bridges. 2018-08-20 17:57:36 +01:00
Torsten Grote
e51c437a06 Merge branch 'ci-dev-urandom' into 'master'
Use /dev/urandom for CI

See merge request briar/briar!899
2018-08-20 16:24:49 +00:00
akwizgran
9fbf740ba7 Use /dev/urandom for tests. 2018-08-20 17:08:57 +01:00
akwizgran
db7686ea52 Merge branch '1247-pin-lock-activity-timeout' into 'master'
Screen Lock: Lock after customizable inactivity timeout

See merge request briar/briar!887
2018-08-20 13:52:23 +00:00
akwizgran
7fe21e079f Merge branch '1358-message-bubbles' into 'master'
New Design for Message Bubbles

Closes #1358

See merge request briar/briar!896
2018-08-20 12:11:22 +00:00
Torsten Grote
be72e624a3 ContactExchangeErrorFragment: Address review comments 2018-08-16 13:00:02 -03:00
Torsten Grote
d9e9741112 Replace generic ErrorFragment with specific one
when key agreement protocol doesn't match
2018-08-16 12:34:20 -03:00
Torsten Grote
656ca8d67a Contact failure: Add better icon and remove technical error message 2018-08-16 12:34:20 -03:00
Torsten Grote
d3e44358a4 Move feedback trigger and making link clickable to UiUtils 2018-08-16 12:34:20 -03:00
Torsten Grote
920a1d0431 Show an error fragment when contact exchange fails 2018-08-16 12:34:20 -03:00
Torsten Grote
4b9a9771f8 Tor settings: Address review comments 2018-08-16 12:27:26 -03:00
Torsten Grote
d64252aaf3 Screen Lock Timeout: Address review comments 2018-08-16 12:16:45 -03:00
Torsten Grote
825ed451a3 Screen lock: Add a fallback in case alarm manager didn't run during sleep 2018-08-16 12:14:59 -03:00
Torsten Grote
bffd78d404 Use a dedicated summary for 'never lock Briar' for proper English 2018-08-16 12:14:59 -03:00
Torsten Grote
04ffff0953 Screen Lock: Lock after customizable inactivity timeout 2018-08-16 12:14:59 -03:00
Torsten Grote
21f95ed9af Add a stroke for private message bubbles on Android 4 2018-08-16 12:07:54 -03:00
Torsten Grote
c8b516196c Add new private message bubbles, get rid of 9-patch drawables
This reverts commit f8a8c0d8b8.
2018-08-16 10:22:15 -03:00
goapunk
941a0cccc3 Fix a regression in the performance tests causing the db key to be regenerated everytime. 2018-08-16 12:09:33 +02:00
Torsten Grote
9b17836595 Refactor Tor settings and add a setting for forcing to use bridges 2018-08-15 17:32:43 -03:00
akwizgran
e5112ae9ee Merge branch 'gradle-witness' into 'master'
Move gradle witness dependency verification into dedicated files

See merge request briar/briar!892
2018-08-15 15:21:56 +00:00
Torsten Grote
f399ce9290 Use gradle wrapper for updating dependency pinning instead of local gradle 2018-08-15 12:01:13 -03:00
Torsten Grote
30e036c672 Move gradle witness dependency verification into dedicated files
This also adds a script for makes upgrading dependency checksums so much easier
2018-08-14 18:01:34 -03:00
akwizgran
2896700e50 Merge branch 'preference-switches' into 'master'
Replace CheckBoxPreference with the more standard SwitchPreference

See merge request briar/briar!891
2018-08-14 10:21:12 +00:00
akwizgran
987baba3bc Update settings.xml 2018-08-14 10:00:36 +00:00
akwizgran
03191ff08f Merge branch 'master' into 'preference-switches'
# Conflicts:
#   briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
2018-08-14 09:59:22 +00:00
akwizgran
42031631dd Merge branch '1247-pin-lock' into 'master'
Screen Lock Feature

See merge request briar/briar!870
2018-08-14 09:28:04 +00:00
Torsten Grote
64e30844b8 Screen Lock: Remember when keyguard was shown (for Android 6)
Also automatically unlock if device screenlock was removed.
2018-08-13 14:36:35 -03:00
Torsten Grote
30a070dd13 Replace CheckBoxPreference witht he more standard SwitchPreference 2018-08-13 13:57:28 -03:00
Torsten Grote
4f18303a1f Merge branch 'remove-unused-constants' into 'master'
Remove unused constants

See merge request briar/briar!889
2018-08-10 17:30:16 +00:00
Torsten Grote
5c500fb740 Merge branch 'back-facing-camera-not-required' into 'master'
Make back-facing camera optional in manifest

See merge request briar/briar!888
2018-08-10 16:30:29 +00:00
Torsten Grote
4d63272c04 Prevent activity loops when pressing back button while unlocking
This solution even works when "don't keep activities" is active
2018-08-10 13:28:43 -03:00
akwizgran
16b09b9380 Make back-facing camera optional in manifest. 2018-08-10 16:31:35 +01:00
akwizgran
a1599df712 Remove unused constants. 2018-08-10 15:04:08 +01:00
Torsten Grote
afa3c3a70e Screen Lock: Show verbose unlock message for older APIs 2018-08-10 07:44:10 -03:00
Torsten Grote
0f37a43415 Screen Lock: More changes due to code review 2018-08-10 07:44:10 -03:00
Torsten Grote
ef1d5d3233 Show lock icon when Briar is locked 2018-08-10 07:44:10 -03:00
Torsten Grote
feab825865 Don't show UnlockActivity anymore, might get removed completetly later 2018-08-10 07:44:10 -03:00
Torsten Grote
5d2c96f916 Remove LOCK button from foreground notification
When the user removes the screen lock, the app does not get really
locked. There is no way about getting notified about this. Before users
lock the app without it getting actually locked, we rather remove the
button that was collapsed and not easy to find anyway.
2018-08-10 07:44:10 -03:00
Torsten Grote
02ff37b187 Screen Lock: Second round of addressing review comments 2018-08-10 07:44:10 -03:00
Torsten Grote
6863727646 Upgrade robolectric to get Keyguard support for tests 2018-08-10 07:44:10 -03:00
Torsten Grote
087d6e9931 Screen Lock: Address first round of review comments 2018-08-10 07:44:10 -03:00
Torsten Grote
d79f1b667a Move app locking logic into dedicatd LockManager 2018-08-10 07:44:10 -03:00
Torsten Grote
633f5a8bd7 Adapt foreground notification when locked and show LOCK button 2018-08-10 07:44:10 -03:00
Torsten Grote
90cb9a2fae Disable screen lock setting instead of hiding it when not available 2018-08-10 07:44:10 -03:00
Torsten Grote
fc86319e13 MVP of PIN lock feature
This only shows the settings if a screen lock is available.
If the setting is activated, it shows a drawer item for locking.
Once locked, the screen lock secret needs to be entered to enter the
app again.

First part of #1247
2018-08-10 07:44:10 -03:00
Torsten Grote
af1ed292ae Merge branch '832-android-tor-plugin' into 'master'
Factor out Android-specific code from TorPlugin

Closes #832

See merge request briar/briar!876
2018-08-09 19:36:00 +00:00
Torsten Grote
5393127400 Merge branch 'show-blocked-country-names' into 'master'
Show names of countries where Tor is blocked

See merge request briar/briar!886
2018-08-09 13:21:22 +00:00
akwizgran
0e6c374d0e Show names of countries where Tor is blocked. 2018-08-09 13:55:06 +01:00
akwizgran
52efbcac8a Merge branch '1360-rename-main-flavor' into 'master'
Rename main flavor due to internal conflicts

Closes #1360

See merge request briar/briar!885
2018-08-09 08:58:24 +00:00
Torsten Grote
acf6a45004 Merge branch 'replace-assert-statements' into 'master'
Replace assert statements with AssertionErrors

See merge request briar/briar!877
2018-08-08 19:56:38 +00:00
Torsten Grote
7ffcace228 Rename Main Flavor due to internal conflicts 2018-08-08 16:52:28 -03:00
akwizgran
e157fdfc7b Merge branch '1251-dark-theme-old-message-bubbles' into 'master'
Dark Theme Changes

See merge request briar/briar!884
2018-08-08 15:18:50 +00:00
akwizgran
f8a8c0d8b8 Revert to old message bubbles pending design changes. 2018-08-08 10:35:05 +01:00
Torsten Grote
f53aeef0d6 Merge branch 'logger-names' into 'master'
Use full class names for loggers

See merge request briar/briar!881
2018-08-07 14:27:57 +00:00
akwizgran
f812acb00b Use general-purpose resource provider. 2018-08-07 15:19:46 +01:00
akwizgran
004467e84e Factor out remaining Android code from Tor plugin. 2018-08-07 15:19:43 +01:00
akwizgran
34c0a83e36 Use full class names for loggers. 2018-08-07 15:17:19 +01:00
Torsten Grote
fd0dad8936 Restore old button size and ensure timestamps are not selectable 2018-08-06 14:26:02 -03:00
Torsten Grote
32420a0781 Give names to colors and clean them up 2018-08-06 13:16:53 -03:00
Torsten Grote
b6c85c8bf6 More Dark Theme Changes after designer feedback 2018-08-06 13:16:53 -03:00
Torsten Grote
4163731ec3 New private message bubbles
This gets rid of all those pesky 9-Patch drawables
2018-08-06 13:16:53 -03:00
akwizgran
8e732d880f Merge branch '47-sign-in-reminder' into 'master'
Do not show sign-in reminder once PasswordActivity was opened

Closes #47

See merge request briar/briar!879
2018-08-06 09:38:05 +00:00
Torsten Grote
0b2594a693 Move SignIn reminder code into AndroidNotificationManager and don't show reminder once PasswordActivity was opened 2018-08-03 15:08:57 -03:00
akwizgran
7e009ceaf2 Merge branch '596-espresso' into 'master'
Setup UI Tests with Espresso for Automatic Localized Screenshots

Closes #596

See merge request briar/briar!863
2018-08-03 16:38:57 +00:00
Torsten Grote
b238b28ef9 Remove PasswordActivity test since it doesn't work anyway 2018-08-03 13:09:42 -03:00
Torsten Grote
edb8e8f9d0 Move res values from build.gradle into strings.xml
This fixes an issue where the build type values were overriding the
flavor values.
2018-08-03 13:08:18 -03:00
Torsten Grote
cc6041e90c Rename Component and Screenshot Tests 2018-08-03 11:42:01 -03:00
Torsten Grote
3ff6462899 Refactor Espresso tests to use new AccountManager 2018-08-03 11:20:43 -03:00
Torsten Grote
6f7d0c6f77 Do proper Doze white-listing in UI tests 2018-08-03 11:20:43 -03:00
Torsten Grote
412381f37e Move buildType to flavor and add hashes for pinning of androidTest dependencies 2018-08-03 11:20:33 -03:00
Torsten Grote
05fbb87c06 Add a NavDrawerActivityTest 2018-08-03 11:16:52 -03:00
Torsten Grote
daf5db470f Use demo mode when taking screenshots to clear status bar
https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/docs/demo_mode.md
2018-08-03 11:16:52 -03:00
Torsten Grote
be2d695150 Setup fastlane
This is great for automatically uploading (localized) screenshots
and app metadata to Google Play.
You can even upload the signed APK releases as well.

For now, this is only useful for running the screenshot Espresso tests
and grabbing the screenshots from the device.
2018-08-03 11:16:52 -03:00
Torsten Grote
d0c2c03057 First prototype of Espresso test infrastructure with automatic screenshoting 2018-08-03 11:16:52 -03:00
Torsten Grote
db11e0101a Merge branch '1355-disable-tor-setting' into 'master'
Add a setting to override location-based disabling of Tor

Closes #1355

See merge request briar/briar!871
2018-08-03 13:35:33 +00:00
akwizgran
25b8932cde Merge branch '47-sign-in-reminder' into 'master'
Don't show sign-in reminder if user is signed-in already

Closes #47

See merge request briar/briar!872
2018-08-03 10:59:25 +00:00
akwizgran
0d658513ba Disable bridges when network is manually enabled. 2018-08-03 11:53:50 +01:00
akwizgran
732bf6d4ec Show countries where Tor is blocked. 2018-08-03 11:53:50 +01:00
akwizgran
53762e7c93 Add setting to override location-based disabling of Tor. 2018-08-03 11:53:47 +01:00
akwizgran
5a145c9eb2 Replace assert statements with AssertionErrors. 2018-08-03 11:14:15 +01:00
akwizgran
d8ce1d75ca Add run configuration for bramble-android tests. 2018-08-03 10:17:36 +01:00
Torsten Grote
77b2fa8acb Merge branch '832-fix-bridge-test' into 'master'
Fix Tor bridge integration test

See merge request briar/briar!875
2018-08-02 15:00:57 +00:00
akwizgran
f9d5873385 Fix Tor bridge test. 2018-08-02 15:51:28 +01:00
Torsten Grote
1de6c863df Merge branch '832-network-manager' into 'master'
Factor network management code out of plugins

See merge request briar/briar!874
2018-08-02 14:36:17 +00:00
akwizgran
8c5c66fa9a Add null-safety and thread-safety annotations. 2018-08-02 15:06:17 +01:00
Torsten Grote
82f939ecd4 Don't show sign-in reminder if user is signed-in already 2018-08-02 09:50:42 -03:00
akwizgran
1a5c02f8a9 Remove extra logging. 2018-08-02 13:22:54 +01:00
akwizgran
16d56535ca Check connectivity after all AP state changes. 2018-08-02 13:22:53 +01:00
akwizgran
dcd6fda046 Check connectivity after entering or leaving doze mode. 2018-08-02 13:22:53 +01:00
akwizgran
2535445831 Factor network management code out of plugins. 2018-08-02 13:22:50 +01:00
Torsten Grote
c0d5a3a5ea Merge branch '1341-account-manager-refactoring' into 'master'
Refactor authentication and account management code

Closes #1341

See merge request briar/briar!866
2018-08-02 11:49:15 +00:00
akwizgran
c1789a8e52 Move identity creation into AccountManager. 2018-08-02 09:51:17 +01:00
akwizgran
2a0ecc3f80 Clean up some tests. 2018-08-01 16:49:14 +01:00
akwizgran
b176ec5844 Add TODO for account creation error handling. 2018-08-01 15:56:53 +01:00
akwizgran
f8df6b88ee Add BriarAccountManager subclass. 2018-08-01 15:52:09 +01:00
akwizgran
277d045469 Add hashes for test dependencies. 2018-07-27 16:04:57 +01:00
akwizgran
287f3760cd Pass database key into LifecycleManager. 2018-07-27 15:46:48 +01:00
akwizgran
58d09d0742 Add tests for AccountManager and AndroidAccountManager. 2018-07-27 15:29:42 +01:00
akwizgran
adbfa26364 Remove redundant locking. 2018-07-27 14:18:31 +01:00
akwizgran
abaefacb69 Add javadocs. 2018-07-27 13:15:04 +01:00
akwizgran
6ca0339da2 Move DB key management into account manager. 2018-07-27 13:15:03 +01:00
akwizgran
4a9977fa58 Use account manager to check whether account exists. 2018-07-27 13:15:03 +01:00
akwizgran
f9d8c720ec Remove ConfigController. 2018-07-27 13:15:03 +01:00
akwizgran
1edf2bfa75 Move account deletion into AccountManager. 2018-07-27 13:14:58 +01:00
akwizgran
233af69909 Add TODOs. 2018-07-27 13:14:58 +01:00
akwizgran
6f6ba38de1 Remove logic from DatabaseConfig. 2018-07-27 13:14:57 +01:00
akwizgran
f9495b49d6 Move encrypted key, account deletion into AccountManager. 2018-07-27 13:14:57 +01:00
akwizgran
cb29c9bf32 Create minimal AccountManager interface. 2018-07-27 13:14:52 +01:00
akwizgran
8283760e8a Move local author creation into IdentityManager. 2018-07-27 13:14:51 +01:00
426 changed files with 9537 additions and 6945 deletions

1
.gitignore vendored
View File

@@ -23,5 +23,6 @@ local.properties
!.idea/codeStyles
.gradle
build/
captures
*.iml
projectFilesBackup/

View File

@@ -11,8 +11,8 @@ test:
- .gradle/caches
script:
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon test
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test
after_script:
# these file change every time but should not be cached

View File

@@ -21,8 +21,9 @@
<method>
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-j2se" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
</method>
</configuration>
</component>
</component>

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-j2se" type="AndroidJUnit" factoryName="Android JUnit">
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-j2se" />
<module name="bramble-java" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
@@ -10,7 +10,7 @@
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-j2se" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">

View File

@@ -1,5 +1,6 @@
apply plugin: 'com.android.library'
apply plugin: 'witness'
apply from: 'witness.gradle'
android {
compileSdkVersion 27
@@ -8,8 +9,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10013
versionName "1.0.13"
versionCode 10101
versionName "1.1.1"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -27,98 +28,19 @@ configurations {
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation 'org.briarproject:jtorctl:0.3'
tor 'org.briarproject:tor-android:0.2.9.16@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification {
verify = [
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86',
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550',
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9',
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10',
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040',
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
]
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
}
project.afterEvaluate {

View File

@@ -1,25 +1,16 @@
package org.briarproject.bramble;
import android.app.Application;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module(includes = {
AndroidSystemModule.class
AndroidNetworkModule.class,
AndroidSystemModule.class,
CircumventionModule.class
})
public class BrambleAndroidModule {
@Provides
@Singleton
CircumventionProvider provideCircumventionProvider(Application app) {
return new CircumventionProviderImpl(app.getApplicationContext());
}
}

View File

@@ -0,0 +1,108 @@
package org.briarproject.bramble.account;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
class AndroidAccountManager extends AccountManagerImpl
implements AccountManager {
private static final Logger LOG =
Logger.getLogger(AndroidAccountManager.class.getName());
private static final String PREF_DB_KEY = "key";
protected final Context appContext;
private final SharedPreferences prefs;
@Inject
AndroidAccountManager(DatabaseConfig databaseConfig,
CryptoComponent crypto, IdentityManager identityManager,
SharedPreferences prefs, Application app) {
super(databaseConfig, crypto, identityManager);
this.prefs = prefs;
appContext = app.getApplicationContext();
}
// Locking: stateChangeLock
@Override
@Nullable
protected String loadEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = super.loadEncryptedDatabaseKey();
else migrateDatabaseKeyToFile(key);
return key;
}
// Locking: stateChangeLock
@Nullable
private String getDatabaseKeyFromPreferences() {
String key = prefs.getString(PREF_DB_KEY, null);
if (key == null) LOG.info("No database key in preferences");
else LOG.info("Found database key in preferences");
return key;
}
// Locking: stateChangeLock
private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) {
if (prefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
} else {
LOG.warning("Database key not migrated to file");
}
}
@Override
public void deleteAccount() {
synchronized (stateChangeLock) {
super.deleteAccount();
SharedPreferences defaultPrefs = getDefaultSharedPreferences();
deleteAppData(prefs, defaultPrefs);
}
}
// Package access for testing
SharedPreferences getDefaultSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(appContext);
}
// Locking: stateChangeLock
private void deleteAppData(SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(appContext.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child);
}
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
}

View File

@@ -0,0 +1,142 @@
package org.briarproject.bramble.network;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Level.INFO;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG =
Logger.getLogger(AndroidNetworkManager.class.getName());
// See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final Context appContext;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver networkStateReceiver = null;
@Inject
AndroidNetworkManager(@Scheduler ScheduledExecutorService scheduler,
EventBus eventBus, Application app) {
this.scheduler = scheduler;
this.eventBus = eventBus;
this.appContext = app.getApplicationContext();
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(ACTION_SCREEN_ON);
filter.addAction(ACTION_SCREEN_OFF);
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
appContext.registerReceiver(networkStateReceiver, filter);
}
@Override
public void stopService() {
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
}
@Override
public NetworkStatus getNetworkStatus() {
ConnectivityManager cm = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (cm == null) throw new AssertionError();
NetworkInfo net = cm.getActiveNetworkInfo();
boolean connected = net != null && net.isConnected();
boolean wifi = connected && net.getType() == TYPE_WIFI;
return new NetworkStatus(connected, wifi);
}
private void updateConnectionStatus() {
eventBus.broadcast(new NetworkStatusEvent(getNetworkStatus()));
}
private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) {
Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, delay, unit);
Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
updateConnectionStatus();
if (isSleepOrDozeEvent(action)) {
// Allow time for the network to be enabled or disabled
scheduleConnectionStatusUpdate(1, MINUTES);
} else if (isApEvent(action)) {
// The state change may be broadcast before the AP address is
// visible, so delay handling the event
scheduleConnectionStatusUpdate(5, SECONDS);
}
}
private boolean isSleepOrDozeEvent(@Nullable String action) {
boolean isSleep = ACTION_SCREEN_ON.equals(action) ||
ACTION_SCREEN_OFF.equals(action);
boolean isDoze = SDK_INT >= 23 &&
ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action);
return isSleep || isDoze;
}
private boolean isApEvent(@Nullable String action) {
return WIFI_AP_STATE_CHANGED_ACTION.equals(action);
}
}
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidNetworkModule {
@Provides
@Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
AndroidNetworkManager networkManager) {
lifecycleManager.registerService(networkManager);
return networkManager;
}
}

View File

@@ -1,15 +1,16 @@
package org.briarproject.bramble.plugin.tcp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
@@ -20,7 +21,6 @@ import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@@ -28,21 +28,13 @@ import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.WIFI_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
@NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin {
// See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private static final int WIFI_AP_STATE_ENABLED = 13;
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private static final byte[] WIFI_AP_ADDRESS_BYTES =
{(byte) 192, (byte) 168, 43, 1};
@@ -60,22 +52,20 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
}
}
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final Executor connectionStatusExecutor;
private final ConnectivityManager connectivityManager;
@Nullable
private final WifiManager wifiManager;
@Nullable
private volatile BroadcastReceiver networkStateReceiver = null;
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Backoff backoff, Context appContext, DuplexPluginCallback callback,
int maxLatency, int maxIdleTime) {
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
this.scheduler = scheduler;
this.appContext = appContext;
// Don't execute more than one connection status check at a time
connectionStatusExecutor =
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
ConnectivityManager connectivityManager = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager == null) throw new AssertionError();
@@ -89,19 +79,12 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
public void start() {
if (used.getAndSet(true)) throw new IllegalStateException();
running = true;
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
appContext.registerReceiver(networkStateReceiver, filter);
updateConnectionStatus();
}
@Override
public void stop() {
running = false;
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
tryToClose(socket);
}
@@ -120,7 +103,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
return singletonList(intToInetAddress(info.getIpAddress()));
// If we're running an access point, return its address
if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
return singletonList(WIFI_AP_ADDRESS);
return singletonList(WIFI_AP_ADDRESS);
// No suitable addresses
return emptyList();
}
@@ -152,21 +135,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
return SocketFactory.getDefault();
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
public void eventOccurred(Event e) {
if (e instanceof NetworkStatusEvent) updateConnectionStatus();
}
@Override
public void onReceive(Context ctx, Intent i) {
if (!running) return;
if (isApEnabledEvent(i)) {
// The state change may be broadcast before the AP address is
// visible, so delay handling the event
scheduler.schedule(this::handleConnectivityChange, 1, SECONDS);
} else {
handleConnectivityChange();
}
}
private void handleConnectivityChange() {
private void updateConnectionStatus() {
connectionStatusExecutor.execute(() -> {
if (!running) return;
Collection<InetAddress> addrs = getLocalIpAddresses();
if (addrs.contains(WIFI_AP_ADDRESS)) {
@@ -186,11 +161,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
socketFactory = getSocketFactory();
if (socket == null || socket.isClosed()) bind();
}
}
private boolean isApEnabledEvent(Intent i) {
return WIFI_AP_STATE_CHANGED_ACTION.equals(i.getAction()) &&
i.getIntExtra(EXTRA_WIFI_STATE, 0) == WIFI_AP_STATE_ENABLED;
}
});
}
}
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tcp;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -11,7 +12,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.concurrent.Immutable;
@@ -28,15 +28,14 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
private final Context appContext;
public AndroidLanTcpPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, BackoffFactory backoffFactory,
Context appContext) {
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
BackoffFactory backoffFactory, Context appContext) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
this.appContext = appContext;
}
@@ -55,7 +54,9 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new AndroidLanTcpPlugin(ioExecutor, scheduler, backoff,
appContext, callback, MAX_LATENCY, MAX_IDLE_TIME);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}
}

View File

@@ -0,0 +1,88 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.RenewableWakeLock;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.net.SocketFactory;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin {
// This tag may prevent Huawei's power manager from killing us
private static final String WAKE_LOCK_TAG = "LocationManagerService";
private final Context appContext;
private final RenewableWakeLock wakeLock;
AndroidTorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
assert pm != null;
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
}
@Override
protected int getProcessId() {
return android.os.Process.myPid();
}
@Override
protected long getLastUpdateTime() {
try {
PackageManager pm = appContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
return pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new AssertionError(e);
}
}
@Override
protected void enableNetwork(boolean enable) throws IOException {
if (!running) return;
if (enable) wakeLock.acquire();
super.enableNetwork(enable);
if (!enable) wakeLock.release();
}
@Override
public void stop() {
super.stop();
wakeLock.release();
}
}

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.os.Build;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -14,6 +15,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.AndroidUtils;
import java.util.concurrent.Executor;
@@ -25,10 +27,10 @@ import javax.net.SocketFactory;
@Immutable
@NotNullByDefault
public class TorPluginFactory implements DuplexPluginFactory {
public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG =
Logger.getLogger(TorPluginFactory.class.getName());
Logger.getLogger(AndroidTorPluginFactory.class.getName());
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
@@ -39,26 +41,30 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor,
public AndroidTorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
CircumventionProvider circumventionProvider,
Clock clock) {
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.clock = clock;
}
@@ -96,9 +102,10 @@ public class TorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, torSocketFactory, clock, backoff, callback,
architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -0,0 +1,32 @@
package org.briarproject.bramble.system;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.ResourceProvider;
import java.io.InputStream;
import javax.inject.Inject;
@NotNullByDefault
class AndroidResourceProvider implements ResourceProvider {
private final Context appContext;
@Inject
AndroidResourceProvider(Application app) {
this.appContext = app.getApplicationContext();
}
@Override
public InputStream getResourceInputStream(String name, String extension) {
Resources res = appContext.getResources();
// extension is ignored on Android, resources are retrieved without it
int resId =
res.getIdentifier(name, "raw", appContext.getPackageName());
return res.openRawResource(resId);
}
}

View File

@@ -1,9 +1,8 @@
package org.briarproject.bramble.system;
import android.app.Application;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import javax.inject.Singleton;
@@ -16,18 +15,26 @@ public class AndroidSystemModule {
@Provides
@Singleton
SecureRandomProvider provideSecureRandomProvider(Application app) {
return new AndroidSecureRandomProvider(app);
SecureRandomProvider provideSecureRandomProvider(
AndroidSecureRandomProvider provider) {
return provider;
}
@Provides
LocationUtils provideLocationUtils(Application app) {
return new AndroidLocationUtils(app);
LocationUtils provideLocationUtils(AndroidLocationUtils locationUtils) {
return locationUtils;
}
@Provides
@Singleton
AndroidExecutor provideAndroidExecutor(Application app) {
return new AndroidExecutorImpl(app);
AndroidExecutor provideAndroidExecutor(
AndroidExecutorImpl androidExecutor) {
return androidExecutor;
}
@Provides
@Singleton
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
return provider;
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.provider.Settings;
@@ -58,30 +57,6 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child);
}
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
public static File getReportDir(Context ctx) {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
}

View File

@@ -0,0 +1,162 @@
package org.briarproject.bramble.account;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.toHexString;
public class AndroidAccountManagerTest extends BrambleMockTestCase {
private final SharedPreferences prefs =
context.mock(SharedPreferences.class, "prefs");
private final SharedPreferences defaultPrefs =
context.mock(SharedPreferences.class, "defaultPrefs");
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final IdentityManager identityManager =
context.mock(IdentityManager.class);
private final SharedPreferences.Editor
editor = context.mock(SharedPreferences.Editor.class);
private final Application app;
private final ApplicationInfo applicationInfo;
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
private final File dbDir = new File(testDir, "db");
private AndroidAccountManager accountManager;
public AndroidAccountManagerTest() {
context.setImposteriser(ClassImposteriser.INSTANCE);
app = context.mock(Application.class);
applicationInfo = new ApplicationInfo();
applicationInfo.dataDir = testDir.getAbsolutePath();
}
@Before
public void setUp() {
context.checking(new Expectations() {{
allowing(databaseConfig).getDatabaseDirectory();
will(returnValue(dbDir));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
allowing(app).getApplicationContext();
will(returnValue(app));
}});
accountManager = new AndroidAccountManager(databaseConfig, crypto,
identityManager, prefs, app) {
@Override
SharedPreferences getDefaultSharedPreferences() {
return defaultPrefs;
}
};
}
@Test
public void testDbKeyIsMigratedFromPreferencesToFile() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(encryptedKeyHex));
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).remove("key");
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex,
accountManager.loadEncryptedDatabaseKey());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
}
@Test
public void testDeleteAccountClearsSharedPrefsAndDeletesFiles()
throws Exception {
// Directories 'lib' and 'shared_prefs' should be spared
File libDir = new File(testDir, "lib");
File libFile = new File(libDir, "file");
File sharedPrefsDir = new File(testDir, "shared_prefs");
File sharedPrefsFile = new File(sharedPrefsDir, "file");
// Directory 'cache' should be emptied
File cacheDir = new File(testDir, "cache");
File cacheFile = new File(cacheDir, "file");
// Other directories should be deleted
File potatoDir = new File(testDir, ".potato");
File potatoFile = new File(potatoDir, "file");
context.checking(new Expectations() {{
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).clear();
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
oneOf(defaultPrefs).edit();
will(returnValue(editor));
oneOf(editor).clear();
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
oneOf(app).getApplicationInfo();
will(returnValue(applicationInfo));
}});
assertTrue(dbDir.mkdirs());
assertTrue(keyDir.mkdirs());
assertTrue(libDir.mkdirs());
assertTrue(libFile.createNewFile());
assertTrue(sharedPrefsDir.mkdirs());
assertTrue(sharedPrefsFile.createNewFile());
assertTrue(cacheDir.mkdirs());
assertTrue(cacheFile.createNewFile());
assertTrue(potatoDir.mkdirs());
assertTrue(potatoFile.createNewFile());
accountManager.deleteAccount();
assertFalse(dbDir.exists());
assertFalse(keyDir.exists());
assertTrue(libDir.exists());
assertTrue(libFile.exists());
assertTrue(sharedPrefsDir.exists());
assertTrue(sharedPrefsFile.exists());
assertTrue(cacheDir.exists());
assertFalse(cacheFile.exists());
assertFalse(potatoDir.exists());
assertFalse(potatoFile.exists());
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}

View File

@@ -0,0 +1,91 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86',
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550',
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9',
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10',
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
]
}

View File

@@ -4,6 +4,7 @@ targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness'
apply from: 'witness.gradle'
dependencies {
implementation "com.google.dagger:dagger:2.0.2"
@@ -19,31 +20,6 @@ dependencies {
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}
// needed to make test output available to bramble-core and briar-core
configurations {
testOutput.extendsFrom(testCompile)

View File

@@ -0,0 +1,70 @@
package org.briarproject.bramble.api.account;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface AccountManager {
/**
* Returns true if the manager has the database key. This will be false
* before {@link #createAccount(String, String)} or {@link #signIn(String)}
* has been called, and true after {@link #createAccount(String, String)}
* or {@link #signIn(String)} has returned true, until the process exits.
*/
boolean hasDatabaseKey();
/**
* Returns the database key if the manager has it. This will be null
* before {@link #createAccount(String, String)} or {@link #signIn(String)}
* has been called, and non-null after
* {@link #createAccount(String, String)} or {@link #signIn(String)} has
* returned true, until the process exits.
*/
@Nullable
SecretKey getDatabaseKey();
/**
* Returns true if the encrypted database key can be loaded from disk, and
* the database directory exists and is a directory.
*/
boolean accountExists();
/**
* Creates an identity with the given name and registers it with the
* {@link IdentityManager}. Creates a database key, encrypts it with the
* given password and stores it on disk.
* <p/>
* This method does not create the database directory, so
* {@link #accountExists()} will continue to return false until the
* database directory is created.
*/
boolean createAccount(String name, String password);
/**
* Deletes all account state from disk. {@link #accountExists()} will
* return false after this method returns.
*/
void deleteAccount();
/**
* Loads the encrypted database key from disk and decrypts it with the
* given password.
*
* @return true if the database key was successfully loaded and decrypted.
*/
boolean signIn(String password);
/**
* Loads the encrypted database key from disk, decrypts it with the old
* password, encrypts it with the new password, and stores it on disk,
* replacing the old key.
*
* @return true if the database key was successfully loaded, re-encrypted
* and stored.
*/
boolean changePassword(String oldPassword, String newPassword);
}

View File

@@ -16,8 +16,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import java.security.GeneralSecurityException;
import java.util.Map;
import javax.annotation.Nullable;
@NotNullByDefault
public interface ClientHelper {
@@ -32,16 +30,12 @@ public interface ClientHelper {
Message createMessageForStoringMetadata(GroupId g);
@Nullable
Message getMessage(MessageId m) throws DbException;
@Nullable
Message getMessage(Transaction txn, MessageId m) throws DbException;
@Nullable
BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
@Nullable
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException;

View File

@@ -16,7 +16,7 @@ public interface ContactManager {
/**
* Registers a hook to be called whenever a contact is added or removed.
* This method should be called before
* {@link LifecycleManager#startServices(String)}.
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerContactHook(ContactHook hook);

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -44,7 +45,8 @@ public interface DatabaseComponent {
* @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated
*/
boolean open(@Nullable MigrationListener listener) throws DbException;
boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException;
/**
* Waits for any open transactions to finish and closes the database.
@@ -149,13 +151,13 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* Returns a batch of messages for the given contact, with a total length
* less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length.
*/
@Nullable
Collection<byte[]> generateBatch(Transaction txn, ContactId c,
Collection<Message> generateBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/**
@@ -176,14 +178,14 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* Returns a batch of messages for the given contact, with a total length
* less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Only messages that have been
* requested by the contact are returned. Returns null if there are no
* sendable messages that fit in the given length.
*/
@Nullable
Collection<byte[]> generateRequestedBatch(Transaction txn, ContactId c,
Collection<Message> generateRequestedBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/**
@@ -261,13 +263,22 @@ public interface DatabaseComponent {
*/
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(Transaction txn, MessageId m) throws DbException;
/**
* Returns the IDs of all delivered messages in the given group.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
throws DbException;
throws DbException;
/**
* Returns the IDs of any messages that need to be validated.
@@ -295,15 +306,6 @@ public interface DatabaseComponent {
Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(Transaction txn, MessageId m) throws DbException;
/**
* Returns the metadata for all delivered messages in the given group.
* <p/>
@@ -487,7 +489,7 @@ public interface DatabaseComponent {
* Removes the given transport keys from the database.
*/
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException;
throws DbException;
/**
* Marks the given contact as verified.
@@ -534,7 +536,7 @@ public interface DatabaseComponent {
* Marks the given transport keys as usable for outgoing streams.
*/
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
throws DbException;
throws DbException;
/**
* Stores the given transport keys, deleting any keys they have replaced.

View File

@@ -1,30 +1,15 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import javax.annotation.Nullable;
@NotNullByDefault
public interface DatabaseConfig {
boolean databaseExists();
File getDatabaseDirectory();
File getDatabaseKeyDirectory();
void setEncryptionKey(SecretKey key);
@Nullable
SecretKey getEncryptionKey();
void setLocalAuthorName(String nickname);
@Nullable
String getLocalAuthorName();
long getMaxSize();
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a message that has been deleted is requested from the database.
* This exception may occur due to concurrent updates and does not indicate a
* database error.
*/
public class MessageDeletedException extends DbException {
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
@@ -9,29 +10,40 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
public interface IdentityManager {
/**
* Stores the local pseudonym.
* Creates a local identity with the given name.
*/
void registerLocalAuthor(LocalAuthor a) throws DbException;
@CryptoExecutor
LocalAuthor createLocalAuthor(String name);
/**
* Returns the cached main local identity, non-blocking, or loads it from
* the db, blocking
* Registers the given local identity with the manager. The identity is
* not stored until {@link #storeLocalAuthor()} is called.
*/
void registerLocalAuthor(LocalAuthor a);
/**
* Stores the local identity registered with
* {@link #registerLocalAuthor(LocalAuthor)}, if any.
*/
void storeLocalAuthor() throws DbException;
/**
* Returns the cached local identity or loads it from the database.
*/
LocalAuthor getLocalAuthor() throws DbException;
/**
* Returns the cached main local identity, non-blocking, or loads it from
* the db, blocking, within the given Transaction.
* Returns the cached local identity or loads it from the database.
*/
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/**
* Returns the trust-level status of the author
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(AuthorId a) throws DbException;
/**
* Returns the trust-level status of the author
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;

View File

@@ -7,16 +7,6 @@ public interface KeyAgreementConstants {
*/
byte PROTOCOL_VERSION = 4;
/**
* The length of the record header in bytes.
*/
int RECORD_HEADER_LENGTH = 4;
/**
* The offset of the payload length in the record header, in bytes.
*/
int RECORD_HEADER_PAYLOAD_LENGTH_OFFSET = 2;
/**
* The length of the BQP key commitment in bytes.
*/

View File

@@ -1,13 +1,12 @@
package org.briarproject.bramble.api.lifecycle;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
/**
* Manages the lifecycle of the app, starting {@link Client Clients}, starting
* and stopping {@link Service Services}, shutting down
@@ -18,7 +17,7 @@ import javax.annotation.Nullable;
public interface LifecycleManager {
/**
* The result of calling {@link #startServices(String)}.
* The result of calling {@link #startServices(SecretKey)}.
*/
enum StartResult {
ALREADY_RUNNING,
@@ -44,28 +43,27 @@ public interface LifecycleManager {
/**
* Registers a {@link Service} to be started and stopped. This method
* should be called before {@link #startServices(String)}.
* should be called before {@link #startServices(SecretKey)}.
*/
void registerService(Service s);
/**
* Registers a {@link Client} to be started. This method should be called
* before {@link #startServices(String)}.
* before {@link #startServices(SecretKey)}.
*/
void registerClient(Client c);
/**
* Registers an {@link ExecutorService} to be shut down. This method
* should be called before {@link #startServices(String)}.
* should be called before {@link #startServices(SecretKey)}.
*/
void registerForShutdown(ExecutorService e);
/**
* Opens the {@link DatabaseComponent}, optionally creates a local author
* with the provided nickname, and starts any registered
* {@link Client Clients} and {@link Service Services}.
* Opens the {@link DatabaseComponent} using the given key and starts any
* registered {@link Client Clients} and {@link Service Services}.
*/
StartResult startServices(@Nullable String nickname);
StartResult startServices(SecretKey dbKey);
/**
* Stops any registered {@link Service Services}, shuts down any

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.network;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface NetworkManager {
NetworkStatus getNetworkStatus();
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.network;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class NetworkStatus {
private final boolean connected, wifi;
public NetworkStatus(boolean connected, boolean wifi) {
this.connected = connected;
this.wifi = wifi;
}
public boolean isConnected() {
return connected;
}
public boolean isWifi() {
return wifi;
}
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.bramble.api.network.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class NetworkStatusEvent extends Event {
private final NetworkStatus status;
public NetworkStatusEvent(NetworkStatus status) {
this.status = status;
}
public NetworkStatus getStatus() {
return status;
}
}

View File

@@ -12,11 +12,13 @@ public interface TorConstants {
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
String PREF_TOR_NETWORK = "network";
String PREF_TOR_NETWORK = "network2";
String PREF_TOR_PORT = "port";
String PREF_TOR_MOBILE = "useMobileData";
int PREF_TOR_NETWORK_NEVER = 0;
int PREF_TOR_NETWORK_WIFI = 1;
int PREF_TOR_NETWORK_ALWAYS = 2;
int PREF_TOR_NETWORK_AUTOMATIC = 0;
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
int PREF_TOR_NETWORK_NEVER = 3;
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.settings;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
@@ -11,6 +12,11 @@ public interface SettingsManager {
*/
Settings getSettings(String namespace) throws DbException;
/**
* Returns all settings in the given namespace.
*/
Settings getSettings(Transaction txn, String namespace) throws DbException;
/**
* Merges the given settings with any existing settings in the given
* namespace.

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.settings.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
import javax.annotation.concurrent.Immutable;
@@ -13,12 +14,18 @@ import javax.annotation.concurrent.Immutable;
public class SettingsUpdatedEvent extends Event {
private final String namespace;
private final Settings settings;
public SettingsUpdatedEvent(String namespace) {
public SettingsUpdatedEvent(String namespace, Settings settings) {
this.namespace = namespace;
this.settings = settings;
}
public String getNamespace() {
return namespace;
}
public Settings getSettings() {
return settings;
}
}

View File

@@ -50,7 +50,7 @@ public class Message {
/**
* Returns the length of the raw message in bytes.
*/
public int getLength() {
public int getRawLength() {
return raw.length;
}

View File

@@ -9,7 +9,7 @@ public interface SyncRecordWriter {
void writeAck(Ack a) throws IOException;
void writeMessage(byte[] raw) throws IOException;
void writeMessage(Message m) throws IOException;
void writeOffer(Offer o) throws IOException;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
@@ -35,7 +36,8 @@ public interface ValidationManager {
/**
* Registers the message validator for the given client. This method
* should be called before {@link LifecycleManager#startServices(String)}.
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
@@ -44,7 +46,7 @@ public interface ValidationManager {
* Registers the incoming message hook for the given client. The hook will
* be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(String)}.
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.InputStream;
@NotNullByDefault
public interface ResourceProvider {
InputStream getResourceInputStream(String name, String extension);
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.versioning;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -25,7 +26,7 @@ public interface ClientVersioningManager {
/**
* Registers a client that will be advertised to contacts. The hook will
* be called when the visibility of the client changes. This method should
* be called before {@link LifecycleManager#startServices(String)}.
* be called before {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerClient(ClientId clientId, int majorVersion, int minorVersion,
ClientVersioningHook hook);

View File

@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -40,6 +41,7 @@ public class TestUtils {
private static final AtomicInteger nextTestDir =
new AtomicInteger((int) (Math.random() * 1000 * 1000));
private static final Random random = new Random();
private static final long timestamp = System.currentTimeMillis();
public static File getTestDirectory() {
int name = nextTestDir.getAndIncrement();
@@ -101,9 +103,8 @@ public class TestUtils {
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
long created = System.currentTimeMillis();
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey,
created);
timestamp);
}
public static Author getAuthor() {
@@ -137,7 +138,6 @@ public class TestUtils {
public static Message getMessage(GroupId groupId, int rawLength) {
MessageId id = new MessageId(getRandomId());
byte[] raw = getRandomBytes(rawLength);
long timestamp = System.currentTimeMillis();
return new Message(id, groupId, timestamp, raw);
}
@@ -174,4 +174,10 @@ public class TestUtils {
Collection<? extends Number> samples) {
return Math.sqrt(getVariance(samples));
}
public static boolean isOptionalTestEnabled(Class testClass) {
String optionalTests = System.getenv("OPTIONAL_TESTS");
return optionalTests != null &&
asList(optionalTests.split(",")).contains(testClass.getName());
}
}

View File

@@ -0,0 +1,24 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}

View File

@@ -6,6 +6,7 @@ apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea'
apply plugin: 'witness'
apply from: 'witness.gradle'
dependencies {
implementation project(path: ':bramble-api', configuration: 'default')
@@ -14,6 +15,7 @@ dependencies {
implementation 'org.bitlet:weupnp:0.1.4'
implementation 'net.i2p.crypto:eddsa:0.2.0'
implementation 'org.whispersystems:curve25519-java:0.4.1'
implementation 'org.briarproject:jtorctl:0.3'
apt 'com.google.dagger:dagger-compiler:2.0.2'
@@ -31,40 +33,7 @@ dependencies {
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
]
}
// needed to make test output available to bramble-j2se
// needed to make test output available to bramble-java
configurations {
testOutput.extendsFrom(testCompile)
}

View File

@@ -0,0 +1,222 @@
package org.briarproject.bramble.account;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.util.IoUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AccountManagerImpl implements AccountManager {
private static final Logger LOG =
Logger.getLogger(AccountManagerImpl.class.getName());
private static final String DB_KEY_FILENAME = "db.key";
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
private final DatabaseConfig databaseConfig;
private final CryptoComponent crypto;
private final IdentityManager identityManager;
private final File dbKeyFile, dbKeyBackupFile;
final Object stateChangeLock = new Object();
@Nullable
private volatile SecretKey databaseKey = null;
@Inject
AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto,
IdentityManager identityManager) {
this.databaseConfig = databaseConfig;
this.crypto = crypto;
this.identityManager = identityManager;
File keyDir = databaseConfig.getDatabaseKeyDirectory();
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
}
@Override
public boolean hasDatabaseKey() {
return databaseKey != null;
}
@Override
@Nullable
public SecretKey getDatabaseKey() {
return databaseKey;
}
// Locking: stateChangeLock
@Nullable
protected String loadEncryptedDatabaseKey() {
String key = readDbKeyFromFile(dbKeyFile);
if (key == null) {
LOG.info("No database key in primary file");
key = readDbKeyFromFile(dbKeyBackupFile);
if (key == null) LOG.info("No database key in backup file");
else LOG.warning("Found database key in backup file");
} else {
LOG.info("Found database key in primary file");
}
return key;
}
// Locking: stateChangeLock
@Nullable
private String readDbKeyFromFile(File f) {
if (!f.exists()) {
LOG.info("Key file does not exist");
return null;
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(f), "UTF-8"));
String key = reader.readLine();
reader.close();
return key;
} catch (IOException e) {
logException(LOG, WARNING, e);
return null;
}
}
// Locking: stateChangeLock
protected boolean storeEncryptedDatabaseKey(String hex) {
LOG.info("Storing database key in file");
// Create the directory if necessary
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
LOG.info("Created database key directory");
// If only the backup file exists, rename it so we don't overwrite it
if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) {
if (dbKeyBackupFile.renameTo(dbKeyFile))
LOG.info("Renamed old backup");
else LOG.warning("Failed to rename old backup");
}
try {
// Write to the backup file
writeDbKeyToFile(hex, dbKeyBackupFile);
LOG.info("Stored database key in backup file");
// Delete the old primary file, if it exists
if (dbKeyFile.exists()) {
if (dbKeyFile.delete()) LOG.info("Deleted primary file");
else LOG.warning("Failed to delete primary file");
}
// The backup file becomes the new primary
if (dbKeyBackupFile.renameTo(dbKeyFile)) {
LOG.info("Renamed backup file to primary");
} else {
LOG.warning("Failed to rename backup file to primary");
return false; // Don't overwrite our only copy
}
// Write a second copy to the backup file
writeDbKeyToFile(hex, dbKeyBackupFile);
LOG.info("Stored second copy of database key in backup file");
return true;
} catch (IOException e) {
logException(LOG, WARNING, e);
return false;
}
}
// Locking: stateChangeLock
private void writeDbKeyToFile(String key, File f) throws IOException {
FileOutputStream out = new FileOutputStream(f);
out.write(key.getBytes("UTF-8"));
out.flush();
out.close();
}
@Override
public boolean accountExists() {
synchronized (stateChangeLock) {
return loadEncryptedDatabaseKey() != null
&& databaseConfig.getDatabaseDirectory().isDirectory();
}
}
@Override
public boolean createAccount(String name, String password) {
synchronized (stateChangeLock) {
// TODO don't allow creating another account if one already exists
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
identityManager.registerLocalAuthor(localAuthor);
SecretKey key = crypto.generateSecretKey();
if (!encryptAndStoreDatabaseKey(key, password)) return false;
databaseKey = key;
return true;
}
}
// Locking: stateChangeLock
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
byte[] plaintext = key.getBytes();
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
return storeEncryptedDatabaseKey(toHexString(ciphertext));
}
@Override
public void deleteAccount() {
synchronized (stateChangeLock) {
LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
}
}
@Override
public boolean signIn(String password) {
synchronized (stateChangeLock) {
SecretKey key = loadAndDecryptDatabaseKey(password);
if (key == null) return false;
databaseKey = key;
return true;
}
}
// Locking: stateChangeLock
@Nullable
private SecretKey loadAndDecryptDatabaseKey(String password) {
String hex = loadEncryptedDatabaseKey();
if (hex == null) {
LOG.warning("Failed to load encrypted database key");
return null;
}
byte[] ciphertext = fromHexString(hex);
byte[] plaintext = crypto.decryptWithPassword(ciphertext, password);
if (plaintext == null) {
LOG.info("Failed to decrypt database key");
return null;
}
return new SecretKey(plaintext);
}
@Override
public boolean changePassword(String oldPassword, String newPassword) {
synchronized (stateChangeLock) {
SecretKey key = loadAndDecryptDatabaseKey(oldPassword);
return key != null && encryptAndStoreDatabaseKey(key, newPassword);
}
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.bramble.account;
import org.briarproject.bramble.api.account.AccountManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AccountModule {
@Provides
@Singleton
AccountManager provideAccountManager(AccountManagerImpl accountManager) {
return accountManager;
}
}

View File

@@ -127,9 +127,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public Message getMessage(Transaction txn, MessageId m) throws DbException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
return messageFactory.createMessage(m, raw);
return db.getMessage(txn, m);
}
@Override
@@ -149,8 +147,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
byte[] raw = db.getMessage(txn, m).getRaw();
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
}

View File

@@ -2,9 +2,11 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -48,7 +50,8 @@ interface Database<T> {
* @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated
*/
boolean open(@Nullable MigrationListener listener) throws DbException;
boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException;
/**
* Prevents new transactions from starting, waits for all current
@@ -295,6 +298,15 @@ interface Database<T> {
*/
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(T txn, MessageId m) throws DbException;
/**
* Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state
@@ -462,15 +474,6 @@ interface Database<T> {
*/
long getNextSendTime(T txn, ContactId c) throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(T txn, MessageId m) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be sent to the
* given contact and have been requested by the contact, up to the given
@@ -641,7 +644,7 @@ interface Database<T> {
* Marks the given transport keys as usable for outgoing streams.
*/
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
throws DbException;
throws DbException;
/**
* Updates the transmission count and expiry time of the given message

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
@@ -103,9 +104,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public boolean open(@Nullable MigrationListener listener)
public boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException {
boolean reopened = db.open(listener);
boolean reopened = db.open(key, listener);
shutdown.addShutdownHook(() -> {
try {
close();
@@ -306,16 +307,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Collection<byte[]> generateBatch(Transaction transaction,
public Collection<Message> generateBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToSend(txn, c, maxLength);
List<byte[]> messages = new ArrayList<>(ids.size());
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m));
messages.add(db.getMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
@@ -355,7 +356,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Collection<byte[]> generateRequestedBatch(Transaction transaction,
public Collection<Message> generateRequestedBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
@@ -363,9 +364,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throw new NoSuchContactException();
Collection<MessageId> ids = db.getRequestedMessagesToSend(txn, c,
maxLength);
List<byte[]> messages = new ArrayList<>(ids.size());
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m));
messages.add(db.getMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
@@ -456,6 +457,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getLocalAuthors(txn);
}
@Override
public Message getMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getMessage(txn, m);
}
@Override
public Collection<MessageId> getMessageIds(Transaction transaction,
GroupId g) throws DbException {
@@ -486,16 +496,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getMessagesToShare(txn);
}
@Nullable
@Override
public byte[] getRawMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getRawMessage(txn, m);
}
@Override
public Map<MessageId, Metadata> getMessageMetadata(Transaction transaction,
GroupId g) throws DbException {
@@ -655,7 +655,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
merged.putAll(s);
if (!merged.equals(old)) {
db.mergeSettings(txn, s, namespace);
transaction.attach(new SettingsUpdatedEvent(namespace));
transaction.attach(new SettingsUpdatedEvent(namespace, merged));
}
}

View File

@@ -32,6 +32,9 @@ class H2Database extends JdbcDatabase {
private final DatabaseConfig config;
private final String url;
@Nullable
private volatile SecretKey key = null;
@Inject
H2Database(DatabaseConfig config, Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
@@ -44,11 +47,11 @@ class H2Database extends JdbcDatabase {
}
@Override
public boolean open(@Nullable MigrationListener listener)
public boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException {
boolean reopen = config.databaseExists();
if (!reopen) config.getDatabaseDirectory().mkdirs();
super.open("org.h2.Driver", reopen, listener);
this.key = key;
boolean reopen = !config.getDatabaseDirectory().mkdirs();
super.open("org.h2.Driver", reopen, key, listener);
return reopen;
}
@@ -63,7 +66,7 @@ class H2Database extends JdbcDatabase {
}
@Override
public long getFreeSpace() throws DbException {
public long getFreeSpace() {
File dir = config.getDatabaseDirectory();
long maxSize = config.getMaxSize();
long free = dir.getFreeSpace();
@@ -88,7 +91,7 @@ class H2Database extends JdbcDatabase {
@Override
protected Connection createConnection() throws SQLException {
SecretKey key = config.getEncryptionKey();
SecretKey key = this.key;
if (key == null) throw new IllegalStateException();
Properties props = new Properties();
props.setProperty("user", "user");

View File

@@ -33,6 +33,9 @@ class HyperSqlDatabase extends JdbcDatabase {
private final DatabaseConfig config;
private final String url;
@Nullable
private volatile SecretKey key = null;
@Inject
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
@@ -46,10 +49,11 @@ class HyperSqlDatabase extends JdbcDatabase {
}
@Override
public boolean open(@Nullable MigrationListener listener) throws DbException {
boolean reopen = config.databaseExists();
if (!reopen) config.getDatabaseDirectory().mkdirs();
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, listener);
public boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException {
this.key = key;
boolean reopen = !config.getDatabaseDirectory().mkdirs();
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener);
return reopen;
}
@@ -93,7 +97,7 @@ class HyperSqlDatabase extends JdbcDatabase {
@Override
protected Connection createConnection() throws SQLException {
SecretKey key = config.getEncryptionKey();
SecretKey key = this.key;
if (key == null) throw new IllegalStateException();
String hex = StringUtils.toHexString(key.getBytes());
return DriverManager.getConnection(url + ";crypt_key=" + hex);

View File

@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -328,7 +329,7 @@ abstract class JdbcDatabase implements Database<Connection> {
this.clock = clock;
}
protected void open(String driverClass, boolean reopen,
protected void open(String driverClass, boolean reopen, SecretKey key,
@Nullable MigrationListener listener) throws DbException {
// Load the JDBC driver
try {
@@ -740,7 +741,7 @@ abstract class JdbcDatabase implements Database<Connection> {
boolean offered = removeOfferedMessage(txn, c, m.getId());
boolean seen = offered || (sender != null && c.equals(sender));
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
m.getLength(), state, e.getValue(), messageShared,
m.getRawLength(), state, e.getValue(), messageShared,
false, seen);
}
// Update denormalised column in messageDependencies if dependency
@@ -1482,6 +1483,32 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public Message getMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT groupId, timestamp, raw FROM messages"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1));
long timestamp = rs.getLong(2);
byte[] raw = rs.getBytes(3);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (raw == null) throw new MessageDeletedException();
return new Message(m, g, timestamp, raw);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override
public Collection<MessageId> getMessageIds(Connection txn, GroupId g)
throws DbException {
@@ -2018,30 +2045,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
@Nullable
public byte[] getRawMessage(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT raw FROM messages WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] raw = rs.getBytes(1);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return raw;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
ContactId c, int maxLength) throws DbException {

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -21,6 +24,8 @@ import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.Author.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
@ThreadSafe
@NotNullByDefault
@@ -30,25 +35,51 @@ class IdentityManagerImpl implements IdentityManager {
Logger.getLogger(IdentityManagerImpl.class.getName());
private final DatabaseComponent db;
private final CryptoComponent crypto;
private final AuthorFactory authorFactory;
// The local author is immutable so we can cache it
@Nullable
private volatile LocalAuthor cachedAuthor;
@Inject
IdentityManagerImpl(DatabaseComponent db) {
IdentityManagerImpl(DatabaseComponent db, CryptoComponent crypto,
AuthorFactory authorFactory) {
this.db = db;
this.crypto = crypto;
this.authorFactory = authorFactory;
}
@Override
public void registerLocalAuthor(LocalAuthor localAuthor)
throws DbException {
public LocalAuthor createLocalAuthor(String name) {
long start = now();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name,
publicKey, privateKey);
logDuration(LOG, "Creating local author", start);
return localAuthor;
}
@Override
public void registerLocalAuthor(LocalAuthor a) {
cachedAuthor = a;
LOG.info("Local author registered");
}
@Override
public void storeLocalAuthor() throws DbException {
LocalAuthor cached = cachedAuthor;
if (cached == null) {
LOG.info("No local author to store");
return;
}
Transaction txn = db.startTransaction(false);
try {
db.addLocalAuthor(txn, localAuthor);
db.addLocalAuthor(txn, cached);
db.commitTransaction(txn);
cachedAuthor = localAuthor;
LOG.info("Local author registered");
LOG.info("Local author stored");
} finally {
db.endTransaction(txn);
}

View File

@@ -102,6 +102,7 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
KeyAgreementTransport transport =
connector.connect(remotePayload, alice);
if (transport == null) {
LOG.warning("Key agreement failed. Transport was null.");
// Notify caller that the connection failed
eventBus.broadcast(new KeyAgreementFailedEvent());
return;

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.lifecycle;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseComponent;
@@ -9,9 +8,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.lifecycle.ServiceException;
@@ -26,7 +23,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
@@ -60,8 +56,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
private final List<Service> services;
private final List<Client> clients;
private final List<ExecutorService> executors;
private final CryptoComponent crypto;
private final AuthorFactory authorFactory;
private final IdentityManager identityManager;
private final Semaphore startStopSemaphore = new Semaphore(1);
private final CountDownLatch dbLatch = new CountDownLatch(1);
@@ -72,12 +66,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
@Inject
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
CryptoComponent crypto, AuthorFactory authorFactory,
IdentityManager identityManager) {
this.db = db;
this.eventBus = eventBus;
this.crypto = crypto;
this.authorFactory = authorFactory;
this.identityManager = identityManager;
services = new CopyOnWriteArrayList<>();
clients = new CopyOnWriteArrayList<>();
@@ -104,25 +95,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
executors.add(e);
}
private LocalAuthor createLocalAuthor(String nickname) {
long start = now();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory
.createLocalAuthor(nickname, publicKey, privateKey);
logDuration(LOG, "Creating local author", start);
return localAuthor;
}
private void registerLocalAuthor(LocalAuthor author) throws DbException {
long start = now();
identityManager.registerLocalAuthor(author);
logDuration(LOG, "Registering local author", start);
}
@Override
public StartResult startServices(@Nullable String nickname) {
public StartResult startServices(SecretKey dbKey) {
if (!startStopSemaphore.tryAcquire()) {
LOG.info("Already starting or stopping");
return ALREADY_RUNNING;
@@ -131,13 +105,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
LOG.info("Starting services");
long start = now();
boolean reopened = db.open(this);
boolean reopened = db.open(dbKey, this);
if (reopened) logDuration(LOG, "Reopening database", start);
else logDuration(LOG, "Creating database", start);
if (nickname != null) {
registerLocalAuthor(createLocalAuthor(nickname));
}
identityManager.storeLocalAuthor();
state = STARTING_SERVICES;
dbLatch.countDown();

View File

@@ -1,10 +1,5 @@
package org.briarproject.bramble.lifecycle;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
@@ -54,11 +49,9 @@ public class LifecycleModule {
@Provides
@Singleton
LifecycleManager provideLifecycleManager(DatabaseComponent db,
EventBus eventBus, CryptoComponent crypto,
AuthorFactory authorFactory, IdentityManager identityManager) {
return new LifecycleManagerImpl(db, eventBus, crypto, authorFactory,
identityManager);
LifecycleManager provideLifecycleManager(
LifecycleManagerImpl lifecycleManager) {
return lifecycleManager;
}
@Provides

View File

@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.util.StringUtils;
@@ -146,16 +147,15 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
updateProperties();
running = true;
loadSettings();
loadSettings(callback.getSettings());
if (shouldAllowContactConnections()) {
if (isAdapterEnabled()) bind();
else enableAdapter();
}
}
private void loadSettings() {
contactConnections =
callback.getSettings().getBoolean(PREF_BT_ENABLE, false);
private void loadSettings(Settings settings) {
contactConnections = settings.getBoolean(PREF_BT_ENABLE, false);
}
private boolean shouldAllowContactConnections() {
@@ -387,7 +387,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString()))
ioExecutor.execute(this::onSettingsUpdated);
ioExecutor.execute(() -> onSettingsUpdated(s.getSettings()));
} else if (e instanceof KeyAgreementListeningEvent) {
ioExecutor.execute(connectionLimiter::keyAgreementStarted);
} else if (e instanceof KeyAgreementStoppedListeningEvent) {
@@ -395,9 +395,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
}
private void onSettingsUpdated() {
private void onSettingsUpdated(Settings settings) {
boolean wasAllowed = shouldAllowContactConnections();
loadSettings();
loadSettings(settings);
boolean isAllowed = shouldAllowContactConnections();
if (wasAllowed && !isAllowed) {
LOG.info("Contact connections disabled");

View File

@@ -24,7 +24,7 @@ import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -35,6 +35,9 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.emptyList;
import static java.util.Collections.list;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -303,16 +306,16 @@ abstract class TcpPlugin implements DuplexPlugin {
}
Collection<InetAddress> getLocalIpAddresses() {
List<NetworkInterface> ifaces;
try {
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
Enumeration<NetworkInterface> ifaces = getNetworkInterfaces();
if (ifaces == null) return emptyList();
List<InetAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : list(ifaces))
addrs.addAll(list(iface.getInetAddresses()));
return addrs;
} catch (SocketException e) {
logException(LOG, WARNING, e);
return Collections.emptyList();
return emptyList();
}
List<InetAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : ifaces)
addrs.addAll(Collections.list(iface.getInetAddresses()));
return addrs;
}
}

View File

@@ -0,0 +1,17 @@
package org.briarproject.bramble.plugin.tor;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class CircumventionModule {
@Provides
@Singleton
CircumventionProvider provideCircumventionProvider(
CircumventionProviderImpl provider) {
return provider;
}
}

View File

@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.util.List;
// TODO: Create a module for this so it doesn't have to be public
public interface CircumventionProvider {
/**

View File

@@ -1,13 +1,9 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.content.res.Resources;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
@@ -16,24 +12,24 @@ import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
public class CircumventionProviderImpl implements CircumventionProvider {
import static java.util.Arrays.asList;
class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges";
private final Context ctx;
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(asList(BRIDGES));
@Nullable
private volatile List<String> bridges = null;
@Inject
public CircumventionProviderImpl(Context ctx) {
this.ctx = ctx;
CircumventionProviderImpl() {
}
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BRIDGES));
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
@@ -47,15 +43,14 @@ public class CircumventionProviderImpl implements CircumventionProvider {
@Override
@IoExecutor
public List<String> getBridges() {
if (this.bridges != null) return this.bridges;
List<String> bridges = this.bridges;
if (bridges != null) return new ArrayList<>(bridges);
Resources res = ctx.getResources();
int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
ctx.getPackageName());
InputStream is = ctx.getResources().openRawResource(resId);
InputStream is = getClass().getClassLoader()
.getResourceAsStream(BRIDGE_FILE_NAME);
Scanner scanner = new Scanner(is);
List<String> bridges = new ArrayList<>();
bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (!line.startsWith("#")) bridges.add(line);

View File

@@ -1,17 +1,5 @@
package org.briarproject.bramble.plugin.tor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection;
@@ -21,6 +9,9 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -35,8 +26,8 @@ import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.RenewableWakeLock;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable;
@@ -59,10 +50,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
@@ -70,27 +58,17 @@ import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WITH_BRIDGES;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -98,7 +76,10 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final Logger LOG =
Logger.getLogger(TorPlugin.class.getName());
private static final String[] EVENTS = {
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
@@ -107,14 +88,9 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final int COOKIE_TIMEOUT_MS = 3000;
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
// This tag may prevent Huawei's power manager from killing us
private static final String WAKE_LOCK_TAG = "LocationManagerService";
private static final Logger LOG =
Logger.getLogger(TorPlugin.class.getName());
private final Executor ioExecutor, connectionStatusExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final SocketFactory torSocketFactory;
private final Clock clock;
@@ -122,55 +98,55 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final DuplexPluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile;
private final RenewableWakeLock wakeLock;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final ConnectionStatus connectionStatus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false;
private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
private volatile BroadcastReceiver networkStateReceiver = null;
private volatile Settings settings = null;
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) {
protected volatile boolean running = false;
protected abstract int getProcessId();
protected abstract long getLastUpdateTime();
TorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, File torDirectory) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.torSocketFactory = torSocketFactory;
this.clock = clock;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
this.circumventionProvider = circumventionProvider;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
socketTimeout = Integer.MAX_VALUE;
else socketTimeout = maxIdleTime * 2;
connectionStatus = new ConnectionStatus();
torDirectory = appContext.getDir("tor", MODE_PRIVATE);
this.torDirectory = torDirectory;
torFile = new File(torDirectory, "tor");
geoIpFile = new File(torDirectory, "geoip");
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
connectionStatus = new ConnectionStatus();
// Don't execute more than one connection status check at a time
connectionStatusExecutor = new PoliteExecutor("TorPlugin",
ioExecutor, 1);
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
connectionStatusExecutor =
new PoliteExecutor("TorPlugin", ioExecutor, 1);
}
@Override
@@ -191,15 +167,25 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException();
if (!torDirectory.exists()) {
if (!torDirectory.mkdirs()) {
LOG.warning("Could not create Tor directory.");
throw new PluginException();
}
}
// Load the settings
settings = callback.getSettings();
// Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets();
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Migrate old settings before having a chance to stop
migrateSettings();
// Start a new Tor process
LOG.info("Starting Tor");
String torPath = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid());
String pid = String.valueOf(getProcessId());
Process torProcess;
ProcessBuilder pb =
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
@@ -271,26 +257,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} catch (IOException e) {
throw new PluginException(e);
}
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(ACTION_SCREEN_ON);
filter.addAction(ACTION_SCREEN_OFF);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
appContext.registerReceiver(networkStateReceiver, filter);
// Check whether we're online
updateConnectionStatus(networkManager.getNetworkStatus());
// Bind a server socket to receive incoming hidden service connections
bind();
}
private boolean assetsAreUpToDate() {
try {
PackageManager pm = appContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
return doneFile.lastModified() > pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
return doneFile.lastModified() > getLastUpdateTime();
}
private void installAssets() throws PluginException {
@@ -323,29 +297,23 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private InputStream getTorInputStream() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing Tor binary for " + architecture);
int resId = getResourceId("tor_" + architecture);
InputStream in = appContext.getResources().openRawResource(resId);
InputStream in = resourceProvider
.getResourceInputStream("tor_" + architecture, ".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getGeoIpInputStream() throws IOException {
int resId = getResourceId("geoip");
InputStream in = appContext.getResources().openRawResource(resId);
InputStream in = resourceProvider.getResourceInputStream("geoip",
".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getConfigInputStream() {
int resId = getResourceId("torrc");
return appContext.getResources().openRawResource(resId);
}
private int getResourceId(String filename) {
Resources res = appContext.getResources();
return res.getIdentifier(filename, "raw", appContext.getPackageName());
return getClass().getClassLoader().getResourceAsStream("torrc");
}
private void tryToClose(@Nullable Closeable c) {
@@ -392,7 +360,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void bind() {
ioExecutor.execute(() -> {
// If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get(PREF_TOR_PORT);
String portString = settings.get(PREF_TOR_PORT);
int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString);
@@ -437,7 +405,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void publishHiddenService(String port) {
if (!running) return;
LOG.info("Creating hidden service");
String privKey = callback.getSettings().get(HS_PRIVKEY);
String privKey = settings.get(HS_PRIVKEY);
Map<Integer, String> portLines =
Collections.singletonMap(80, "127.0.0.1:" + port);
Map<String, String> response;
@@ -491,15 +459,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
private void enableNetwork(boolean enable) throws IOException {
protected void enableNetwork(boolean enable) throws IOException {
if (!running) return;
if (enable) wakeLock.acquire();
connectionStatus.enableNetwork(enable);
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
if (!enable) {
callback.transportDisabled();
wakeLock.release();
}
if (!enable) callback.transportDisabled();
}
private void enableBridges(boolean enable) throws IOException {
@@ -517,8 +481,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
public void stop() {
running = false;
tryToClose(socket);
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
if (controlSocket != null && controlConnection != null) {
try {
LOG.info("Stopping Tor");
@@ -529,7 +491,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
logException(LOG, WARNING, e);
}
}
wakeLock.release();
}
@Override
@@ -627,9 +588,12 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
if (status.equals("CLOSED") || status.equals("FAILED"))
updateConnectionStatus(); // Check whether we've lost connectivity
if (LOG.isLoggable(INFO))
LOG.info("OR connection " + status + " " + orName);
if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus());
}
}
@Override
@@ -662,24 +626,27 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) {
LOG.info("Tor settings updated");
updateConnectionStatus();
settings = s.getSettings();
updateConnectionStatus(networkManager.getNetworkStatus());
}
} else if (e instanceof NetworkStatusEvent) {
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
}
}
private void updateConnectionStatus() {
private void updateConnectionStatus(NetworkStatus status) {
connectionStatusExecutor.execute(() -> {
if (!running) return;
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
boolean online = status.isConnected();
boolean wifi = status.isWifi();
String country = locationUtils.getCurrentCountry();
boolean blocked =
circumventionProvider.isTorProbablyBlocked(country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
int network = settings.getInt(PREF_TOR_NETWORK,
PREF_TOR_NETWORK_AUTOMATIC);
boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true);
boolean bridgesWork = circumventionProvider.doBridgesWork(country);
boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC;
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi);
@@ -691,21 +658,20 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
} else if (network == PREF_TOR_NETWORK_NEVER ||
(!useMobile && !wifi)) {
LOG.info("Disabling network due to setting");
enableNetwork(false);
} else if (blocked) {
if (circumventionProvider.doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
}
} else if (automatic && blocked && !bridgesWork) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
(automatic && bridgesWork)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Enabling network");
LOG.info("Enabling network, not using bridges");
enableBridges(false);
enableNetwork(true);
}
@@ -715,27 +681,19 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
});
}
private void scheduleConnectionStatusUpdate() {
Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, 1, MINUTES);
Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
if (!running) return;
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
updateConnectionStatus();
if (ACTION_SCREEN_ON.equals(action)
|| ACTION_SCREEN_OFF.equals(action)) {
scheduleConnectionStatusUpdate();
}
// TODO remove when sufficient time has passed. Added 2018-08-15
private void migrateSettings() {
Settings sOld = callback.getSettings();
int oldNetwork = sOld.getInt("network", -1);
if (oldNetwork == -1) return;
Settings s = new Settings();
if (oldNetwork == 0) {
s.putInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_NEVER);
} else if (oldNetwork == 1) {
s.putBoolean(PREF_TOR_MOBILE, false);
}
s.putInt("network", -1);
callback.mergeSettings(s);
}
private static class ConnectionStatus {

View File

@@ -164,7 +164,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getMessageAsList(txn,
e.getValue().messageId);
if (message == null) throw new DbException();
local.put(e.getKey(), parseProperties(message));
}
return local;
@@ -187,7 +186,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest local properties
BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId);
if (message == null) throw new DbException();
p = parseProperties(message);
}
db.commitTransaction(txn);
@@ -227,7 +225,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest remote properties
BdfList message =
clientHelper.getMessageAsList(txn, latest.messageId);
if (message == null) throw new DbException();
return parseProperties(message);
} catch (FormatException e) {
throw new DbException(e);
@@ -265,7 +262,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
} else {
BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId);
if (message == null) throw new DbException();
TransportProperties old = parseProperties(message);
merged = new TransportProperties(old);
merged.putAll(p);

View File

@@ -34,6 +34,12 @@ class SettingsManagerImpl implements SettingsManager {
return s;
}
@Override
public Settings getSettings(Transaction txn, String namespace)
throws DbException {
return db.getSettings(txn, namespace);
}
@Override
public void mergeSettings(Settings s, String namespace) throws DbException {
Transaction txn = db.startTransaction(false);

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
@@ -274,7 +275,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateBatchQueued.getAndSet(false))
throw new AssertionError();
try {
Collection<byte[]> b;
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateRequestedBatch(txn, contactId,
@@ -296,9 +297,9 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private class WriteBatch implements ThrowingRunnable<IOException> {
private final Collection<byte[]> batch;
private final Collection<Message> batch;
private WriteBatch(Collection<byte[]> batch) {
private WriteBatch(Collection<Message> batch) {
this.batch = batch;
}
@@ -306,7 +307,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
@Override
public void run() throws IOException {
if (interrupted) return;
for (byte[] raw : batch) recordWriter.writeMessage(raw);
for (Message m : batch) recordWriter.writeMessage(m);
LOG.info("Sent batch");
generateBatch();
}

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.transport.StreamWriter;
@@ -171,7 +172,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
Collection<byte[]> b;
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateBatch(txn, contactId,
@@ -193,9 +194,9 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private class WriteBatch implements ThrowingRunnable<IOException> {
private final Collection<byte[]> batch;
private final Collection<Message> batch;
private WriteBatch(Collection<byte[]> batch) {
private WriteBatch(Collection<Message> batch) {
this.batch = batch;
}
@@ -203,7 +204,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
@Override
public void run() throws IOException {
if (interrupted) return;
for (byte[] raw : batch) recordWriter.writeMessage(raw);
for (Message m : batch) recordWriter.writeMessage(m);
LOG.info("Sent batch");
dbExecutor.execute(new GenerateBatch());
}

View File

@@ -46,7 +46,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
}
private void readRecord() throws IOException {
assert nextRecord == null;
if (nextRecord != null) throw new AssertionError();
while (true) {
nextRecord = reader.readRecord();
// Check the protocol version
@@ -62,7 +62,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
}
private byte getNextRecordType() {
assert nextRecord != null;
if (nextRecord == null) throw new AssertionError();
return nextRecord.getRecordType();
}
@@ -100,7 +100,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
}
private List<MessageId> readMessageIds() throws IOException {
assert nextRecord != null;
if (nextRecord == null) throw new AssertionError();
byte[] payload = nextRecord.getPayload();
if (payload.length == 0) throw new FormatException();
if (payload.length % UniqueId.LENGTH != 0) throw new FormatException();
@@ -122,7 +122,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
@Override
public Message readMessage() throws IOException {
if (!hasMessage()) throw new FormatException();
assert nextRecord != null;
if (nextRecord == null) throw new AssertionError();
byte[] payload = nextRecord.getPayload();
if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException();
// Validate timestamp

View File

@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.record.Record;
import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
@@ -44,8 +45,8 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
}
@Override
public void writeMessage(byte[] raw) throws IOException {
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
public void writeMessage(Message m) throws IOException {
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, m.getRaw()));
}
@Override

View File

@@ -16,7 +16,6 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
@@ -52,7 +51,6 @@ class ValidationManagerImpl implements ValidationManager, Service,
private final DatabaseComponent db;
private final Executor dbExecutor, validationExecutor;
private final MessageFactory messageFactory;
private final Map<ClientMajorVersion, MessageValidator> validators;
private final Map<ClientMajorVersion, IncomingMessageHook> hooks;
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -60,12 +58,10 @@ class ValidationManagerImpl implements ValidationManager, Service,
@Inject
ValidationManagerImpl(DatabaseComponent db,
@DatabaseExecutor Executor dbExecutor,
@ValidationExecutor Executor validationExecutor,
MessageFactory messageFactory) {
@ValidationExecutor Executor validationExecutor) {
this.db = db;
this.dbExecutor = dbExecutor;
this.validationExecutor = validationExecutor;
this.messageFactory = messageFactory;
validators = new ConcurrentHashMap<>();
hooks = new ConcurrentHashMap<>();
}
@@ -128,9 +124,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
Transaction txn = db.startTransaction(true);
try {
MessageId id = unvalidated.poll();
byte[] raw = db.getRawMessage(txn, id);
if (raw == null) throw new DbException();
m = messageFactory.createMessage(id, raw);
m = db.getMessage(txn, id);
g = db.getGroup(txn, m.getGroupId());
db.commitTransaction(txn);
} finally {
@@ -197,9 +191,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
invalidateMessage(txn, id);
invalidate = getDependentsToInvalidate(txn, id);
} else if (allDelivered) {
byte[] raw = db.getRawMessage(txn, id);
if (raw == null) throw new DbException();
Message m = messageFactory.createMessage(id, raw);
Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
ClientId c = g.getClientId();
int majorVersion = g.getMajorVersion();

View File

@@ -7,13 +7,15 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Properties;
import javax.annotation.concurrent.Immutable;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.list;
@Immutable
@NotNullByDefault
abstract class AbstractSecureRandomProvider implements SecureRandomProvider {
@@ -23,13 +25,14 @@ abstract class AbstractSecureRandomProvider implements SecureRandomProvider {
out.writeLong(System.currentTimeMillis());
out.writeLong(System.nanoTime());
out.writeLong(Runtime.getRuntime().freeMemory());
List<NetworkInterface> ifaces =
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface i : ifaces) {
List<InetAddress> addrs = Collections.list(i.getInetAddresses());
for (InetAddress a : addrs) out.write(a.getAddress());
byte[] hardware = i.getHardwareAddress();
if (hardware != null) out.write(hardware);
Enumeration<NetworkInterface> ifaces = getNetworkInterfaces();
if (ifaces != null) {
for (NetworkInterface i : list(ifaces)) {
for (InetAddress a : list(i.getInetAddresses()))
out.write(a.getAddress());
byte[] hardware = i.getHardwareAddress();
if (hardware != null) out.write(hardware);
}
}
for (Entry<String, String> e : System.getenv().entrySet()) {
out.writeUTF(e.getKey());

View File

@@ -139,7 +139,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
}
@Override
public void stopService() throws ServiceException {
public void stopService() {
}
@Override
@@ -274,9 +274,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
private List<ClientVersion> loadClientVersions(Transaction txn,
MessageId m) throws DbException {
try {
BdfList body = clientHelper.getMessageAsList(txn, m);
if (body == null) throw new DbException();
return parseClientVersions(body);
return parseClientVersions(clientHelper.getMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}
@@ -359,9 +357,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
private Update loadUpdate(Transaction txn, MessageId m) throws DbException {
try {
BdfList body = clientHelper.getMessageAsList(txn, m);
if (body == null) throw new DbException();
return parseUpdate(body);
return parseUpdate(clientHelper.getMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}

View File

@@ -3,6 +3,6 @@ Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C
Bridge 97.107.131.168:65341 DCDA8A5F1E2C50A6756A58462E5CF4B6B2DFDE26
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106

View File

@@ -0,0 +1,341 @@
package org.briarproject.bramble.account;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.annotation.Nullable;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class AccountManagerImplTest extends BrambleMockTestCase {
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final IdentityManager identityManager =
context.mock(IdentityManager.class);
private final SecretKey key = getSecretKey();
private final byte[] encryptedKey = getRandomBytes(123);
private final String encryptedKeyHex = toHexString(encryptedKey);
private final byte[] newEncryptedKey = getRandomBytes(123);
private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
private final LocalAuthor localAuthor = getLocalAuthor();
private final String authorName = localAuthor.getName();
private final String password = getRandomString(10);
private final String newPassword = getRandomString(10);
private final File testDir = getTestDirectory();
private final File dbDir = new File(testDir, "db");
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
private AccountManagerImpl accountManager;
@Before
public void setUp() {
context.checking(new Expectations() {{
allowing(databaseConfig).getDatabaseDirectory();
will(returnValue(dbDir));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
accountManager =
new AccountManagerImpl(databaseConfig, crypto, identityManager);
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testSignInReturnsFalseIfDbKeyCannotBeLoaded() {
assertFalse(accountManager.signIn(password));
assertFalse(accountManager.hasDatabaseKey());
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testSignInReturnsFalseIfPasswordIsWrong() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password);
will(returnValue(null));
}});
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertFalse(accountManager.signIn(password));
assertFalse(accountManager.hasDatabaseKey());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testSignInReturnsTrueIfPasswordIsRight() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password);
will(returnValue(key.getBytes()));
}});
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertTrue(accountManager.signIn(password));
assertTrue(accountManager.hasDatabaseKey());
SecretKey decrypted = accountManager.getDatabaseKey();
assertNotNull(decrypted);
assertArrayEquals(key.getBytes(), decrypted.getBytes());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex);
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex,
accountManager.loadEncryptedDatabaseKey());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertFalse(keyBackupFile.exists());
}
@Test
public void testDbKeyIsLoadedFromBackupFile() throws Exception {
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertFalse(keyFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertEquals(encryptedKeyHex,
accountManager.loadEncryptedDatabaseKey());
assertFalse(keyFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testDbKeyIsNullIfNotFound() {
assertNull(accountManager.loadEncryptedDatabaseKey());
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testStoringDbKeyOverwritesPrimary() throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex);
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertFalse(keyBackupFile.exists());
assertTrue(accountManager.storeEncryptedDatabaseKey(
newEncryptedKeyHex));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testStoringDbKeyOverwritesBackup() throws Exception {
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertFalse(keyFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertTrue(accountManager.storeEncryptedDatabaseKey(
newEncryptedKeyHex));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testAccountExistsReturnsFalseIfDbKeyCannotBeLoaded() {
assertFalse(accountManager.accountExists());
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testAccountExistsReturnsFalseIfDbDirectoryDoesNotExist()
throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertFalse(dbDir.exists());
assertFalse(accountManager.accountExists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertFalse(dbDir.exists());
}
@Test
public void testAccountExistsReturnsFalseIfDbDirectoryIsNotDirectory()
throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertTrue(dbDir.createNewFile());
assertFalse(dbDir.isDirectory());
assertFalse(accountManager.accountExists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertTrue(dbDir.exists());
assertFalse(dbDir.isDirectory());
}
@Test
public void testAccountExistsReturnsTrueIfDbDirectoryIsDirectory()
throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertTrue(dbDir.mkdirs());
assertTrue(dbDir.isDirectory());
assertTrue(accountManager.accountExists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertTrue(dbDir.exists());
assertTrue(dbDir.isDirectory());
}
@Test
public void testCreateAccountStoresDbKey() throws Exception {
context.checking(new Expectations() {{
oneOf(identityManager).createLocalAuthor(authorName);
will(returnValue(localAuthor));
oneOf(identityManager).registerLocalAuthor(localAuthor);
oneOf(crypto).generateSecretKey();
will(returnValue(key));
oneOf(crypto).encryptWithPassword(key.getBytes(), password);
will(returnValue(encryptedKey));
}});
assertFalse(accountManager.hasDatabaseKey());
assertTrue(accountManager.createAccount(authorName, password));
assertTrue(accountManager.hasDatabaseKey());
SecretKey dbKey = accountManager.getDatabaseKey();
assertNotNull(dbKey);
assertArrayEquals(key.getBytes(), dbKey.getBytes());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testChangePasswordReturnsFalseIfDbKeyCannotBeLoaded() {
assertFalse(accountManager.changePassword(password, newPassword));
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testChangePasswordReturnsFalseIfPasswordIsWrong()
throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password);
will(returnValue(null));
}});
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertFalse(accountManager.changePassword(password, newPassword));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testChangePasswordReturnsTrueIfPasswordIsRight()
throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password);
will(returnValue(key.getBytes()));
oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword);
will(returnValue(newEncryptedKey));
}});
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertTrue(accountManager.changePassword(password, newPassword));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
private void storeDatabaseKey(File f, String hex) throws IOException {
f.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(f);
out.write(hex.getBytes("UTF-8"));
out.flush();
out.close();
}
@Nullable
private String loadDatabaseKey(File f) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(f), "UTF-8"));
String hex = reader.readLine();
reader.close();
return hex;
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}

View File

@@ -18,6 +18,8 @@ import org.junit.Test;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@@ -28,8 +30,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
new BdfMessageValidator(clientHelper, metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body)
throws InvalidMessageException, FormatException {
BdfList body) {
throw new AssertionError();
}
};
@@ -69,7 +70,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) {
assertSame(message, m);
assertSame(group, g);
assertSame(body, b);
@@ -83,11 +84,12 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
@Test(expected = InvalidMessageException.class)
public void testRejectsTooShortMessage() throws Exception {
byte[] invalidRaw = new byte[MESSAGE_HEADER_LENGTH];
byte[] invalidRaw = getRandomBytes(MESSAGE_HEADER_LENGTH);
// Use a mock message so the length of the raw message can be invalid
Message invalidMessage = context.mock(Message.class);
context.checking(new Expectations() {{
//noinspection ResultOfMethodCallIgnored
oneOf(invalidMessage).getTimestamp();
will(returnValue(timestamp));
oneOf(clock).currentTimeMillis();
@@ -101,15 +103,13 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
@Test
public void testAcceptsMinLengthMessage() throws Exception {
byte[] shortRaw = new byte[MESSAGE_HEADER_LENGTH + 1];
Message shortMessage =
new Message(messageId, groupId, timestamp, shortRaw);
Message shortMessage = getMessage(groupId, MESSAGE_HEADER_LENGTH + 1);
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(clientHelper).toList(shortRaw, MESSAGE_HEADER_LENGTH,
shortRaw.length - MESSAGE_HEADER_LENGTH);
oneOf(clientHelper).toList(shortMessage.getRaw(),
MESSAGE_HEADER_LENGTH, 1);
will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta));
@@ -120,7 +120,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) {
assertSame(shortMessage, m);
assertSame(group, g);
assertSame(body, b);
@@ -160,7 +160,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) throws FormatException {
throw new FormatException();
}
};

View File

@@ -39,6 +39,7 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
@@ -67,11 +68,9 @@ public class ClientHelperImplTest extends BrambleTestCase {
private final GroupId groupId = new GroupId(getRandomId());
private final BdfDictionary dictionary = new BdfDictionary();
private final long timestamp = 42L;
private final byte[] rawMessage = getRandomBytes(42);
private final MessageId messageId = new MessageId(getRandomId());
private final Message message =
new Message(messageId, groupId, timestamp, rawMessage);
private final Message message = getMessage(groupId);
private final MessageId messageId = message.getId();
private final long timestamp = message.getTimestamp();
private final Metadata metadata = new Metadata();
private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42));
private final String label = StringUtils.getRandomString(5);
@@ -120,8 +119,8 @@ public class ClientHelperImplTest extends BrambleTestCase {
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getRawMessage(txn, messageId);
will(returnValue(rawMessage));
oneOf(db).getMessage(txn, messageId);
will(returnValue(message));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
@@ -267,7 +266,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testToList() throws Exception {
expectToList(true);
assertEquals(list, clientHelper.toList(rawMessage));
assertEquals(list, clientHelper.toList(getRandomBytes(123)));
context.assertIsSatisfied();
}
@@ -276,7 +275,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
expectToList(false); // no EOF after list
try {
clientHelper.toList(rawMessage);
clientHelper.toList(getRandomBytes(123));
fail();
} catch (FormatException e) {
// expected

View File

@@ -64,6 +64,7 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
@@ -72,6 +73,7 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
@@ -89,6 +91,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
context.mock(ShutdownManager.class);
private final EventBus eventBus = context.mock(EventBus.class);
private final SecretKey key = getSecretKey();
private final Object txn = new Object();
private final ClientId clientId;
private final int majorVersion;
@@ -96,10 +99,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private final Group group;
private final Author author;
private final LocalAuthor localAuthor;
private final Message message, message1;
private final MessageId messageId, messageId1;
private final int size;
private final byte[] raw;
private final Message message;
private final Metadata metadata;
private final TransportId transportId;
private final int maxLatency;
@@ -114,12 +115,10 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
messageId = new MessageId(getRandomId());
messageId1 = new MessageId(getRandomId());
long timestamp = System.currentTimeMillis();
size = 1234;
raw = new byte[size];
message = new Message(messageId, groupId, timestamp, raw);
message = getMessage(groupId);
message1 = getMessage(groupId);
messageId = message.getId();
messageId1 = message1.getId();
metadata = new Metadata();
metadata.put("foo", new byte[] {'b', 'a', 'r'});
transportId = getTransportId();
@@ -141,7 +140,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
int shutdownHandle = 12345;
context.checking(new Expectations() {{
// open()
oneOf(database).open(null);
oneOf(database).open(key, null);
will(returnValue(false));
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
will(returnValue(shutdownHandle));
@@ -208,7 +207,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
assertFalse(db.open(null));
assertFalse(db.open(key, null));
Transaction transaction = db.startTransaction(false);
try {
db.addLocalAuthor(transaction, localAuthor);
@@ -645,7 +644,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
transaction = db.startTransaction(false);
try {
db.getRawMessage(transaction, messageId);
db.getMessage(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
@@ -864,22 +863,22 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test
public void testGenerateBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToSend(txn, contactId, size * 2);
oneOf(database).getMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2);
will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId);
will(returnValue(raw));
oneOf(database).getMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTime(txn, contactId, messageId,
maxLatency);
oneOf(database).getRawMessage(txn, messageId1);
will(returnValue(raw1));
oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
@@ -892,7 +891,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false);
try {
assertEquals(messages, db.generateBatch(transaction, contactId,
size * 2, maxLatency));
MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction);
} finally {
db.endTransaction(transaction);
@@ -960,23 +959,22 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test
public void testGenerateRequestedBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getRequestedMessagesToSend(txn, contactId,
size * 2);
MAX_MESSAGE_LENGTH * 2);
will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId);
will(returnValue(raw));
oneOf(database).getMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTime(txn, contactId, messageId,
maxLatency);
oneOf(database).getRawMessage(txn, messageId1);
will(returnValue(raw1));
oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
@@ -989,7 +987,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false);
try {
assertEquals(messages, db.generateRequestedBatch(transaction,
contactId, size * 2, maxLatency));
contactId, MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction);
} finally {
db.endTransaction(transaction);
@@ -1602,7 +1600,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
MessageId messageId2 = new MessageId(getRandomId());
context.checking(new Expectations() {{
// open()
oneOf(database).open(null);
oneOf(database).open(key, null);
will(returnValue(false));
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
will(returnValue(shutdownHandle));
@@ -1646,7 +1644,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
assertFalse(db.open(null));
assertFalse(db.open(key, null));
Transaction transaction = db.startTransaction(false);
try {
db.addLocalMessage(transaction, message, metadata, true);

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseConfig;
@@ -26,6 +27,7 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -43,6 +45,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
protected final DatabaseConfig config =
new TestDatabaseConfig(testDir, 1024 * 1024);
protected final SecretKey key = getSecretKey();
protected final Clock clock = new SystemClock();
abstract Database<Connection> createDatabase(
@@ -62,7 +65,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
public void testDoesNotRunMigrationsWhenCreatingDatabase()
throws Exception {
Database<Connection> db = createDatabase(singletonList(migration));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close();
}
@@ -72,14 +75,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
throws Exception {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
// Override the data schema version
setDataSchemaVersion(db, -1);
db.close();
// Reopen the DB - an exception should be thrown
db = createDatabase(asList(migration, migration1));
db.open(null);
db.open(key, null);
}
@Test
@@ -87,12 +90,12 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
throws Exception {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close();
// Reopen the DB - migrations should not be run
db = createDatabase(asList(migration, migration1));
assertTrue(db.open(null));
assertTrue(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close();
}
@@ -101,14 +104,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
// Override the data schema version
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
db.close();
// Reopen the DB - an exception should be thrown
db = createDatabase(asList(migration, migration1));
db.open(null);
db.open(key, null);
}
@Test(expected = DataTooOldException.class)
@@ -116,13 +119,13 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
throws Exception {
// Open the DB for the first time
Database<Connection> db = createDatabase(emptyList());
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
db.close();
// Reopen the DB - an exception should be thrown
db = createDatabase(emptyList());
db.open(null);
db.open(key, null);
}
@Test(expected = DataTooOldException.class)
@@ -141,14 +144,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
// Override the data schema version
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
db.close();
// Reopen the DB - an exception should be thrown
db = createDatabase(asList(migration, migration1));
db.open(null);
db.open(key, null);
}
@Test
@@ -170,14 +173,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
// Override the data schema version
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
db.close();
// Reopen the DB - the first migration should be run
db = createDatabase(asList(migration, migration1));
assertTrue(db.open(null));
assertTrue(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close();
}
@@ -202,14 +205,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
// Open the DB for the first time
Database<Connection> db = createDatabase(asList(migration, migration1));
assertFalse(db.open(null));
assertFalse(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
// Override the data schema version
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
db.close();
// Reopen the DB - both migrations should be run
db = createDatabase(asList(migration, migration1));
assertTrue(db.open(null));
assertTrue(db.open(key, null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close();
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.system.Clock;
@@ -15,6 +16,7 @@ import java.util.List;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getMean;
import static org.briarproject.bramble.test.TestUtils.getMedian;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01;
@@ -25,6 +27,7 @@ public abstract class DatabasePerformanceComparisonTest
* How many blocks of each condition to compare.
*/
private static final int COMPARISON_BLOCKS = 10;
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock);
@@ -71,7 +74,7 @@ public abstract class DatabasePerformanceComparisonTest
throws DbException {
Database<Connection> db = createDatabase(conditionA,
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(null);
db.open(databaseKey, null);
return db;
}

View File

@@ -506,11 +506,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
@Test
public void testGetRawMessage() throws Exception {
String name = "getRawMessage(T, MessageId)";
public void testGetMessage() throws Exception {
String name = "getMessage(T, MessageId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getRawMessage(txn, pickRandom(messages).getId());
db.getMessage(txn, pickRandom(messages).getId());
db.commitTransaction(txn);
});
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.system.Clock;
@@ -16,9 +17,12 @@ import java.sql.Connection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock);
@@ -43,7 +47,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(null);
db.open(databaseKey, null);
return db;
}

View File

@@ -9,8 +9,8 @@ import java.util.List;
public class H2MigrationTest extends DatabaseMigrationTest {
@Override
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
throws Exception {
Database<Connection> createDatabase(
List<Migration<Connection>> migrations) {
return new H2Database(config, clock) {
@Override
List<Migration<Connection>> getMigrations() {

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -52,7 +53,7 @@ import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
@@ -61,9 +62,10 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -79,35 +81,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
private static final int ONE_MEGABYTE = 1024 * 1024;
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
private final File testDir = TestUtils.getTestDirectory();
private final SecretKey key = getSecretKey();
private final File testDir = getTestDirectory();
private final GroupId groupId;
private final ClientId clientId;
private final int majorVersion;
private final Group group;
private final Author author;
private final LocalAuthor localAuthor;
private final MessageId messageId;
private final long timestamp;
private final int size;
private final byte[] raw;
private final Message message;
private final MessageId messageId;
private final TransportId transportId;
private final ContactId contactId;
private final KeySetId keySetId, keySetId1;
private final Random random = new Random();
JdbcDatabaseTest() throws Exception {
JdbcDatabaseTest() {
clientId = getClientId();
majorVersion = 123;
group = getGroup(clientId, majorVersion);
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
messageId = new MessageId(getRandomId());
timestamp = System.currentTimeMillis();
size = 1234;
raw = getRandomBytes(size);
message = new Message(messageId, groupId, timestamp, raw);
message = getMessage(groupId);
messageId = message.getId();
transportId = getTransportId();
contactId = new ContactId(1);
keySetId = new KeySetId(1);
@@ -147,8 +144,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertTrue(db.containsContact(txn, contactId));
assertTrue(db.containsGroup(txn, groupId));
assertTrue(db.containsMessage(txn, messageId));
byte[] raw1 = db.getRawMessage(txn, messageId);
assertArrayEquals(raw, raw1);
assertArrayEquals(message.getRaw(),
db.getMessage(txn, messageId).getRaw());
// Delete the records
db.removeMessage(txn, messageId);
@@ -358,11 +355,11 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The message is sendable, but too large to send
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
size - 1);
message.getRawLength() - 1);
assertTrue(ids.isEmpty());
// The message is just the right size to send
ids = db.getMessagesToSend(txn, contactId, size);
ids = db.getMessagesToSend(txn, contactId, message.getRawLength());
assertEquals(singletonList(messageId), ids);
db.commitTransaction(txn);
@@ -382,8 +379,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addGroupVisibility(txn, contactId, groupId, false);
// Add some messages to ack
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
db.addMessage(txn, message, DELIVERED, true, contactId);
db.addMessage(txn, message1, DELIVERED, true, contactId);
@@ -446,9 +443,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetFreeSpace() throws Exception {
byte[] largeBody = new byte[MAX_MESSAGE_LENGTH];
for (int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
Message message = new Message(messageId, groupId, timestamp, largeBody);
Message message = getMessage(groupId, MAX_MESSAGE_BODY_LENGTH);
Database<Connection> db = open(false);
// Sanity check: there should be enough space on disk for this test
@@ -1102,8 +1097,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMetadataQueries() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1206,8 +1201,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMetadataQueriesOnlyForDeliveredMessages() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1277,14 +1272,14 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMessageDependencies() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
MessageId messageId2 = new MessageId(getRandomId());
MessageId messageId3 = new MessageId(getRandomId());
MessageId messageId4 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message2 = new Message(messageId2, groupId, timestamp, raw);
Message message3 = new Message(messageId3, groupId, timestamp, raw);
Message message4 = new Message(messageId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
MessageId messageId1 = message1.getId();
MessageId messageId2 = message2.getId();
MessageId messageId3 = message3.getId();
MessageId messageId4 = message4.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1382,16 +1377,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addGroup(txn, group1);
// Add a message to the second group
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId1, timestamp, raw);
Message message1 = getMessage(groupId1);
MessageId messageId1 = message1.getId();
db.addMessage(txn, message1, DELIVERED, true, contactId);
// Create an ID for a missing message
MessageId messageId2 = new MessageId(getRandomId());
// Add another message to the first group
MessageId messageId3 = new MessageId(getRandomId());
Message message3 = new Message(messageId3, groupId, timestamp, raw);
Message message3 = getMessage(groupId);
MessageId messageId3 = message3.getId();
db.addMessage(txn, message3, DELIVERED, true, contactId);
// Add dependencies between the messages
@@ -1425,36 +1420,32 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetPendingMessagesForDelivery() throws Exception {
MessageId mId1 = new MessageId(getRandomId());
MessageId mId2 = new MessageId(getRandomId());
MessageId mId3 = new MessageId(getRandomId());
MessageId mId4 = new MessageId(getRandomId());
Message m1 = new Message(mId1, groupId, timestamp, raw);
Message m2 = new Message(mId2, groupId, timestamp, raw);
Message m3 = new Message(mId3, groupId, timestamp, raw);
Message m4 = new Message(mId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a group and some messages with different states
db.addGroup(txn, group);
db.addMessage(txn, m1, UNKNOWN, true, contactId);
db.addMessage(txn, m2, INVALID, true, contactId);
db.addMessage(txn, m3, PENDING, true, contactId);
db.addMessage(txn, m4, DELIVERED, true, contactId);
db.addMessage(txn, message1, UNKNOWN, true, contactId);
db.addMessage(txn, message2, INVALID, true, contactId);
db.addMessage(txn, message3, PENDING, true, contactId);
db.addMessage(txn, message4, DELIVERED, true, contactId);
Collection<MessageId> result;
// Retrieve messages to be validated
result = db.getMessagesToValidate(txn);
assertEquals(1, result.size());
assertTrue(result.contains(mId1));
assertTrue(result.contains(message1.getId()));
// Retrieve pending messages
result = db.getPendingMessages(txn);
assertEquals(1, result.size());
assertTrue(result.contains(mId3));
assertTrue(result.contains(message3.getId()));
db.commitTransaction(txn);
db.close();
@@ -1462,35 +1453,31 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetMessagesToShare() throws Exception {
MessageId mId1 = new MessageId(getRandomId());
MessageId mId2 = new MessageId(getRandomId());
MessageId mId3 = new MessageId(getRandomId());
MessageId mId4 = new MessageId(getRandomId());
Message m1 = new Message(mId1, groupId, timestamp, raw);
Message m2 = new Message(mId2, groupId, timestamp, raw);
Message m3 = new Message(mId3, groupId, timestamp, raw);
Message m4 = new Message(mId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a group and some messages
db.addGroup(txn, group);
db.addMessage(txn, m1, DELIVERED, true, contactId);
db.addMessage(txn, m2, DELIVERED, false, contactId);
db.addMessage(txn, m3, DELIVERED, false, contactId);
db.addMessage(txn, m4, DELIVERED, true, contactId);
db.addMessage(txn, message1, DELIVERED, true, contactId);
db.addMessage(txn, message2, DELIVERED, false, contactId);
db.addMessage(txn, message3, DELIVERED, false, contactId);
db.addMessage(txn, message4, DELIVERED, true, contactId);
// Introduce dependencies between the messages
db.addMessageDependency(txn, m1, mId2, DELIVERED);
db.addMessageDependency(txn, m3, mId1, DELIVERED);
db.addMessageDependency(txn, m4, mId3, DELIVERED);
db.addMessageDependency(txn, message1, message2.getId(), DELIVERED);
db.addMessageDependency(txn, message3, message1.getId(), DELIVERED);
db.addMessageDependency(txn, message4, message3.getId(), DELIVERED);
// Retrieve messages to be shared
Collection<MessageId> result = db.getMessagesToShare(txn);
assertEquals(2, result.size());
assertTrue(result.contains(mId2));
assertTrue(result.contains(mId3));
assertTrue(result.contains(message2.getId()));
assertTrue(result.contains(message3.getId()));
db.commitTransaction(txn);
db.close();
@@ -1652,8 +1639,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
ids = db.getMessagesToOffer(txn, contactId, 100);
assertEquals(singletonList(messageId), ids);
// The raw message should not be null
assertNotNull(db.getRawMessage(txn, messageId));
// The message should be available
Message m = db.getMessage(txn, messageId);
assertEquals(messageId, m.getId());
assertEquals(groupId, m.getGroupId());
assertEquals(message.getTimestamp(), m.getTimestamp());
assertArrayEquals(message.getRaw(), m.getRaw());
// Delete the message
db.deleteMessage(txn, messageId);
@@ -1667,8 +1658,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
ids = db.getMessagesToOffer(txn, contactId, 100);
assertTrue(ids.isEmpty());
// The raw message should be null
assertNull(db.getRawMessage(txn, messageId));
// Requesting the message should throw an exception
try {
db.getMessage(txn, messageId);
fail();
} catch (MessageDeletedException expected) {
// Expected
}
db.commitTransaction(txn);
db.close();
@@ -1800,7 +1796,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
try {
// Ask for a nonexistent message - an exception should be thrown
db.getRawMessage(txn, messageId);
db.getMessage(txn, messageId);
fail();
} catch (DbException expected) {
// It should be possible to abort the transaction without error
@@ -1819,7 +1815,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
if (!resume) TestUtils.deleteTestDirectory(testDir);
db.open(null);
db.open(key, null);
return db;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.system.Clock;
@@ -13,6 +14,7 @@ import java.util.List;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getMean;
import static org.briarproject.bramble.test.TestUtils.getMedian;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
public abstract class SingleDatabasePerformanceTest
@@ -21,6 +23,8 @@ public abstract class SingleDatabasePerformanceTest
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock);
private SecretKey databaseKey = getSecretKey();
@Override
protected void benchmark(String name,
BenchmarkTask<Database<Connection>> task) throws Exception {
@@ -40,7 +44,7 @@ public abstract class SingleDatabasePerformanceTest
private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(null);
db.open(databaseKey, null);
return db;
}

View File

@@ -2,15 +2,21 @@ package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
@@ -27,24 +33,48 @@ import static org.junit.Assert.assertEquals;
public class IdentityManagerImplTest extends BrambleMockTestCase {
private final IdentityManager identityManager;
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final AuthorFactory authorFactory =
context.mock(AuthorFactory.class);
private final PublicKey publicKey = context.mock(PublicKey.class);
private final PrivateKey privateKey = context.mock(PrivateKey.class);
private final Transaction txn = new Transaction(null, false);
private final LocalAuthor localAuthor = getLocalAuthor();
private final Collection<LocalAuthor> localAuthors =
Collections.singletonList(localAuthor);
private final String authorName = localAuthor.getName();
private final KeyPair keyPair = new KeyPair(publicKey, privateKey);
private final byte[] publicKeyBytes = localAuthor.getPublicKey();
private final byte[] privateKeyBytes = localAuthor.getPrivateKey();
private IdentityManager identityManager;
public IdentityManagerImplTest() {
identityManager = new IdentityManagerImpl(db);
@Before
public void setUp() {
identityManager = new IdentityManagerImpl(db, crypto, authorFactory);
}
@Test
public void testRegisterLocalAuthor() throws DbException {
expectRegisterLocalAuthor();
identityManager.registerLocalAuthor(localAuthor);
public void testCreateLocalAuthor() {
context.checking(new Expectations() {{
oneOf(crypto).generateSignatureKeyPair();
will(returnValue(keyPair));
oneOf(publicKey).getEncoded();
will(returnValue(publicKeyBytes));
oneOf(privateKey).getEncoded();
will(returnValue(privateKeyBytes));
oneOf(authorFactory).createLocalAuthor(authorName,
publicKeyBytes, privateKeyBytes);
will(returnValue(localAuthor));
}});
assertEquals(localAuthor,
identityManager.createLocalAuthor(authorName));
}
private void expectRegisterLocalAuthor() throws DbException {
@Test
public void testRegisterAndStoreLocalAuthor() throws DbException {
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
@@ -52,6 +82,10 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
identityManager.registerLocalAuthor(localAuthor);
assertEquals(localAuthor, identityManager.getLocalAuthor());
identityManager.storeLocalAuthor();
}
@Test
@@ -69,7 +103,6 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
@Test
public void testGetCachedLocalAuthor() throws DbException {
expectRegisterLocalAuthor();
identityManager.registerLocalAuthor(localAuthor);
assertEquals(localAuthor, identityManager.getLocalAuthor());
}

View File

@@ -34,11 +34,10 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -187,8 +186,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
BdfDictionary metaDictionary = BdfDictionary.of(
new BdfEntry("transportId", "foo"),
@@ -229,8 +227,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
// Version 4 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
@@ -267,8 +264,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
public void testDeletesObsoleteUpdateWhenDelivered() throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
// Version 3 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
@@ -619,12 +615,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
true, active);
}
private Message getMessage(GroupId g, long timestamp) {
MessageId messageId = new MessageId(getRandomId());
byte[] raw = getRandomBytes(MAX_MESSAGE_BODY_LENGTH);
return new Message(messageId, g, timestamp, raw);
}
private void expectGetLocalProperties(Transaction txn) throws Exception {
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
// The latest update for transport "foo" should be returned
@@ -664,9 +654,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
private void expectStoreMessage(Transaction txn, GroupId g,
String transportId, BdfDictionary properties, long version,
boolean local, boolean shared) throws Exception {
long timestamp = 123456789;
BdfList body = BdfList.of(transportId, version, properties);
Message message = getMessage(g, timestamp);
Message message = getMessage(g);
long timestamp = message.getTimestamp();
BdfDictionary meta = BdfDictionary.of(
new BdfEntry("transportId", transportId),
new BdfEntry("version", version),

View File

@@ -5,6 +5,8 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.transport.StreamWriter;
@@ -13,11 +15,11 @@ import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Executor;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
@@ -32,7 +34,8 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
private final Executor dbExecutor = new ImmediateExecutor();
private final ContactId contactId = new ContactId(234);
private final MessageId messageId = new MessageId(getRandomId());
private final Message message = getMessage(new GroupId(getRandomId()));
private final MessageId messageId = message.getId();
@Test
public void testNothingToSend() throws Exception {
@@ -71,8 +74,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
@Test
public void testSomethingToSend() throws Exception {
Ack ack = new Ack(Collections.singletonList(messageId));
byte[] raw = new byte[1234];
Ack ack = new Ack(singletonList(messageId));
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
recordWriter);
@@ -97,10 +99,10 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
will(returnValue(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
will(returnValue(Arrays.asList(raw)));
will(returnValue(singletonList(message)));
oneOf(db).commitTransaction(msgTxn);
oneOf(db).endTransaction(msgTxn);
oneOf(recordWriter).writeMessage(raw);
oneOf(recordWriter).writeMessage(message);
// No more acks
oneOf(db).startTransaction(false);
will(returnValue(noAckTxn));

View File

@@ -108,8 +108,8 @@ public class SyncIntegrationTest extends BrambleTestCase {
streamWriter.getOutputStream());
recordWriter.writeAck(new Ack(messageIds));
recordWriter.writeMessage(message.getRaw());
recordWriter.writeMessage(message1.getRaw());
recordWriter.writeMessage(message);
recordWriter.writeMessage(message1);
recordWriter.writeOffer(new Offer(messageIds));
recordWriter.writeRequest(new Request(messageIds));
@@ -169,7 +169,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
assertArrayEquals(m1.getGroupId().getBytes(),
m2.getGroupId().getBytes());
assertEquals(m1.getTimestamp(), m2.getTimestamp());
assertEquals(m1.getLength(), m2.getLength());
assertEquals(m1.getRawLength(), m2.getRawLength());
assertArrayEquals(m1.getRaw(), m2.getRaw());
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Metadata;
@@ -13,7 +12,6 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
@@ -21,30 +19,31 @@ import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.briarproject.bramble.util.ByteUtils;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
public class ValidationManagerImplTest extends BrambleMockTestCase {
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final MessageFactory messageFactory =
context.mock(MessageFactory.class);
private final MessageValidator validator =
context.mock(MessageValidator.class);
private final IncomingMessageHook hook =
@@ -54,38 +53,26 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
private final Executor validationExecutor = new ImmediateExecutor();
private final ClientId clientId = getClientId();
private final int majorVersion = 123;
private final MessageId messageId = new MessageId(getRandomId());
private final MessageId messageId1 = new MessageId(getRandomId());
private final MessageId messageId2 = new MessageId(getRandomId());
private final Group group = getGroup(clientId, majorVersion);
private final GroupId groupId = group.getId();
private final long timestamp = System.currentTimeMillis();
private final byte[] raw = new byte[123];
private final Message message = new Message(messageId, groupId, timestamp,
raw);
private final Message message1 = new Message(messageId1, groupId, timestamp,
raw);
private final Message message2 = new Message(messageId2, groupId, timestamp,
raw);
private final Message message = getMessage(groupId);
private final Message message1 = getMessage(groupId);
private final Message message2 = getMessage(groupId);
private final MessageId messageId = message.getId();
private final MessageId messageId1 = message1.getId();
private final MessageId messageId2 = message2.getId();
private final Metadata metadata = new Metadata();
private final MessageContext validResult = new MessageContext(metadata);
private final ContactId contactId = new ContactId(234);
private final MessageContext validResultWithDependencies =
new MessageContext(metadata, Collections.singletonList(messageId1));
new MessageContext(metadata, singletonList(messageId1));
private ValidationManagerImpl vm;
public ValidationManagerImplTest() {
// Encode the messages
System.arraycopy(groupId.getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
}
@Before
public void setUp() {
vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor,
messageFactory);
vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor);
vm.registerMessageValidator(clientId, majorVersion, validator);
vm.registerIncomingMessageHook(clientId, majorVersion, hook);
}
@@ -101,21 +88,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// deliverOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// shareOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -145,9 +132,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
@@ -166,15 +151,13 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn3));
oneOf(db).getRawMessage(txn3, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn3, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -193,21 +176,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn4, messageId1);
// Recursively invalidate any dependents
oneOf(db).getMessageDependents(txn4, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getPendingMessages(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn6));
oneOf(db).getMessagesToShare(txn6);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -228,14 +211,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.singletonList(messageId)));
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the message is ready to deliver
@@ -244,11 +227,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn2, messageId);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the message and its metadata to deliver
oneOf(db).getRawMessage(txn2, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn2, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -260,7 +241,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(Collections.singletonMap(messageId2, PENDING)));
will(returnValue(singletonMap(messageId2, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether the dependent is ready to deliver
@@ -269,11 +250,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the dependent and its metadata to deliver
oneOf(db).getRawMessage(txn3, messageId2);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId2, raw);
oneOf(db).getMessage(txn3, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -285,7 +264,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn3, messageId2, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
@@ -293,7 +272,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getMessagesToShare(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
@@ -314,14 +293,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// No pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
@@ -329,7 +308,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(Collections.singletonList(messageId)));
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Share message and get dependencies
@@ -337,7 +316,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn3));
oneOf(db).setMessageShared(txn3, messageId);
oneOf(db).getMessageDependencies(txn3, messageId);
will(returnValue(Collections.singletonMap(messageId2, DELIVERED)));
will(returnValue(singletonMap(messageId2, DELIVERED)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Share dependency
@@ -345,7 +324,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn4));
oneOf(db).setMessageShared(txn4, messageId2);
oneOf(db).getMessageDependencies(txn4, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
@@ -376,7 +355,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -384,7 +363,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
// Share message
oneOf(db).setMessageShared(txn1, messageId);
oneOf(db).commitTransaction(txn1);
@@ -394,7 +373,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn2));
oneOf(db).setMessageShared(txn2, messageId1);
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -423,16 +402,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message - *gasp* it's gone!
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
oneOf(db).getMessage(txn1, messageId);
will(throwException(new NoSuchMessageException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -451,21 +428,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId1);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
@@ -494,9 +471,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
// Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn1, groupId);
@@ -506,9 +481,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -527,21 +500,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId1);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
@@ -575,7 +548,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
@@ -584,7 +557,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
}
@Test
public void testLocalMessagesAreNotValidatedWhenAdded() throws Exception {
public void testLocalMessagesAreNotValidatedWhenAdded() {
vm.eventOccurred(new MessageAddedEvent(message, null));
}
@@ -611,7 +584,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, UNKNOWN)));
will(returnValue(singletonMap(messageId1, UNKNOWN)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
oneOf(db).setMessageState(txn1, messageId, PENDING);
oneOf(db).commitTransaction(txn1);
@@ -644,7 +617,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -652,7 +625,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
@@ -685,7 +658,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
validResultWithDependencies.getDependencies());
// Check for invalid dependencies
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, INVALID)));
will(returnValue(singletonMap(messageId1, INVALID)));
// Invalidate message
oneOf(db).getMessageState(txn1, messageId);
will(returnValue(UNKNOWN));
@@ -694,7 +667,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn1, messageId);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId2, UNKNOWN)));
will(returnValue(singletonMap(messageId2, UNKNOWN)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate dependent in a new transaction
@@ -706,7 +679,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessage(txn2, messageId2);
oneOf(db).deleteMessageMetadata(txn2, messageId2);
oneOf(db).getMessageDependents(txn2, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -763,7 +736,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn2, messageId1);
// Message 1 has one dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Invalidate message 2
@@ -776,7 +749,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId2);
// Message 2 has one dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Invalidate message 3 (via 1)
@@ -789,7 +762,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn4, messageId3);
// Message 3 has one dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(Collections.singletonMap(messageId4, PENDING)));
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Invalidate message 3 (again, via 2)
@@ -809,7 +782,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn6, messageId4);
// Message 4 has no dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -819,12 +792,10 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
@Test
public void testPendingDependentsGetDelivered() throws Exception {
MessageId messageId3 = new MessageId(getRandomId());
MessageId messageId4 = new MessageId(getRandomId());
Message message3 = new Message(messageId3, groupId, timestamp,
raw);
Message message4 = new Message(messageId4, groupId, timestamp,
raw);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
MessageId messageId3 = message3.getId();
MessageId messageId4 = message4.getId();
Map<MessageId, State> twoDependents = new LinkedHashMap<>();
twoDependents.put(messageId1, PENDING);
twoDependents.put(messageId2, PENDING);
@@ -869,11 +840,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId, DELIVERED)));
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 1 and its metadata
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -885,7 +854,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId1, DELIVERED);
// Message 1 has one pending dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether message 2 is ready to be delivered
@@ -894,11 +863,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId, DELIVERED)));
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 2 and its metadata
oneOf(db).getRawMessage(txn3, messageId2);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId2, raw);
oneOf(db).getMessage(txn3, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -910,7 +877,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn3, messageId2, DELIVERED);
// Message 2 has one pending dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Check whether message 3 is ready to be delivered (via 1)
@@ -921,9 +888,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn4, messageId3);
will(returnValue(twoDependencies));
// Get message 3 and its metadata
oneOf(db).getRawMessage(txn4, messageId3);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId3, raw);
oneOf(db).getMessage(txn4, messageId3);
will(returnValue(message3));
oneOf(db).getGroup(txn4, groupId);
will(returnValue(group));
@@ -934,7 +899,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn4, messageId3, DELIVERED);
// Message 3 has one pending dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(Collections.singletonMap(messageId4, PENDING)));
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Check whether message 3 is ready to be delivered (again, via 2)
@@ -950,11 +915,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn6, messageId4);
will(returnValue(Collections.singletonMap(messageId3, DELIVERED)));
will(returnValue(singletonMap(messageId3, DELIVERED)));
// Get message 4 and its metadata
oneOf(db).getRawMessage(txn6, messageId4);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId4, raw);
oneOf(db).getMessage(txn6, messageId4);
will(returnValue(message4));
oneOf(db).getGroup(txn6, groupId);
will(returnValue(group));
@@ -966,7 +929,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn6, messageId4, DELIVERED);
// Message 4 has no pending dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -1004,7 +967,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, PENDING)));
will(returnValue(singletonMap(messageId1, PENDING)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the pending dependent is ready to be delivered

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -11,7 +10,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
private final File dbDir, keyDir;
private final long maxSize;
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
public TestDatabaseConfig(File testDir, long maxSize) {
dbDir = new File(testDir, "db");
@@ -19,13 +17,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
this.maxSize = maxSize;
}
@Override
public boolean databaseExists() {
if (!dbDir.isDirectory()) return false;
File[] files = dbDir.listFiles();
return files != null && files.length > 0;
}
@Override
public File getDatabaseDirectory() {
return dbDir;
@@ -36,26 +27,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
return keyDir;
}
@Override
public void setEncryptionKey(SecretKey key) {
this.key = key;
}
@Override
public SecretKey getEncryptionKey() {
return key;
}
@Override
public void setLocalAuthorName(String nickname) {
}
@Override
public String getLocalAuthorName() {
return null;
}
@Override
public long getMaxSize() {
return maxSize;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.Service;
@@ -11,7 +12,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import dagger.Module;
@@ -40,7 +40,7 @@ public class TestLifecycleModule {
}
@Override
public StartResult startServices(@Nullable String nickname) {
public StartResult startServices(SecretKey dbKey) {
return StartResult.SUCCESS;
}
@@ -49,15 +49,15 @@ public class TestLifecycleModule {
}
@Override
public void waitForDatabase() throws InterruptedException {
public void waitForDatabase() {
}
@Override
public void waitForStartup() throws InterruptedException {
public void waitForStartup() {
}
@Override
public void waitForShutdown() throws InterruptedException {
public void waitForShutdown() {
}
@Override

View File

@@ -0,0 +1,33 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
]
}

View File

@@ -1,3 +0,0 @@
bin
build
.settings

View File

@@ -1,54 +0,0 @@
apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea'
apply plugin: 'witness'
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'net.java.dev.jna:jna:4.4.0'
implementation 'net.java.dev.jna:jna-platform:4.4.0'
apt 'com.google.dagger:dagger-compiler:2.0.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
}
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.java.dev.jna:jna-platform:4.4.0:jna-platform-4.4.0.jar:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
'net.java.dev.jna:jna:4.4.0:jna-4.4.0.jar:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}
tasks.withType(Test) {
systemProperty 'java.library.path', 'libs'
}

4
bramble-java/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
bin
build
.settings
src/main/resources/*.zip

44
bramble-java/build.gradle Normal file
View File

@@ -0,0 +1,44 @@
apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea'
apply plugin: 'witness'
apply from: 'witness.gradle'
configurations {
tor
}
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'net.java.dev.jna:jna:4.4.0'
implementation 'net.java.dev.jna:jna-platform:4.4.0'
tor 'org.briarproject:tor:0.2.9.16@zip'
apt 'com.google.dagger:dagger-compiler:2.0.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
}
project.afterEvaluate {
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/resources'
}
}
tasks.withType(Test) {
systemProperty 'java.library.path', 'libs'
}

Some files were not shown because too many files have changed in this diff Show More