Compare commits

...

518 Commits

Author SHA1 Message Date
akwizgran
b02d89967e Use /dev/urandom for tests. 2018-08-20 16:54:46 +01:00
akwizgran
65ce049737 Enable logging to console for briar-core tests. 2018-08-20 15:53:13 +01:00
akwizgran
335c360ef8 Ignore IntroductionIntegrationTest. 2018-08-20 15:35:15 +01:00
akwizgran
fc26aaa168 Run only briar-core tests. 2018-08-20 15:23:35 +01:00
akwizgran
88224793c1 Fix cache paths. 2018-08-20 12:24:28 +01:00
akwizgran
0bf74f6a69 Environment var isn't available when creating cache. 2018-08-20 12:20:18 +01:00
akwizgran
4286621b02 Specify cache key. 2018-08-20 12:12:33 +01:00
akwizgran
b3e3b970ab List Gradle user directory. 2018-08-20 12:11:13 +01:00
akwizgran
ef10a08165 List cached directories. 2018-08-20 12:07:56 +01:00
akwizgran
094e1f8b65 List wrapper dists directory. 2018-08-20 12:06:46 +01:00
akwizgran
8b58bdb289 Remove stop command, use cache path. 2018-08-20 12:05:06 +01:00
akwizgran
7f61061f15 Stop daemon, just run Animal Sniffer. 2018-08-20 11:59:16 +01:00
akwizgran
cd127670bb Just clean, don't run tests. 2018-08-20 11:56:46 +01:00
akwizgran
a9b412be40 Slightly less minimal .gitlab-ci.yml 2018-08-20 11:56:45 +01:00
akwizgran
413360db09 Minimal .gitlab-ci.yml for debugging. 2018-08-20 11:56:45 +01: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
55d8f853db Bump version numbers for 1.0.13 release. 2018-07-31 17:34:08 +01:00
Torsten Grote
004853a09b Merge branch '1354-forget-hsforget' into 'master'
Don't try to use missing HSFORGET command

Closes #1354

See merge request briar/briar!869
2018-07-31 16:27:32 +00:00
akwizgran
d815dd6ec9 Don't try to use missing HSFORGET command. 2018-07-31 17:19:11 +01:00
akwizgran
f243ed39ab Bump version numbers for 1.0.12 release. 2018-07-30 16:48:04 +01:00
akwizgran
4aed0632b8 Update translations. 2018-07-30 15:21:39 +01:00
Torsten Grote
1860db10b4 Merge branch 'tor-0.2.9.16' into 'master'
Upgrade Tor to 0.2.9.16

See merge request briar/briar!868
2018-07-30 12:45:54 +00:00
akwizgran
cf4efbeef3 Upgrade Tor to 0.2.9.16. 2018-07-30 10:11:06 +01:00
Torsten Grote
099e8ef4d5 Merge branch 'bluetooth-not-required' into 'master'
Allow devices without Bluetooth support

See merge request briar/briar!867
2018-07-27 17:01:12 +00:00
akwizgran
05152eef0e Allow devices without Bluetooth support. 2018-07-27 17:49:02 +01:00
Hugh Isaacs II
481de00f90 Chrome OS / Chromebook support
By setting adding the uses-feature tag for touchscreens and android:required="false" to it, it tells Google Play and the Android runtime that this app doesn't require touchscreens, making Google Play and the OS treat it as if it'll work on non-touch devices.

Also it's possible to add android:required="false" to the Bluetooth tag as it's not needed for adding contacts, I'm just not sure how the Briar app would react on an Android device that doesn't support Bluetooth so I didn't take that leap.
2018-07-27 17:42:37 +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
14353653c7 Merge branch 'sign-in-reminder' into 'master'
Remove sign-in reminder when PasswordActivity starts

See merge request briar/briar!865
2018-07-27 14:25:23 +00: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
Torsten Grote
e300245f8d Remove sign-in reminder when PasswordActivity starts 2018-07-26 17:55:14 -03:00
akwizgran
81cbb7e843 Merge branch '1350-logo-broken' into 'master'
Fix Navigation Drawer Logo on Android 5

Closes #1350

See merge request briar/briar!864
2018-07-26 10:28:18 +00:00
Torsten Grote
bc0e529d89 Fix Navigation Drawer Logo on Android 5 2018-07-25 17:50:58 -03:00
Torsten Grote
c6b6bc307e Merge branch 'remove-notification-reminder-svg' into 'master'
Removed unused reminder notification SVG

See merge request briar/briar!862
2018-07-25 15:54:32 +00:00
akwizgran
b200dd9323 Removed unused reminder notification SVG. 2018-07-25 16:40:16 +01:00
akwizgran
881d8034cb Merge branch '1251-dark-theme' into 'master'
Dark theme changes based on designer feedback

Closes #1250 and #1251

See merge request briar/briar!861
2018-07-25 15:37:17 +00:00
akwizgran
1bee58e70d Merge branch 'run-unless-activity-not-added' into 'master'
Run UI actions only when the activity is added to the fragment.

Closes #1336

See merge request briar/briar!858
2018-07-25 13:33:15 +00:00
akwizgran
ede33d9278 Check for null activity in finish(). 2018-07-25 14:19:31 +01:00
Torsten Grote
ce6293b1d3 Dark theme changes based on designer feedback 2018-07-25 09:25:15 -03:00
akwizgran
912dd0eb4a Merge branch 'more-bridges' into 'master'
Add more vanilla bridges

See merge request briar/briar!859
2018-07-24 08:57:22 +00:00
Torsten Grote
06197295f8 Add more vanilla bridges 2018-07-20 16:14:05 -03:00
Torsten Grote
6a163c0358 Run UI actions only when the activity is added to the fragment.
This is different from the previous behavior
where we only check if it is not detached.
2018-07-20 13:28:34 -03:00
akwizgran
aa6b5511c2 Merge branch '47-sign-in-reminder' into 'master'
Add an option to not show the sign-in reminder

Closes #47

See merge request briar/briar!851
2018-07-18 12:57:22 +00:00
Torsten Grote
1cbd76bbc9 Address review nitpicks 2018-07-18 09:40:30 -03:00
Torsten Grote
ba4a4aea59 Only show a Dismiss button attached to the sign-in reminder
Also change the logo to a logout icon
2018-07-17 16:33:58 -03:00
Torsten Grote
391e869d29 Also remind to sign-in again after app was upgraded 2018-07-17 16:33:58 -03:00
Torsten Grote
8925d6f5d7 Add an option to not show the sign-in reminder
This is done via another preference in the settings screen
and an action button attached to the notification itself
2018-07-17 16:33:58 -03:00
Torsten Grote
afa9b6193a Merge branch 'remove-reference-manager' into 'master'
Removed unused ReferenceManager

See merge request briar/briar!856
2018-07-16 15:44:29 +00:00
akwizgran
1bcedea34a Removed unused ReferenceManager. 2018-07-16 16:21:25 +01:00
akwizgran
0f16ac57f3 Merge branch '1267-tor-bridges' into 'master'
Tor Bridge Support

See merge request briar/briar!847
2018-07-05 14:22:39 +00:00
Torsten Grote
7ecac1867e Address review comments for Tor bridge support 2018-07-05 11:14:11 -03:00
Torsten Grote
331c09a02a Load bridges from file res/raw/bridges 2018-07-04 16:21:49 -03:00
Torsten Grote
7e05a49bda Add Android integration tests that checks if included bridges work
This also changes the way bridges are used.
Instead of using the torrc config file,
bridges are now activated via Tor's control port.
2018-07-04 15:17:28 -03:00
Torsten Grote
eac1f9ed74 MVP for bridge support 2018-07-04 15:17:28 -03:00
Torsten Grote
d16aa9e2a4 Merge branch '1334-disable-resource-shrinking' into 'master'
Disable resource shrinking for release builds

Closes #1334

See merge request briar/briar!854
2018-07-04 17:20:40 +00:00
akwizgran
cc72d146a0 Disable resource shrinking for release builds. 2018-07-04 17:02:39 +01:00
Torsten Grote
bff23480d7 Trigger external pipeline to check release builds 2018-07-04 12:47:22 -03:00
akwizgran
e435578f3b Merge branch 'gui-minor-padding-corrections' into 'master'
Fixed padding in rss_feed_import, list_item_crash, power_view

See merge request briar/briar!831
2018-07-04 13:21:18 +00:00
jRustig
33b9539a72 correction of crash report alignment 2018-07-04 14:59:34 +02:00
akwizgran
a114d4db15 Bump version numbers for 1.0.11 release. 2018-07-04 08:45:03 +01:00
akwizgran
73b7879c64 Update translations. 2018-07-04 08:44:00 +01:00
akwizgran
e622a518ac Merge branch 'fix_npe_keyfrag' into 'master'
Fix a possible null reference bug

See merge request briar/briar!853
2018-07-03 17:20:59 +00:00
goapunk
28ea3d014a Fix a possible null reference bug 2018-07-03 11:33:13 +02:00
akwizgran
457d77ca51 Bump version numbers for 1.0.10 release. 2018-07-02 14:06:49 +01:00
akwizgran
581c67f5fd Update translations. 2018-07-02 14:04:51 +01:00
Torsten Grote
1dcb9aa1d0 Merge branch '1329-auth-cookie' into 'master'
Delete old auth cookie before starting Tor

Closes #1329

See merge request briar/briar!852
2018-06-29 15:38:23 +00:00
akwizgran
d97dcfff30 Merge branch 'no_screenfilter_warning_splash' into 'master'
Don't show screenfilter warning in SplashScreenActivity

See merge request briar/briar!832
2018-06-29 14:41:09 +00:00
akwizgran
e166d9dd15 Merge branch '1327-setup-crash' into 'master'
Ensure that pressing back after setup will always return the user to home

Closes #1327

See merge request briar/briar!849
2018-06-29 14:40:43 +00:00
akwizgran
2e002d132c Delete old auth cookie before starting Tor. 2018-06-29 15:28:50 +01:00
Torsten Grote
da629df630 Ensure that pressing back after setup will always return the user to home 2018-06-26 11:42:54 -03:00
Nico Alt
135372ebee Use consistent language for forum posts
Fixes #888.
2018-06-26 14:25:24 +02:00
akwizgran
b083122d72 Merge branch '47-sign-in-reminder' into 'master'
Remind the user to sign in

See merge request briar/briar!841
2018-06-22 14:49:09 +00:00
akwizgran
649433a506 Merge branch '1032-message-icon' into 'master'
Use message icon rather than mail icon for private messages

Closes #1032

See merge request briar/briar!846
2018-06-22 14:18:20 +00:00
Torsten Grote
eff3a69734 Disable sign-in reminder with a feature flag in release builds 2018-06-22 10:59:27 -03:00
Torsten Grote
62de50af76 Remind the user to sign in only when an account has been created 2018-06-22 10:46:27 -03:00
Torsten Grote
1f9def8418 Minimal Sign-in reminder 2018-06-22 10:46:27 -03:00
Torsten Grote
1e80069980 Merge branch 'feature-flags' into 'master'
Add feature flag for dark theme

See merge request briar/briar!843
2018-06-22 13:43:56 +00:00
Torsten Grote
bfde71c151 Merge branch '1307-readable-log' into 'master'
Display log file in a reader-friendly way

Closes #1307

See merge request briar/briar!845
2018-06-22 13:42:40 +00:00
akwizgran
bce0a3150b Use message icon rather than mail icon. 2018-06-22 13:48:52 +01:00
akwizgran
ee59b9b3ad Unescape newlines when showing log. 2018-06-22 11:17:54 +01:00
akwizgran
55918a88b2 Merge branch '1251-dark-theme-fixes' into 'master'
Dark Theme Fixes

See merge request briar/briar!844
2018-06-21 12:49:15 +00:00
Torsten Grote
679c1c3719 Fix RSS feed delete button and disabled button text 2018-06-21 09:40:55 -03:00
akwizgran
21f33d6cfb Add feature flag for dark theme. 2018-06-21 13:28:32 +01:00
akwizgran
912b1b5b1d Merge branch 'factor_out_keyagreement_ui-theme' into 'master'
Factor out keyagreement ui theme

See merge request briar/briar!835
2018-06-21 11:38:49 +00:00
goapunk
0ad20037ae Pass String instead of the TextView 2018-06-20 18:36:39 +02:00
akwizgran
62d893f7b1 Merge branch 'android-gradle-3.1.3' into 'master'
Upgrade Android Gradle Plugin to 3.1.3

See merge request briar/briar!842
2018-06-20 15:45:55 +00:00
goapunk
497213e56d add KeyAgreementEventListener interface 2018-06-20 15:44:42 +02:00
akwizgran
f5c0d0b2cb Merge branch '1251-dark-theme' into 'master'
Implement Dark Theme (DayNight with automatic option)

See merge request akwizgran/briar!818
2018-06-20 13:43:04 +00:00
goapunk
f4131d6f32 address reviews 2018-06-20 15:32:51 +02:00
goapunk
06deba4bd4 Create a dedicated qrCodeView 2018-06-20 15:32:42 +02:00
goapunk
26643e491b Add some abstraction to the keyagreement ui 2018-06-20 15:32:23 +02:00
Torsten Grote
6ef4130f8f Upgrade Android Gradle Plugin to 3.1.3 2018-06-19 17:36:35 -03:00
Torsten Grote
ba5b2f601b Applying night mode to DevReportActivity 2018-06-19 14:19:15 -03:00
Torsten Grote
5be672f0e7 Remove unused resources 2018-06-19 13:30:01 -03:00
Torsten Grote
fa525564c0 Hide Theme Settings in release builds for now 2018-06-19 13:30:01 -03:00
Torsten Grote
dee0ca238b Address first round of review comments 2018-06-19 13:30:00 -03:00
Torsten Grote
3c6b43b2bd Implement Dark Theme (DayNight with automatic option)
This is just a first rough implementation.
A real UI designer should look over this.
2018-06-19 13:29:13 -03:00
Administrator
dcacae0729 Merge branch 'language_improvements' into 'master'
Language improvements

See merge request akwizgran/briar!829
2018-06-19 16:27:50 +00:00
akwizgran
aefc5c519e Merge branch '1297-opendb-gui' into 'master'
Resolve ""Decrypting database" label needs some padding"

Closes #1297

See merge request akwizgran/briar!830
2018-06-18 14:19:34 +00:00
akwizgran
7225adf24e Merge branch 'fix_translation_verification' into 'master'
Use project path for translation verification

See merge request akwizgran/briar!840
2018-06-18 14:18:49 +00:00
goapunk
30228cf025 Use project path for translation verification 2018-06-17 16:11:22 +02:00
Torsten Grote
99e2b7eaab Merge branch 'exception-logging-method' into 'master'
Add utility method for logging exceptions

See merge request akwizgran/briar!838
2018-06-16 13:38:25 +00:00
Torsten Grote
2f7d5b869c Merge branch 'hide-ui-if-not-in-foreground' into 'master'
Don't hide UI on low memory if we're in the foreground

See merge request akwizgran/briar!839
2018-06-15 20:19:05 +00:00
akwizgran
d5d6db6723 Add utility method for logging exceptions. 2018-06-15 17:09:34 +01:00
Torsten Grote
b026031d66 Merge branch 'fine-logging' into 'master'
Replace logging boilerplate with a static method

See merge request akwizgran/briar!837
2018-06-15 15:30:31 +00:00
akwizgran
abe14f19e6 Replace boilerplate with static method. 2018-06-15 16:17:08 +01:00
Torsten Grote
fa17549972 Merge branch 'fine-logging' into 'master'
Move logging of time measurements to FINE level

See merge request akwizgran/briar!836
2018-06-15 15:00:25 +00:00
akwizgran
0d2a91289f Don't calculate duration unless needed. 2018-06-15 15:52:05 +01:00
Torsten Grote
2e22318b27 Merge branch '1291-huawei-protected-apps' into 'master'
Don't show Huawei protected apps button on API 24+

Closes #1291

See merge request akwizgran/briar!823
2018-06-15 14:35:46 +00:00
akwizgran
11f0bd1ae0 Merge branch '1288-placeholder-texts' into 'master'
Use placeholder text for text fields and add show password button

Closes #1096 and #1288

See merge request akwizgran/briar!834
2018-06-15 14:22:21 +00:00
akwizgran
e2d636e274 Don't hide UI on low memory if we're in the foreground. 2018-06-15 15:14:13 +01:00
Torsten Grote
f41b76c567 Shorten password hints 2018-06-15 11:13:38 -03:00
akwizgran
08931e64cb Use System.nanoTime() for timing measurements. 2018-06-15 13:01:48 +01:00
akwizgran
ccee1febbc Move timing measurements down to FINE log level. 2018-06-15 13:01:48 +01:00
Torsten Grote
7bfc1c3579 Add buttons to show passwords wherever they can be entered
Closes #1096
2018-06-14 15:40:17 -03:00
Torsten Grote
2dc94a95ed Use placeholder texts for text fields
Closes #1288
2018-06-14 15:36:08 -03:00
Torsten Grote
a47a1cf442 Merge branch '1316-make-introduction-string' into 'master'
Use separate strings for introduction menu item and button

Closes #1316

See merge request akwizgran/briar!833
2018-06-13 20:16:34 +00:00
akwizgran
4adb27a1ce Use separate strings for introduction menu item and button. 2018-06-13 16:50:24 +01:00
akwizgran
841c31ebce Bump version numbers for 1.0.9 release. 2018-06-13 15:38:49 +01:00
akwizgran
d6810cf87f Update translations. 2018-06-13 15:36:57 +01:00
goapunk
7a2df3d6cb simplify 2018-06-13 13:38:15 +02:00
goapunk
0c65ff4783 remove the unncessary synchronization from reset 2018-06-13 12:42:03 +02:00
goapunk
8b10b7ed23 Don't show screenfilter warning here 2018-06-13 12:36:43 +02:00
goapunk
9743255ce9 immutable version 2018-06-13 12:32:38 +02:00
jRustig
8c64734ff1 Fixed padding in rss_feed_import, list_item_crash, power_view 2018-06-13 10:34:10 +02:00
jRustig
c845dfc7f4 Fix padding in activity_open_database
Closes #1297
2018-06-13 10:00:42 +02:00
akwizgran
a8a02b9e45 Merge branch '992-refresh-wake-lock' into 'master'
Renew the wake lock every minute to avoid wake lock killers

See merge request akwizgran/briar!827
2018-06-12 16:59:32 +00:00
akwizgran
6703be1c32 Add thread safety, null safety annotations. 2018-06-12 17:50:58 +01:00
goapunk
fc99dedb53 Detect if system language changed 2018-06-12 16:23:32 +02:00
goapunk
65a461a0db Reset Localizer on account deletion 2018-06-12 12:15:47 +02:00
akwizgran
a44a68f231 Bump version numbers for 1.0.8 release. 2018-06-08 13:00:39 +01:00
akwizgran
4ac6baa23d Update translations. 2018-06-08 13:00:39 +01:00
akwizgran
4cde50b7f5 Merge branch '1293-cookie-file-polling' into 'master'
Poll for creation of Tor auth cookie file

Closes #1293

See merge request akwizgran/briar!828
2018-06-08 11:30:12 +00:00
akwizgran
da40eca80b Merge branch '1160-language-setting' into 'master'
Add language setting

Closes #1160 and #1222

See merge request akwizgran/briar!679
2018-06-08 11:20:39 +00:00
akwizgran
fa267d38af Filter out RTL languages on API < 17. 2018-06-08 13:07:30 +02:00
akwizgran
ba20fbeb47 Poll for creation of cookie file. 2018-06-08 10:40:38 +01:00
akwizgran
196df05df9 Bump version numbers for 1.0.7 release. 2018-06-07 12:12:39 +01:00
akwizgran
44f07c8d76 Merge branch '1293-tor-cookie-file' into 'master'
Watch for creation rather than updating of Tor cookie file

See merge request akwizgran/briar!825
2018-06-07 11:07:30 +00:00
akwizgran
d7f39af6d1 Reduce wake lock refresh interval to 1 minute. 2018-06-07 10:46:16 +01:00
akwizgran
4f732c3997 Acquire wake lock with a timeout. 2018-06-07 10:46:16 +01:00
akwizgran
74cfd313ab Code cleanup. 2018-06-07 10:46:16 +01:00
akwizgran
c089a099f0 Refactor wake lock to use existing ScheduledExecutorService. 2018-06-07 10:46:15 +01:00
goapunk
98a0d09899 Renew the wake lock every 30min
Signed-off-by: goapunk <noobie@goapunks.net>
2018-06-07 10:46:15 +01:00
goapunk
18c4195115 fix region and title 2018-06-07 11:42:31 +02:00
akwizgran
d4a9c41cf5 Watch for creation rather than updating of Tor cookie file.
Tor writes to a temporary file and then renames it over the old
file, if any, so CLOSE_WRITE never occurs. The old code was
working in most cases because it received IGNORED when the old
file was unlinked and didn't check the event type.
2018-06-07 09:19:52 +01:00
goapunk
8bc28f99c1 Improvements:
* Force LTR by prefixing language names with the LRM marker
* Add Polish
* Cleanup
2018-06-07 10:19:17 +02:00
goapunk
1834146ad0 fix hebrew 2018-06-07 10:19:17 +02:00
akwizgran
624e03a2c9 Merge branch 'default-build-timestamp' into 'master'
Add default build timestamp in case Git command fails

See merge request akwizgran/briar!826
2018-06-07 08:15:08 +00:00
akwizgran
a24e0482c9 Add default build timestamp in case Git command fails. 2018-06-06 14:34:40 +01:00
goapunk
695b543ba9 fix review 2018-06-06 11:16:24 +02:00
goapunk
75e910e1d9 Add a language setting 2018-06-06 11:16:21 +02:00
Torsten Grote
8fc8333451 Merge branch '1294-log-stack-traces' into 'master'
Log exception stacktraces

Closes #1294

See merge request akwizgran/briar!824
2018-06-03 02:28:17 +00:00
akwizgran
c2154c81f4 Log exception stacktraces. 2018-06-01 16:43:10 +01:00
akwizgran
5cd5fc7e43 Bump version numbers for 1.0.6 release. 2018-06-01 10:20:32 +01:00
akwizgran
abd9db70b9 Update translations, add Polish translation. 2018-06-01 10:18:42 +01:00
akwizgran
5025cf1e40 Merge branch 'remove-removable-drive-plugin' into 'master'
Remove RemovableDrivePlugin, refactor plugin interface

Closes #25

See merge request akwizgran/briar!817
2018-05-31 08:49:32 +00:00
akwizgran
5e679e7a10 Don't show Huawei protected apps button on API 24+. 2018-05-31 09:48:38 +01:00
akwizgran
834342fd3a Merge branch 'remove-reblog-scene-transition' into 'master'
Disable reblog scene transition as it even crashes my Android 7.1 device

Closes #785

See merge request akwizgran/briar!821
2018-05-29 15:56:07 +00:00
akwizgran
3028b236e1 Merge branch 'disable-prefetching' into 'master'
Disable pre-fetching in Threaded RecyclerView as a workaround for #1289

See merge request akwizgran/briar!820
2018-05-29 15:47:15 +00:00
Torsten Grote
254422bc02 Disable reblog scene transition as it even crashes my Android 7.1 device
Closes #785
2018-05-29 12:44:41 -03:00
Torsten Grote
c7949d6e00 Disable pre-fetching in Threaded RecyclerView as a workaround for #1289 2018-05-29 12:29:40 -03:00
Torsten Grote
0187264da7 Merge branch '1219-remove-debug-logging' into 'master'
Remove debug logging from setup process

See merge request akwizgran/briar!819
2018-05-28 13:59:22 +00:00
akwizgran
85a18cf53f Remove debug logging from setup process. 2018-05-28 14:34:20 +01:00
akwizgran
3181b695df Remove RemovableDrivePlugin, refactor plugin interface. 2018-05-25 13:57:38 +01:00
akwizgran
b2ac210586 Merge branch 'factor_out_plugin_conf' into 'master'
Make plugins and polling configurable

See merge request akwizgran/briar!814
2018-05-24 16:34:05 +00:00
Torsten Grote
d20340416d Merge branch 'jcenter-tor-binaries' into 'master'
Download Tor binaries from JCenter

See merge request akwizgran/briar!816
2018-05-24 12:21:14 +00:00
akwizgran
9da871718c Download Tor binaries from JCenter. 2018-05-24 10:54:34 +01:00
goapunk
3793cb841b Fix test and poller instantiation 2018-05-23 14:39:01 +02:00
goapunk
c6b88b51f0 Make plugins and polling configurable
* Move PluginConfig out of bramble-android. Projects using bramble now need to provide it.
* Add a PluginConfig#shouldPoll() method which can be used to disable polling altogether.
* Move Poller instantiation to the PluginManager.
2018-05-23 14:39:00 +02:00
Torsten Grote
2f00215a44 Merge branch 'remove-jtorctl-jar' into 'master'
Replace jtorctl jar with JCenter dependency

See merge request akwizgran/briar!815
2018-05-23 11:22:15 +00:00
akwizgran
183f0c5f31 Bump version numbers for 1.0.5 release. 2018-05-22 15:30:33 +01:00
Torsten Grote
34c5aaae0a Update translations (Farsi and Chinese complete now) 2018-05-22 11:17:51 -03:00
Torsten Grote
5531355ebd Merge branch '1219-store-db-key-in-file' into 'master'
Store database key in a file

Closes #1219

See merge request akwizgran/briar!810
2018-05-22 12:24:13 +00:00
akwizgran
b9e607744a Store second copy of DB key in backup file. 2018-05-22 12:07:07 +01:00
akwizgran
def62bce5a Replace jtorctl jar with JCenter dependency. 2018-05-22 11:32:19 +01:00
akwizgran
9dae3d191a Merge branch '1281-introduction-bug' into 'master'
Introduction: Reset session information for removed introducees

Closes #1281

See merge request akwizgran/briar!813
2018-05-22 09:09:13 +00:00
Torsten Grote
20422edf78 Introduction: Reset session information for removed introducees 2018-05-21 16:26:11 -03:00
Torsten Grote
f8bc5f08bf Merge branch 'unicode-escapes-for-test-data' into 'master'
Escape Unicode characters in test data

See merge request akwizgran/briar!812
2018-05-21 16:21:29 +00:00
akwizgran
9434495d70 Escape Unicode characters in test data.
This enables reproducible builds with non-Unicode locales.
2018-05-21 17:02:09 +01:00
Torsten Grote
bf9e91fcf5 Merge branch 'fix-build-timestamp' into 'master'
Make build timestamp command compatible with old versions of Git

See merge request akwizgran/briar!811
2018-05-21 12:47:47 +00:00
akwizgran
d9d86206a6 Make build timestamp command compatible with old versions of Git. 2018-05-21 13:40:14 +01:00
akwizgran
b410b8efcc Don't overwrite the backup if it's our only copy. 2018-05-18 15:17:43 +01:00
akwizgran
39aa2d96b3 Unit tests for DB key storage and retrieval. 2018-05-18 15:11:28 +01:00
akwizgran
21dae824a6 Store database key in a file rather than shared prefs. 2018-05-18 14:47:53 +01:00
akwizgran
cfdbd29cb4 Remove unused logging methods. 2018-05-18 14:47:20 +01:00
akwizgran
4df335ebd3 Merge branch 'own-ci' into 'master'
Switch to our own CI image

See merge request akwizgran/briar!809
2018-05-18 10:01:04 +00:00
Torsten Grote
682bee1486 Switch to our own CI image 2018-05-17 18:52:49 -03:00
akwizgran
f31219d54b Bump version numbers for 1.0.4 release. 2018-05-17 16:22:39 +01:00
Torsten Grote
b0ea32c85f Merge branch 'hide-testing-preferences' into 'master'
Hide testing preferences in release builds

See merge request akwizgran/briar!808
2018-05-17 14:33:06 +00:00
akwizgran
651e0b9859 Hide testing preferences in release builds. 2018-05-17 15:14:59 +01:00
akwizgran
f66244b578 Merge branch 'ci-test' into 'master'
Add CI stage for testing reproducibility

See merge request akwizgran/briar!807
2018-05-17 14:13:40 +00:00
Torsten Grote
3a35effae9 Add CI stage for testing reproducibility 2018-05-17 10:55:56 -03:00
Torsten Grote
97f4cd039a Update translations. New: Farsi and Asturian 2018-05-17 10:55:08 -03:00
akwizgran
20a1474457 Merge branch '1277-bdf-reader' into 'master'
Use lower default limit for BDF strings and raws

Closes #1277

See merge request akwizgran/briar!805
2018-05-17 13:35:57 +00:00
Torsten Grote
f214208b0a Merge branch 'test-data-lan-addresses' into 'master'
Use more realistic LAN addresses for test contacts

See merge request akwizgran/briar!804
2018-05-17 11:53:48 +00:00
akwizgran
d95a5fd58c Use lower default limit for BDF strings and raws. 2018-05-17 12:33:56 +01:00
akwizgran
7d4de21be0 Merge branch 'decouple-report-sender' into 'master'
Decouple DevReportSender from TorPlugin

See merge request akwizgran/briar!803
2018-05-17 09:52:47 +00:00
akwizgran
a65bda04bf Use more realistic LAN addresses for test contacts. 2018-05-17 10:22:29 +01:00
akwizgran
41ae7b0522 Merge branch 'internal-logger' into 'master'
Use internal log handler for crash reports and feedback

Closes #986

See merge request akwizgran/briar!802
2018-05-17 08:22:48 +00:00
akwizgran
c2214f5e61 Merge branch 'message-encrypter' into 'master'
Refactor MessageEncrypter main method

See merge request akwizgran/briar!800
2018-05-17 08:22:22 +00:00
akwizgran
75bd7927ac Decouple DevReportSender from TorPlugin. 2018-05-17 09:20:12 +01:00
akwizgran
ed2c0336ed Merge branch 'crash-button' into 'master'
Add crash button to UI in debug mode

See merge request akwizgran/briar!801
2018-05-16 11:19:15 +00:00
akwizgran
b23baf70b4 Don't send system logs in ACRA reports. 2018-05-16 11:53:00 +01:00
akwizgran
17a7144194 Add internal logger. 2018-05-16 11:52:55 +01:00
akwizgran
0f7d27cd95 Refactor MessageEncrypter main method. 2018-05-16 11:42:00 +01:00
akwizgran
6735e5075b Add crash button to UI in debug mode. 2018-05-16 11:40:50 +01:00
akwizgran
135cf086f6 Merge branch 'silence_strict_mode' into 'master'
Silence known strict mode violations

See merge request akwizgran/briar!795
2018-05-16 09:48:54 +00:00
goapunk
72bac59989 silence known strict mode violations 2018-05-15 17:29:53 +02:00
Torsten Grote
2c99a75b4e Merge branch 'settings-screen' into 'master'
Use lighter text colour for preference categories and fix layout

See merge request akwizgran/briar!799
2018-05-15 14:20:01 +00:00
Torsten Grote
5c068ed07b Merge branch 'remove-unbound-transport-keys' into 'master'
Remove support for unbound transport keys

See merge request akwizgran/briar!791
2018-05-15 14:18:58 +00:00
akwizgran
fec384c200 Add migration for NOT NULL constraint. 2018-05-15 14:37:36 +01:00
akwizgran
89a4d1922b Remove support for unbound transport keys. 2018-05-15 14:37:36 +01:00
akwizgran
6ed16802ce Merge branch 'deterministic-build-timestamp' into 'master'
Use git commit timestamp as build timestamp

See merge request akwizgran/briar!798
2018-05-15 13:24:00 +00:00
akwizgran
7f11d7280f Merge branch 'animal-sniffer' into 'master'
Use Animal Sniffer to check Java 6 API compatibility

See merge request akwizgran/briar!787
2018-05-15 13:23:29 +00:00
akwizgran
597e2a233f Use git commit timestamp as build timestamp. 2018-05-15 12:47:14 +01:00
akwizgran
e83d8bb700 Bump version numbers for 1.0.3 release. 2018-05-14 21:52:16 +01:00
akwizgran
d1ce0d0628 Merge branch '1215-low-memory-hide-ui' into 'master'
Clear the UI when memory is critically low

See merge request akwizgran/briar!786
2018-05-14 14:53:04 +00:00
akwizgran
d73ec3cd88 Merge branch 'disable-expiry' into 'master'
Disable expiry for release builds

See merge request akwizgran/briar!797
2018-05-14 14:51:40 +00:00
akwizgran
71c66c843b Merge branch '1219-commit-shared-prefs' into 'master'
Commit shared preferences, clear instead of deleting

See merge request akwizgran/briar!794
2018-05-14 14:18:49 +00:00
akwizgran
bd19272099 Throw exception if account exists when beginning setup. 2018-05-14 14:20:13 +01:00
akwizgran
b77b885a94 Commit shared preferences, clear instead of deleting. 2018-05-14 14:20:12 +01:00
akwizgran
1fc4f657c7 Merge branch '1219-account-exists' into 'master'
Add logging to debug account creation and deletion

See merge request akwizgran/briar!793
2018-05-14 13:19:20 +00:00
akwizgran
df7d48d54d Fix test expectations. 2018-05-14 12:35:03 +01:00
akwizgran
1987dcb936 Make field that's used on background thread volatile. 2018-05-14 12:34:32 +01:00
akwizgran
f3b69a26f8 Remove unused exception declarations. 2018-05-14 12:31:48 +01:00
akwizgran
5e0ca10dae Add logging to debug account setup. 2018-05-14 12:31:46 +01:00
akwizgran
685496fb15 Extract DatabaseConfig implementation. 2018-05-14 12:30:57 +01:00
akwizgran
1521cdd258 Move expiry date to TestingConstants. 2018-05-14 12:24:37 +01:00
akwizgran
80561910b1 Disable expiry for release builds. 2018-05-14 12:03:30 +01:00
akwizgran
bffb5c94ed Merge branch '1229-setup-crash' into 'master'
Store nickname and password across screen rotations

Closes #1229

See merge request akwizgran/briar!796
2018-05-14 09:57:12 +00:00
akwizgran
dcbb3e76d4 Use lighter text colour for preference categories. 2018-05-11 12:48:43 +01:00
akwizgran
c19f7c27b1 Merge branch 'stream-writer-interface' into 'master'
Send end of stream marker when sync session finishes

See merge request akwizgran/briar!790
2018-05-11 10:55:32 +00:00
akwizgran
9a5a1489ef Remove a redundant method. 2018-05-11 11:41:49 +01:00
akwizgran
648793e092 Add javadoc. 2018-05-11 11:36:49 +01:00
akwizgran
e10742a23d Store nickname and password across screen rotations. 2018-05-11 11:36:04 +01:00
akwizgran
32ada51831 Log transport ID with number of connected contacts. 2018-05-10 12:31:54 +01:00
akwizgran
7734a62c3e Interrupt outgoing session when incoming session ends. 2018-05-10 12:29:45 +01:00
akwizgran
e516c329a1 Bump version numbers for 1.0.2 release. 2018-05-09 16:59:09 +01:00
Torsten Grote
b839041d5a Update translations 2018-05-09 09:56:15 -03:00
Torsten Grote
65de8707b7 Merge branch '1225-improve-setup-ux' into 'master'
Remove circle, make button flat to improve setup UX

Closes #1225

See merge request akwizgran/briar!792
2018-05-09 10:41:17 +00:00
akwizgran
dc5bd39ce4 Remove circle, make button flat to improve setup UX. 2018-05-09 10:50:23 +01:00
akwizgran
3c4513b9c7 Convert test to BrambleMockTestCase. 2018-05-08 15:02:07 +01:00
akwizgran
5320737d49 Send end of stream marker when sync session finishes. 2018-05-08 14:41:53 +01:00
akwizgran
0ad9415850 Merge branch 'fix-javadoc' into 'master'
Fix random javadoc errors

See merge request akwizgran/briar!789
2018-05-08 12:56:25 +00:00
goapunk
6f1fba44b6 Fix random javadoc errors 2018-05-08 14:42:14 +02:00
akwizgran
46cd7e3719 Merge branch 'update_external_deps' into 'master'
Update external dependencies

See merge request akwizgran/briar!788
2018-05-08 12:34:44 +00:00
goapunk
496ffc22ba Update external dependencies
* Update CircleImageView
* Update Tap target prompt
2018-05-08 13:22:25 +02:00
akwizgran
286937e472 Resolve merge conflicts. 2018-05-07 14:37:32 +00:00
akwizgran
2908145a06 Merge branch 'android-studio-3-1-debugging' into 'master'
Upgrade to Android Studio 3.1

See merge request akwizgran/briar!784
2018-05-07 14:16:24 +00:00
akwizgran
ed53544226 Clear the UI in onLowMemory() if SDK_INT < 16. 2018-05-04 12:18:52 +01:00
akwizgran
6da45a4585 Clear the UI when memory is critically low. 2018-05-04 12:04:13 +01:00
akwizgran
0d85a56a29 Merge branch '1216-fix-testdata' into 'master'
Resolve "IllegalArgumentException when creating test data with zero contacts"

Closes #1216

See merge request akwizgran/briar!785
2018-05-03 08:39:23 +00:00
goapunk
3e5d1a0d20 Fix testdata creation:
* Create at least one contact
2018-05-02 20:49:33 +02:00
akwizgran
0e9af1d993 Add new code style settings. 2018-05-02 17:13:27 +01:00
akwizgran
a3b5ff0bc0 Add dependency hashes for Animal Sniffer. 2018-05-02 16:24:59 +01:00
akwizgran
9b583ab7ae Build tools 26.0.2 no longer needed. 2018-05-02 16:14:40 +01:00
akwizgran
1192f66487 Use Animal Sniffer to check Java 6 API compatibility. 2018-05-02 16:10:40 +01:00
akwizgran
a10dc45a6a Remove old attempt to work around build issues. 2018-05-02 15:11:21 +01:00
akwizgran
3c6e2e8875 Upgrade support library and constraint layout. 2018-05-02 15:06:34 +01:00
akwizgran
cccdacc3e4 Upgrade to Android Studio 3.1. 2018-05-02 14:34:34 +01:00
akwizgran
1833efa51b Bump version numbers for 1.0.1 release. 2018-04-30 18:05:57 +01:00
akwizgran
77461619f0 Merge branch '1217-get-message-status' into 'master'
Return default message status if group is invisible

Closes #1217

See merge request akwizgran/briar!783
2018-04-30 16:23:19 +00:00
Torsten Grote
3bed6de93b Update translations 2018-04-30 12:52:46 -03:00
Torsten Grote
8e814e1bbf Merge branch '1215-disable-low-memory-shutdowns' into 'master'
Disable low memory shutdowns

See merge request akwizgran/briar!782
2018-04-30 13:43:17 +00:00
akwizgran
1b9f975199 Return default message status if group is invisible. 2018-04-30 13:55:40 +01:00
akwizgran
c1b8552c2b Merge branch 'introduction-test-fix' into 'master'
Fix introduction test non-determinism

See merge request akwizgran/briar!781
2018-04-30 08:05:00 +00:00
akwizgran
0091fcef5d Updated translations. 2018-04-30 07:46:00 +01:00
akwizgran
5d1a4acd15 Disable low memory shutdowns. 2018-04-30 07:43:16 +01:00
akwizgran
9be6d6c00f Bump version numbers for 1.0.0 release. 2018-04-29 20:28:53 +01:00
akwizgran
d5643d8e5d Merge branch '617-protocol-versioning-for-contact-exchange' into 'master'
Protocol versioning for the contact exchange protocol

Closes #617

See merge request akwizgran/briar!765
2018-04-29 16:40:05 +00:00
Torsten Grote
d9ed4a3ac9 Fix introduction test non-determinism 2018-04-29 13:33:59 -03:00
akwizgran
30bfa91fc4 Use new client helper methods for transport properties. 2018-04-29 17:27:46 +01:00
akwizgran
c3e4742bfe Use buffers for record headers. No need to buffer payloads. 2018-04-29 17:27:45 +01:00
akwizgran
d4b87983e8 Avoid an unnecessary copy when parsing messages. 2018-04-29 17:27:42 +01:00
akwizgran
eed1439745 Use generic record reader/writer for contact exchange. 2018-04-29 17:26:45 +01:00
akwizgran
4ba3708931 Use wildcards to allow easier construction. 2018-04-29 17:26:45 +01:00
akwizgran
215c62ed23 Use generic record reader/writer for sync. 2018-04-29 17:26:42 +01:00
akwizgran
4100daaa47 Rename sync record reader/writer. 2018-04-29 17:25:35 +01:00
akwizgran
6fa6ceb5ee Use generic record reader/writer for key agreement. 2018-04-29 17:25:34 +01:00
akwizgran
cc2791c37f Unit tests for generic record reader/writer. 2018-04-29 17:25:34 +01:00
akwizgran
20a131bec5 Add generic record reader and writer. 2018-04-29 17:25:34 +01:00
Torsten Grote
edee90dbe2 Merge branch '237-versioning-client' into 'master'
Client for negotiating supported clients

Closes #237

See merge request akwizgran/briar!759
2018-04-29 16:08:08 +00:00
akwizgran
fd78139a5a Remove stale comments. 2018-04-29 16:40:29 +01:00
akwizgran
41242ef369 Check that there's only one local client versions message. 2018-04-29 16:40:29 +01:00
akwizgran
c55bef95ce Fix rebasing mistakes. 2018-04-29 16:40:29 +01:00
akwizgran
fb6b487212 Unit tests for client versioning manager. 2018-04-29 16:40:28 +01:00
akwizgran
97f40bd20b Check whether hooks need to be called before loading contact. 2018-04-29 16:40:28 +01:00
akwizgran
36b191e9d4 Use remote states to update local states at startup. 2018-04-29 16:40:28 +01:00
akwizgran
ebaa50b101 Don't send redundant updates to new contacts. 2018-04-29 16:40:28 +01:00
akwizgran
4c5331888a Unit tests for client versioning validator. 2018-04-29 16:40:27 +01:00
akwizgran
c5efb6e16d Move versioning client to its own package. 2018-04-29 16:40:27 +01:00
akwizgran
522cba6ac3 Rename utility classes, add comment. 2018-04-29 16:40:27 +01:00
akwizgran
f25fbc5b94 Merge registration methods for clients and hooks. 2018-04-29 16:40:27 +01:00
akwizgran
57a6c8cb3a Separate the crypto executor into its own module.
This allows it to be replaced for testing.
2018-04-29 16:40:26 +01:00
akwizgran
6942a368d4 Don't share groups unless the contact supports the client. 2018-04-29 16:40:26 +01:00
akwizgran
c4e9b6f2ab Remove debug logging. 2018-04-29 16:40:26 +01:00
akwizgran
05deaf42e3 Store and exchange client minor versions.
These don't affect client visibility.
2018-04-29 16:40:26 +01:00
akwizgran
2e570ba50d Rename client version to major version. 2018-04-29 16:40:23 +01:00
akwizgran
cadb17987c Use client versioning for messaging. 2018-04-29 16:39:54 +01:00
akwizgran
e76f114a72 Use client versioning for introductions. 2018-04-29 16:39:54 +01:00
akwizgran
cb11b55a9a Use client versioning for transport properties. 2018-04-29 16:39:54 +01:00
akwizgran
f4c5855dd8 Use client versioning for private groups. 2018-04-29 16:39:53 +01:00
akwizgran
be309057cd Use client versioning for blogs and forums. 2018-04-29 16:39:53 +01:00
akwizgran
cf396c2ce2 Check whether contact group exists before using it. 2018-04-29 16:39:53 +01:00
akwizgran
a9f77f0f90 Add a method for getting a client's visibility. 2018-04-29 16:39:53 +01:00
akwizgran
cc6fed0298 Add javadocs. 2018-04-29 16:39:53 +01:00
akwizgran
66137d4cfa Add method for comparing visibilities. 2018-04-29 16:39:52 +01:00
akwizgran
114044ee5f Use client version to register validators, delivery hooks. 2018-04-29 16:39:52 +01:00
akwizgran
1197d65d8d Extract ClientVersion inner class. 2018-04-29 16:39:52 +01:00
akwizgran
85c11f8e1f Remove redundant checks when adding contacts.
Hooks are now called exactly once per contact.
2018-04-29 16:39:52 +01:00
akwizgran
8c00f2417b Add client version to groups table. 2018-04-29 16:39:51 +01:00
akwizgran
a38f39207f Initial implementation of client versioning client. 2018-04-29 16:39:51 +01:00
akwizgran
b7874365a3 Expose getMessageIds() through DatabaseComponent interface. 2018-04-29 16:39:51 +01:00
akwizgran
196caa7b45 Update ID of transport properties client. 2018-04-29 16:39:51 +01:00
akwizgran
3fd6ce2313 Fix javadoc. 2018-04-29 16:39:50 +01:00
akwizgran
c42852cde2 Merge branch '1213-update-transport-keys' into 'master'
Update transport keys in-place to retain key set IDs

Closes #1213

See merge request akwizgran/briar!779
2018-04-29 15:00:02 +00:00
Torsten Grote
a38b0a8527 Merge branch 'bluetooth-connection-limiter' into 'master'
Don't make or accept Bluetooth contact connections during key agreement

See merge request akwizgran/briar!770
2018-04-29 14:42:00 +00:00
Torsten Grote
79d6fd28de Merge branch '474-alice-flag' into 'master'
IntroduceeProtocolEngine uses wrong role when adding keys

See merge request akwizgran/briar!780
2018-04-29 02:27:18 +00:00
akwizgran
68132d893b IntroduceeProtocolEngine uses wrong role when adding keys. 2018-04-28 23:04:08 +01:00
akwizgran
6b011d2a7d Update transport keys in-place to retain key set IDs. 2018-04-28 22:15:59 +01:00
akwizgran
d7492df81c Skip UTestTest, which literally fails at random. 2018-04-28 14:52:56 +01:00
Torsten Grote
ebf73716bb Merge branch '474-manual-decline' into 'master'
Don't automatically respond to declined introductions

See merge request akwizgran/briar!777
2018-04-28 13:46:40 +00:00
akwizgran
6e42377b74 Don't automatically respond to declined introduction. 2018-04-28 00:11:45 +01:00
akwizgran
e8f33c0e6e Merge branch 'introduction-ui-messages' into 'master'
Fix introduction response messages in UI and some minor fixes

Closes #923

See merge request akwizgran/briar!776
2018-04-27 21:42:10 +00:00
Torsten Grote
5f6af4e40f Fix introduction response messages in UI and some minor fixes 2018-04-27 16:22:10 -03:00
Torsten Grote
55a329a879 Merge branch '474-automatic-decline' into 'master'
Send automatic decline when other introducee declines

See merge request akwizgran/briar!775
2018-04-27 17:58:45 +00:00
akwizgran
23f0864d8b Don't track invisible decline message. 2018-04-27 18:35:07 +01:00
akwizgran
c0dfe3e85a Sent automatic decline when other introducee declines. 2018-04-27 17:33:24 +01:00
Torsten Grote
31b69577e8 Merge branch '474-introduction-client' into 'master'
New Introduction Protocol

Closes #308, #377, #474, and #613

See merge request akwizgran/briar!758
2018-04-27 14:43:01 +00:00
Torsten Grote
99dba69c87 Only add transport properties and keys when the contact was added
This will be changed once we have a way to reset state for peers
that were contacts already at some point in the past.
One contact might have deleted the other, but not vice versa.
So they have mismatching state that needs to be reset.

See #2 for more information.
2018-04-27 11:30:18 -03:00
Torsten Grote
44f5a9db1e Address last review comments 2018-04-27 11:04:08 -03:00
Torsten Grote
80a9689316 Address second round of review comments 2018-04-26 20:39:17 -03:00
Torsten Grote
337f7e7b8f Unify introduction response methods and handle ProtocolStateException
It is possible that a remote DECLINE message arrives short before the
user responds to the introduction.
This will cause a ProtocolStateException which (for now) is just caught
and a generic (existing) error message will be shown.
2018-04-26 18:18:31 -03:00
Torsten Grote
f8f98ed95d Properly handle DECLINE messages in START state
Previously, DECLINE messages let directly to the START state
for introducer and introducees.
So incoming ACCEPT and DECLINE messages needed to be ignored in START state
introducing undefined behavior into the protocol.

This is fixed with this commit by adding two additional states
to the introducer state machine as well as making use of the existing
LOCAL_DECLINED state for the introducees.
2018-04-26 18:00:57 -03:00
Torsten Grote
bd5504de26 Add a MAC to the ACTIVATE message to prevent the introducer to fake them
A fake ACTIVATE message would cause us to activate the transport keys
before the contact has received our auth message,
which would compromise forward secrecy.
2018-04-26 16:56:38 -03:00
Torsten Grote
0e04044ebb Ensure that incoming messages are expected in the current state
Previously, the introducer would process and forward invalid messages by
the introducees. This commit adds the necessary checks and tests.
2018-04-26 11:18:04 -03:00
Torsten Grote
0a5d408686 Add a test for when one introducee had deleted the other one 2018-04-25 14:42:17 -03:00
Torsten Grote
f94db28035 Handle and test introductions to existing contacts 2018-04-25 13:30:51 -03:00
Torsten Grote
b291fcd2cd Only allow new introductions in START state
When the user attempts an introduction, instead of the introduction
message input field, an explanatory text will be shown and the
introduction can not be made until the last one has been finished.
2018-04-25 12:05:15 -03:00
Torsten Grote
94a6137a42 Also validate encoded message in MessageEncoder test 2018-04-25 10:52:32 -03:00
Torsten Grote
72e9a9d807 Address first round of review comments for new IntroductionClient 2018-04-25 10:43:56 -03:00
Torsten Grote
a9b678df32 Remove broken and deprecated MessageQueue as it is not needed anymore
Closes #308
2018-04-25 10:14:04 -03:00
Torsten Grote
f81ef30b47 Replace old introduction client with new one 2018-04-25 10:14:01 -03:00
Torsten Grote
1bc29fec06 IntroductionManager and Protocol Engines 2018-04-25 10:13:41 -03:00
Torsten Grote
61b216f572 Copy over Introduction API messages and events from old client 2018-04-25 10:13:41 -03:00
Torsten Grote
d57102ed90 IntroductionCrypto: Create dedicated class to handle introduction related crypto 2018-04-25 10:13:40 -03:00
Torsten Grote
e1fae7ad95 Implement SessionEncoder and SessionParser 2018-04-25 10:13:40 -03:00
Torsten Grote
672a52b2e5 Implement MessageEncoder and MessageParser 2018-04-25 10:13:39 -03:00
Torsten Grote
155c6a5613 Messages and Validator for new Introduction Client 2018-04-25 10:13:39 -03:00
Torsten Grote
218b2f7ff9 Fix activating transport keys in JdbcDatabase 2018-04-25 10:13:38 -03:00
Torsten Grote
f78f065204 Merge branch 'constant-time-mac-verification' into 'master'
Add constant-time method for verifying MACs

See merge request akwizgran/briar!773
2018-04-25 12:08:49 +00:00
akwizgran
0217c205a1 Add constant-time method for verifying MACs. 2018-04-25 12:23:46 +01:00
akwizgran
615f527270 Renamed method that now runs on IoExecutor. 2018-04-24 17:43:28 +01:00
akwizgran
b9cf1da861 Merge branch 'test_data_config' into 'master'
Make test data creation configurable.

Closes #1149

See merge request akwizgran/briar!771
2018-04-24 16:35:15 +00:00
goapunk
69c34adae3 Remove createTestData() 2018-04-24 16:57:02 +02:00
goapunk
fe213d46e3 Address review comments 2018-04-24 16:05:46 +02:00
goapunk
ac1bfcae60 Make test data creation configurable. 2018-04-24 12:29:20 +02:00
akwizgran
9efb6ab38f Don't allow BT contact connections during key agreement. 2018-04-24 10:45:23 +01:00
akwizgran
b30c2a8033 Merge branch 'fix_bt_test_data' into 'master'
Create a valid BT MAC and UUID when creating testdata

See merge request akwizgran/briar!769
2018-04-24 09:26:42 +00:00
goapunk
575847cb36 Create a valid BT MAC and UUID when creating testdata 2018-04-23 21:05:14 +02:00
akwizgran
951605151f Merge branch 'transport-properties' into 'master'
Helper methods for dealing with TransportProperties

See merge request akwizgran/briar!768
2018-04-23 09:05:14 +00:00
Torsten Grote
05735e7a48 Add methods for dealing with TransportProperties to ClientHelper 2018-04-21 18:23:34 -03:00
Torsten Grote
f835e82653 Merge branch 'download-briar-button' into 'master'
Add download button to ExpiredActivity

See merge request akwizgran/briar!766
2018-04-19 17:11:49 +00:00
akwizgran
d074e4a3d6 Add download button to ExpiredActivity. 2018-04-19 17:39:07 +01:00
akwizgran
87a92c9ab6 Merge branch 'parse-transport-properties' into 'master'
Helper method for parsing transport properties

See merge request akwizgran/briar!764
2018-04-19 16:01:16 +00:00
akwizgran
89cc769dea Don't accept empty keys/values in transport properties. 2018-04-19 16:48:59 +01:00
akwizgran
fcdc6ebafd Helper methods for parsing transport properties. 2018-04-19 16:20:32 +01:00
akwizgran
215d236c2c Merge branch 'forward-compatible-message-ids' into 'master'
Generate message and group IDs in a forward-compatible way

See merge request akwizgran/briar!763
2018-04-19 14:55:39 +00:00
Torsten Grote
e1b8b271e3 Merge branch 'offline-build' into 'master'
Don't download Tor binaries if they already exist

See merge request akwizgran/briar!760
2018-04-19 13:08:21 +00:00
akwizgran
9379990480 Use block label for root hash of single-block messages. 2018-04-19 13:13:31 +01:00
akwizgran
c7718db419 Skip second verification if first succeeds. 2018-04-18 17:01:02 +01:00
akwizgran
9196169561 Generate message and group IDs in a forward-compatible way. 2018-04-18 16:34:02 +01:00
akwizgran
ff9971b728 If verification fails, delete, download and re-verify. 2018-04-18 11:03:39 +01:00
Torsten Grote
8decc73f4d Merge branch 'max-client-id-length' into 'master'
Set max length for client IDs

See merge request akwizgran/briar!762
2018-04-17 19:01:22 +00:00
akwizgran
d23fc2cbda Use TestUtils to create groups. 2018-04-17 17:57:06 +01:00
akwizgran
58d1707467 Set max length for client IDs. 2018-04-17 17:57:00 +01:00
akwizgran
b08b2c691c Merge branch 'merge-contact-hooks' into 'master'
Merge add/remove contact hooks

See merge request akwizgran/briar!761
2018-04-17 16:53:22 +00:00
akwizgran
284e3a2e86 Merge add/remove contact hooks. 2018-04-17 16:20:16 +01:00
akwizgran
0823934e28 Don't download Tor binaries if they already exist. 2018-04-17 15:07:52 +01:00
akwizgran
95b9b3a3c6 Merge branch 'multiple-transport-keys' into 'master'
Support multiple sets of transport keys per contact

See merge request akwizgran/briar!745
2018-04-17 14:02:45 +00:00
Torsten Grote
ede390b897 Merge branch '1180-tor-plugin-status' into 'master'
Don't reset Tor connectivity state unless we lose connectivity

Closes #1180

See merge request akwizgran/briar!756
2018-03-30 15:49:20 +00:00
akwizgran
5b790130d4 Don't reset circuit built flag unless network is disabled. 2018-03-30 16:33:03 +01:00
akwizgran
ff44edf714 Merge branch '1171-wifi-access-point' into 'master'
Enable LAN plugin when providing a wifi access point

Closes #1171

See merge request akwizgran/briar!752
2018-03-29 15:17:46 +00:00
Torsten Grote
60dffd0998 Update translations, add Romanian 2018-03-29 10:38:01 -03:00
akwizgran
46dae59444 Delay handling of AP enabled event. 2018-03-29 14:34:58 +01:00
Torsten Grote
e385d58148 Merge branch '1190-shutdown-from-background' into 'master'
Shut down cleanly when phone is shutting down or memory is low

Closes #1190

See merge request akwizgran/briar!742
2018-03-29 13:29:42 +00:00
akwizgran
b20626935e AP state change event races with address appearing. 2018-03-29 12:26:42 +01:00
akwizgran
8e9fc3b338 Enable LAN plugin to use wifi AP interface. 2018-03-29 12:26:42 +01:00
akwizgran
c3a70fe58d Serialise concurrent calls to updateConnectionStatus(). 2018-03-29 12:26:42 +01:00
akwizgran
ddfaddccdc Serialise concurrent calls to bind(). 2018-03-29 12:26:41 +01:00
akwizgran
4a892acdd5 Merge branch '845-wifi-without-internet' into 'master'
Looks like I added the last commit after the MR was merged.
2018-03-29 12:25:02 +01:00
akwizgran
bdb518ff09 Use wifi network's socket factory on API 21+. 2018-03-29 12:23:42 +01:00
akwizgran
8ebced9481 Show notification for low memory shutdown. 2018-03-29 11:45:03 +01:00
akwizgran
b81058d6da Activate outgoing keys when incoming tag is recognised. 2018-03-28 12:39:03 +01:00
akwizgran
f7c2f86499 Add a method for checking whether we can send streams. 2018-03-28 12:39:03 +01:00
akwizgran
798b871cc9 Use key set ID to increment stream counter. 2018-03-28 12:39:02 +01:00
akwizgran
6787d29f11 Add a flag to indicate whether outgoing keys are active. 2018-03-28 12:39:02 +01:00
akwizgran
57e6f2ea9c Unit tests for removing unbound keys. 2018-03-28 12:39:02 +01:00
akwizgran
0a802bbe0b Add a method for removing unbound transport keys. 2018-03-28 12:39:02 +01:00
akwizgran
17fe358fd9 Add a method for binding transport keys to a contact. 2018-03-28 12:39:01 +01:00
akwizgran
5bd2092a03 Return key set IDs when adding unbound keys. 2018-03-28 12:39:01 +01:00
akwizgran
cb8f89db53 Add method for adding a contact without transport keys. 2018-03-28 12:39:01 +01:00
akwizgran
bb2f94d5eb Add methods for adding unbound keys. 2018-03-28 12:39:01 +01:00
akwizgran
78f2d48bc4 Support multiple sets of transport keys per contact. 2018-03-28 12:38:59 +01:00
Torsten Grote
309c7a4668 Merge branch '965-empty-state-messages' into 'master'
Shorten and clean up various strings, remove empty forum warning bubble

See merge request akwizgran/briar!741
2018-03-26 16:59:12 +00:00
Torsten Grote
750f2b1b75 Merge branch 'hide-ui-during-shutdown' into 'master'
Hide UI during shutdown

See merge request akwizgran/briar!737
2018-03-26 16:53:16 +00:00
Torsten Grote
e7b2fe1906 Merge branch '545-message-dependencies' into 'master'
Add denormalised columns to messageDependencies table

See merge request akwizgran/briar!733
2018-03-26 15:58:01 +00:00
akwizgran
bfd22cfced Merge branch '346-full-screen-qr-code' into 'master'
Add fullscreen button to QR code view

Closes #346

See merge request akwizgran/briar!734
2018-03-26 15:30:30 +00:00
akwizgran
ea0223ef1e Merge branch '1159-android-8-notification-settings' into 'master'
Show different notification settings for Android O

Closes #1159

See merge request akwizgran/briar!727
2018-03-26 15:24:28 +00:00
Torsten Grote
38b739442c Merge branch '845-wifi-without-internet' into 'master'
Use WifiManager to get wifi network information

Closes #845

See merge request akwizgran/briar!743
2018-03-26 14:54:03 +00:00
Torsten Grote
25f9ab7c33 Merge branch '1184-rejected-execution-exception' into 'master'
Discard tasks submitted to ScheduledExecutorService during shutdown

Closes #1184

See merge request akwizgran/briar!739
2018-03-26 14:27:42 +00:00
akwizgran
e0a1fa559d Use WifiManager to get wifi network information.
This ensures we bind to the wifi interface even if it doesn't have internet access and there's another interface with internet access (e.g. mobile data).
2018-03-26 13:58:10 +01:00
akwizgran
196cf15ef2 Shut down cleanly when device shuts down. 2018-03-21 14:42:30 +00:00
akwizgran
6ff0f317a5 Shut down cleanly when memory is low. 2018-03-21 14:31:12 +00:00
Torsten Grote
5a3f47d72c Merge branch '965-forum-empty-state' into 'master'
Remove mention of pen icon from forum empty state message

Closes #965

See merge request akwizgran/briar!740
2018-03-21 11:45:30 +00:00
akwizgran
7e784c6be1 Remove empty forum warning bubble. 2018-03-21 10:30:49 +00:00
akwizgran
3ee212f3ab Consistent text for blogs and forums. 2018-03-21 10:28:10 +00:00
akwizgran
ee942790d3 Shorter empty state messages. 2018-03-21 10:27:09 +00:00
akwizgran
2d740675c7 Consistent explanation of account deletion options. 2018-03-21 10:24:17 +00:00
akwizgran
e4f3960ce0 Remove mention of pen icon from forum empty state message. 2018-03-21 10:18:18 +00:00
akwizgran
fef916991b Discard tasks submitted during shutdown. 2018-03-20 17:41:30 +00:00
akwizgran
3fa38d3b28 Finish if back button is pressed in SignOutFragment. 2018-03-20 16:50:40 +00:00
akwizgran
48c41f77c7 Use database icon for SignOutFragment. 2018-03-20 16:50:40 +00:00
akwizgran
c3bf82c5b2 Close NavDrawerActivity immediately when signing out. 2018-03-20 16:50:40 +00:00
akwizgran
74fe36c46e Use selectable item background to get touch effect. 2018-03-20 15:30:46 +00:00
akwizgran
0d5d1f4cb2 Adjust layout weights when resizing QR code view. 2018-03-20 15:22:58 +00:00
akwizgran
2c4d5680a6 Add fullscreen button to QR code view. 2018-03-20 11:14:27 +00:00
akwizgran
9e2e0585c5 Index dependencies by dependency ID. 2018-03-14 16:08:01 +00:00
akwizgran
2367e6c481 Add denormalised columns to messageDependencies table. 2018-03-14 15:33:00 +00:00
Torsten Grote
ff8b38f7e8 Use a different notification preference summary for Android 8 2018-03-14 10:01:38 -03:00
Torsten Grote
f609ad1a92 Show different notification settings for Android O
This also makes the defaults consistent with Android versions below O.
2018-03-14 09:41:09 -03:00
akwizgran
a0c88da1ac Report UNKNOWN state for cross-group dependencies.
This causes the validator to treat the dependent message in the same way regardless of whether there is a subscription to the dependency's group.
2018-03-14 11:25:24 +00:00
749 changed files with 24772 additions and 14366 deletions

2
.gitignore vendored
View File

@@ -20,7 +20,9 @@ local.properties
.idea/* .idea/*
!.idea/runConfigurations/ !.idea/runConfigurations/
!.idea/codeStyleSettings.xml !.idea/codeStyleSettings.xml
!.idea/codeStyles
.gradle .gradle
build/ build/
captures
*.iml *.iml
projectFilesBackup/ projectFilesBackup/

View File

@@ -1,29 +1,27 @@
image: registry.gitlab.com/fdroid/ci-images-base:latest image: briar/ci-image-android:latest
cache:
paths:
- .gradle/wrapper
- .gradle/caches
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
# Accept the license for the Android build tools
- echo y | /opt/android-sdk/tools/bin/sdkmanager "build-tools;26.0.2"
# Download OpenJDK 6 so we can compile against its standard library
- JDK_FILE=openjdk-6-jre-headless_6b38-1.13.10-1~deb7u1_amd64.deb
- if [ ! -d openjdk ]
- then
- wget -q http://ftp.uk.debian.org/debian/pool/main/o/openjdk-6/$JDK_FILE
- dpkg-deb -x $JDK_FILE openjdk
- fi
- export JAVA_6_HOME=$PWD/openjdk/usr/lib/jvm/java-6-openjdk-amd64
test: test:
script: before_script:
- ./gradlew test - set -e
- export GRADLE_USER_HOME=$PWD/.gradle
after_script: cache:
# this file changes every time but should not be cached paths:
- .gradle/wrapper
- .gradle/caches
script:
- ./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
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock - rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/ - rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
test_reproducible:
script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only:
- tags

261
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,261 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
</JavaCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="Groovy">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="80" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="ASSERT_STATEMENT_WRAP" value="1" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="1" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -21,6 +21,7 @@
<method> <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-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-core" 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-j2se" 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 briar-core" run_configuration_type="AndroidJUnit" /> <option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
</method> </method>

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,20 +1,19 @@
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'witness' apply plugin: 'witness'
apply plugin: 'de.undercouch.download' apply from: 'witness.gradle'
android { android {
compileSdkVersion 27 compileSdkVersion 27
buildToolsVersion '26.0.2' buildToolsVersion '27.0.3'
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 1700 versionCode 10013
versionName "0.17.0" versionName "1.0.13"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
compileOptions { compileOptions {
@@ -23,74 +22,41 @@ android {
} }
} }
configurations {
tor
}
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar') tor 'org.briarproject:tor-android:0.2.9.16@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification { testImplementation project(path: ':bramble-api', configuration: 'testOutput')
verify = [ testImplementation 'junit:junit:4.12'
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', testImplementation "org.jmock:jmock:2.8.2"
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3', testImplementation "org.jmock:jmock-junit4:2.8.2"
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b', testImplementation "org.jmock:jmock-legacy:2.8.2"
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9', testImplementation "org.hamcrest:hamcrest-library:1.3"
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99', testImplementation "org.hamcrest:hamcrest-core:1.3"
'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.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128-runtime.jar:e357a0f1d573c2f702a273992b1b6cb661734f66311854efb3778a888515c5b5',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128.jar:47b4bec6df11a1118da3953da8b9fa1e7079d6fec857faa1a3cf912e53a6fd4e',
'org.jacoco:org.jacoco.ant:0.7.4.201502262128:org.jacoco.ant-0.7.4.201502262128.jar:013ce2a68ba57a3c59215ae0dec4df3498c078062a38c3b94c841fc14450f283',
'org.jacoco:org.jacoco.core:0.7.4.201502262128:org.jacoco.core-0.7.4.201502262128.jar:ec4c74554312fac5116350164786f91b35c9e082fa4ea598bfa42b5db05d7abb',
'org.jacoco:org.jacoco.report:0.7.4.201502262128:org.jacoco.report-0.7.4.201502262128.jar:7a3554c605e088e7e323b1084656243f0444fa353e2f2dee1f1a4204eb64ff09',
'org.ow2.asm:asm-debug-all:5.0.1:asm-debug-all-5.0.1.jar:4734de5b515a454b0096db6971fb068e5f70e6f10bbee2b3bd2fdfe5d978ed57',
]
}
ext.torBinaryDir = 'src/main/res/raw' androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
ext.torVersion = '0.2.9.14' androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
ext.geoipVersion = '2017-11-06' androidTestImplementation 'com.android.support.test:runner:1.0.2'
ext.torDownloadUrl = 'https://briarproject.org/build/' androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
def torBinaries = [
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
]
def downloadBinary(name) {
return tasks.create("downloadBinary${name}", Download) {
src "${torDownloadUrl}${name}.zip"
.replace('tor_', "tor-${torVersion}-")
.replace('geoip', "geoip-${geoipVersion}")
.replaceAll('_', '-')
dest "${torBinaryDir}/${name}.zip"
onlyIfNewer true
}
}
def verifyBinary(name, chksum) {
return tasks.create([
name : "verifyBinary${name}",
type : Verify,
dependsOn: downloadBinary(name)]) {
src "${torBinaryDir}/${name}.zip"
algorithm 'SHA-256'
checksum chksum
}
} }
project.afterEvaluate { project.afterEvaluate {
torBinaries.every { key, value -> copy {
preBuild.dependsOn.add(verifyBinary(key, value)) from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
} }
} }
tasks.withType(Test) {
// Use entropy-gathering device specified on command line, if any
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
}

View File

@@ -0,0 +1,130 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.support.test.runner.AndroidJUnit4;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
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.test.BrambleAndroidIntegrationTestComponent;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.DaggerBrambleAndroidIntegrationTestComponent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class BridgeTest extends BrambleTestCase {
private final static long TIMEOUT = SECONDS.toMillis(23);
private final static Logger LOG =
Logger.getLogger(BridgeTest.class.getName());
@Inject
NetworkManager networkManager;
@Inject
ResourceProvider resourceProvider;
@Inject
CircumventionProvider circumventionProvider;
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final Context appContext =
getTargetContext().getApplicationContext();
private List<String> bridges;
private AndroidTorPluginFactory factory;
private volatile String currentBridge = null;
@Before
public void setUp() {
BrambleAndroidIntegrationTestComponent component =
DaggerBrambleAndroidIntegrationTestComponent.builder().build();
component.inject(this);
Executor ioExecutor = Executors.newCachedThreadPool();
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
LocationUtils locationUtils = () -> "US";
SocketFactory torSocketFactory = SocketFactory.getDefault();
bridges = circumventionProvider.getBridges();
CircumventionProvider bridgeProvider = new CircumventionProvider() {
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return true;
}
@Override
public boolean doBridgesWork(String countryCode) {
return true;
}
@Override
public List<String> getBridges() {
return singletonList(currentBridge);
}
};
factory = new AndroidTorPluginFactory(ioExecutor, scheduler, appContext,
networkManager, locationUtils, eventBus, torSocketFactory,
backoffFactory, resourceProvider, bridgeProvider, clock);
}
@Test
public void testBridges() throws Exception {
assertTrue(bridges.size() > 0);
for (String bridge : bridges) testBridge(bridge);
}
private void testBridge(String bridge) throws Exception {
DuplexPlugin duplexPlugin =
factory.createPlugin(new TorPluginCallBack());
assertNotNull(duplexPlugin);
AndroidTorPlugin plugin = (AndroidTorPlugin) duplexPlugin;
currentBridge = bridge;
LOG.warning("Testing " + bridge);
try {
plugin.start();
long start = clock.currentTimeMillis();
while (clock.currentTimeMillis() - start < TIMEOUT) {
if (plugin.isRunning()) return;
clock.sleep(500);
}
if (!plugin.isRunning()) {
fail("Could not connect to Tor within timeout.");
}
} finally {
plugin.stop();
}
}
}

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
@NotNullByDefault
public class TorPluginCallBack implements DuplexPluginCallback {
@Override
public void incomingConnectionCreated(DuplexTransportConnection d) {
}
@Override
public void outgoingConnectionCreated(ContactId c,
DuplexTransportConnection d) {
}
@Override
public Settings getSettings() {
return new Settings();
}
@Override
public TransportProperties getLocalProperties() {
return new TransportProperties();
}
@Override
public void mergeSettings(Settings s) {
}
@Override
public void mergeLocalProperties(TransportProperties p) {
}
@Override
public void transportEnabled() {
}
@Override
public void transportDisabled() {
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.test;
import android.app.Application;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static android.support.test.InstrumentationRegistry.getTargetContext;
@Module
class ApplicationModule {
@Provides
@Singleton
Application provideApplication() {
return (Application) getTargetContext().getApplicationContext();
}
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleAndroidModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
import org.briarproject.bramble.system.SystemModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
BrambleAndroidModule.class,
TestLifecycleModule.class,
ApplicationModule.class,
PluginModule.class, // needed for BackoffFactory
EventModule.class,
SystemModule.class,
})
public interface BrambleAndroidIntegrationTestComponent {
void inject(BridgeTest init);
}

View File

@@ -2,14 +2,13 @@
package="org.briarproject.bramble" package="org.briarproject.bramble"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.bluetooth"/> <uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application <application

View File

@@ -1,13 +1,16 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.plugin.AndroidPluginModule; import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module; import dagger.Module;
@Module(includes = { @Module(includes = {
AndroidPluginModule.class, AndroidNetworkModule.class,
AndroidSystemModule.class AndroidSystemModule.class,
CircumventionModule.class
}) })
public class BrambleAndroidModule { public class BrambleAndroidModule {
} }

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,69 +0,0 @@
package org.briarproject.bramble.plugin;
import android.app.Application;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.Scheduler;
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.net.SocketFactory;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidPluginModule {
@Provides
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
@Scheduler ScheduledExecutorService scheduler,
AndroidExecutor androidExecutor, SecureRandom random,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Application app, LocationUtils locationUtils, DevReporter reporter,
EventBus eventBus) {
Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth =
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
appContext, random, eventBus, backoffFactory);
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
appContext, locationUtils, reporter, eventBus,
torSocketFactory, backoffFactory);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
backoffFactory, appContext);
Collection<DuplexPluginFactory> duplex =
Arrays.asList(bluetooth, tor, lan);
@NotNullByDefault
PluginConfig pluginConfig = new PluginConfig() {
@Override
public Collection<DuplexPluginFactory> getDuplexFactories() {
return duplex;
}
@Override
public Collection<SimplexPluginFactory> getSimplexFactories() {
return Collections.emptyList();
}
};
return pluginConfig;
}
}

View File

@@ -38,6 +38,7 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_OFF;
import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -55,10 +56,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
// Non-null if the plugin started successfully // Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null; private volatile BluetoothAdapter adapter = null;
AndroidBluetoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor, AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Backoff backoff, Context appContext, SecureRandom secureRandom, Backoff backoff,
DuplexPluginCallback callback, int maxLatency) { DuplexPluginCallback callback, int maxLatency) {
super(ioExecutor, secureRandom, backoff, callback, maxLatency); super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency);
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.appContext = appContext; this.appContext = appContext;
} }
@@ -143,7 +146,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try { try {
if (ss != null) ss.close(); if (ss != null) ss.close();
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); logException(LOG, WARNING, e);
} }
} }
@@ -154,7 +157,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
} }
private DuplexTransportConnection wrapSocket(BluetoothSocket s) { private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
return new AndroidBluetoothTransportConnection(this, s); return new AndroidBluetoothTransportConnection(this,
connectionLimiter, s);
} }
@Override @Override
@@ -182,7 +186,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); logException(LOG, WARNING, e);
} }
} }

View File

@@ -59,11 +59,13 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
@Override @Override
public DuplexPlugin createPlugin(DuplexPluginCallback callback) { public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl();
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(ioExecutor, AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
androidExecutor, appContext, secureRandom, backoff, callback, connectionLimiter, ioExecutor, androidExecutor, appContext,
MAX_LATENCY); secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -14,10 +14,14 @@ import java.io.OutputStream;
class AndroidBluetoothTransportConnection class AndroidBluetoothTransportConnection
extends AbstractDuplexTransportConnection { extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionManager;
private final BluetoothSocket socket; private final BluetoothSocket socket;
AndroidBluetoothTransportConnection(Plugin plugin, BluetoothSocket socket) { AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionManager,
BluetoothSocket socket) {
super(plugin); super(plugin);
this.connectionManager = connectionManager;
this.socket = socket; this.socket = socket;
} }
@@ -33,6 +37,10 @@ class AndroidBluetoothTransportConnection
@Override @Override
protected void closeConnection(boolean exception) throws IOException { protected void closeConnection(boolean exception) throws IOException {
socket.close(); try {
socket.close();
} finally {
connectionManager.connectionClosed(this);
}
} }
} }

View File

@@ -1,76 +1,166 @@
package org.briarproject.bramble.plugin.tcp; package org.briarproject.bramble.plugin.tcp;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo; 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.content.Context.WIFI_SERVICE;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
@NotNullByDefault @NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin { class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private static final byte[] WIFI_AP_ADDRESS_BYTES =
{(byte) 192, (byte) 168, 43, 1};
private static final InetAddress WIFI_AP_ADDRESS;
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidLanTcpPlugin.class.getName()); Logger.getLogger(AndroidLanTcpPlugin.class.getName());
private final Context appContext; static {
try {
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
} catch (UnknownHostException e) {
// Should only be thrown if the address has an illegal length
throw new AssertionError(e);
}
}
private final Executor connectionStatusExecutor;
private final ConnectivityManager connectivityManager;
@Nullable @Nullable
private volatile BroadcastReceiver networkStateReceiver = null; private final WifiManager wifiManager;
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff, private volatile SocketFactory socketFactory;
Context appContext, DuplexPluginCallback callback, int maxLatency,
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
int maxIdleTime) { int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime); super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
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();
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault();
} }
@Override @Override
public void start() { public void start() {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
// Register to receive network status events updateConnectionStatus();
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
appContext.registerReceiver(networkStateReceiver, filter);
} }
@Override @Override
public void stop() { public void stop() {
running = false; running = false;
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
tryToClose(socket); tryToClose(socket);
} }
private class NetworkStateReceiver extends BroadcastReceiver { @Override
protected Socket createSocket() throws IOException {
return socketFactory.createSocket();
}
@Override @Override
public void onReceive(Context ctx, Intent i) { protected Collection<InetAddress> getLocalIpAddresses() {
if (!running) return; // If the device doesn't have wifi, don't open any sockets
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE); if (wifiManager == null) return emptyList();
ConnectivityManager cm = (ConnectivityManager) o; // If we're connected to a wifi network, use that network
NetworkInfo net = cm.getActiveNetworkInfo(); WifiInfo info = wifiManager.getConnectionInfo();
if (net != null && net.getType() == TYPE_WIFI && net.isConnected()) { if (info != null && info.getIpAddress() != 0)
LOG.info("Connected to Wi-Fi"); return singletonList(intToInetAddress(info.getIpAddress()));
if (socket == null || socket.isClosed()) bind(); // If we're running an access point, return its address
} else { if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
LOG.info("Not connected to Wi-Fi"); return singletonList(WIFI_AP_ADDRESS);
tryToClose(socket); // No suitable addresses
} return emptyList();
}
private InetAddress intToInetAddress(int ip) {
byte[] ipBytes = new byte[4];
ipBytes[0] = (byte) (ip & 0xFF);
ipBytes[1] = (byte) ((ip >> 8) & 0xFF);
ipBytes[2] = (byte) ((ip >> 16) & 0xFF);
ipBytes[3] = (byte) ((ip >> 24) & 0xFF);
try {
return InetAddress.getByAddress(ipBytes);
} catch (UnknownHostException e) {
// Should only be thrown if address has illegal length
throw new AssertionError(e);
} }
} }
}
// On API 21 and later, a socket that is not created with the wifi
// network's socket factory may try to connect via another network
private SocketFactory getSocketFactory() {
if (SDK_INT < 21) return SocketFactory.getDefault();
for (Network net : connectivityManager.getAllNetworks()) {
NetworkInfo info = connectivityManager.getNetworkInfo(net);
if (info != null && info.getType() == TYPE_WIFI)
return net.getSocketFactory();
}
LOG.warning("Could not find suitable socket factory");
return SocketFactory.getDefault();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof NetworkStatusEvent) updateConnectionStatus();
}
private void updateConnectionStatus() {
connectionStatusExecutor.execute(() -> {
if (!running) return;
Collection<InetAddress> addrs = getLocalIpAddresses();
if (addrs.contains(WIFI_AP_ADDRESS)) {
LOG.info("Providing wifi hotspot");
// There's no corresponding Network object and thus no way
// to get a suitable socket factory, so we won't be able to
// make outgoing connections on API 21+ if another network
// has internet access
socketFactory = SocketFactory.getDefault();
if (socket == null || socket.isClosed()) bind();
} else if (addrs.isEmpty()) {
LOG.info("Not connected to wifi");
socketFactory = SocketFactory.getDefault();
tryToClose(socket);
} else {
LOG.info("Connected to wifi");
socketFactory = getSocketFactory();
if (socket == null || socket.isClosed()) bind();
}
});
}
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tcp;
import android.content.Context; import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -27,12 +28,14 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final double BACKOFF_BASE = 1.2; private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor; private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final Context appContext; private final Context appContext;
public AndroidLanTcpPluginFactory(Executor ioExecutor, public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
BackoffFactory backoffFactory, Context appContext) { BackoffFactory backoffFactory, Context appContext) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.appContext = appContext; this.appContext = appContext;
} }
@@ -51,7 +54,9 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) { public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new AndroidLanTcpPlugin(ioExecutor, backoff, appContext, AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
callback, MAX_LATENCY, MAX_IDLE_TIME); 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 android.os.Build;
import org.briarproject.bramble.api.event.EventBus; 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -12,8 +13,9 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.reporting.DevReporter; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -25,10 +27,10 @@ import javax.net.SocketFactory;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class TorPluginFactory implements DuplexPluginFactory { public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG = 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_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
@@ -39,25 +41,32 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor; private final Executor ioExecutor;
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
private final Context appContext; private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils; private final LocationUtils locationUtils;
private final DevReporter reporter;
private final EventBus eventBus; private final EventBus eventBus;
private final SocketFactory torSocketFactory; private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory; 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, ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, DevReporter reporter, NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory, EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory) { BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Clock clock) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.scheduler = scheduler; this.scheduler = scheduler;
this.appContext = appContext; this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils; this.locationUtils = locationUtils;
this.reporter = reporter;
this.eventBus = eventBus; this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory; this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.clock = clock;
} }
@Override @Override
@@ -93,9 +102,10 @@ public class TorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext, AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
locationUtils, reporter, torSocketFactory, backoff, callback, appContext, networkManager, locationUtils, torSocketFactory,
architecture, MAX_LATENCY, MAX_IDLE_TIME); clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
class TorNetworkMetadata {
// See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
// and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
// TODO: get a more complete list
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList("CN", "IR", "SY", "ZZ"));
static boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
}

View File

@@ -0,0 +1,30 @@
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) {
Resources res = appContext.getResources();
int resId = res.getIdentifier(name, "raw", appContext.getPackageName());
return res.openRawResource(resId);
}
}

View File

@@ -9,6 +9,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.StrictMode;
import android.provider.Settings; import android.provider.Settings;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -66,9 +67,12 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
@Override @Override
protected void writeSeed() { protected void writeSeed() {
// Silence strict mode
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
super.writeSeed(); super.writeSeed();
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18) if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
applyOpenSslFix(); applyOpenSslFix();
StrictMode.setThreadPolicy(tp);
} }
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html // Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html

View File

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

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.util; package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
@@ -10,11 +11,15 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
public class AndroidUtils { public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
@@ -35,6 +40,7 @@ public class AndroidUtils {
public static String getBluetoothAddress(Context ctx, public static String getBluetoothAddress(Context ctx,
BluetoothAdapter adapter) { BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake // Return the adapter's address if it's valid and not fake
@SuppressLint("HardwareIds")
String address = adapter.getAddress(); String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) return address; if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake // Return the address from settings if it's valid and not fake
@@ -51,19 +57,6 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS); && !address.equals(FAKE_BLUETOOTH_ADDRESS);
} }
public static void deleteAppData(Context ctx) {
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children != null) {
for (File child : children) {
if (!child.getName().equals("lib"))
IoUtils.deleteFileOrDir(child);
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
new File(dataDir, "cache").mkdir();
}
public static File getReportDir(Context ctx) { public static File getReportDir(Context ctx) {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE); return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
} }

View File

@@ -0,0 +1,100 @@
package org.briarproject.bramble.util;
import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
@ThreadSafe
@NotNullByDefault
public class RenewableWakeLock {
private static final Logger LOG =
Logger.getLogger(RenewableWakeLock.class.getName());
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final int SAFETY_MARGIN_MS = 10_000;
private final PowerManager powerManager;
private final ScheduledExecutorService scheduler;
private final int levelAndFlags;
private final String tag;
private final long durationMs;
private final Runnable renewTask;
private final Object lock = new Object();
@Nullable
private PowerManager.WakeLock wakeLock; // Locking: lock
@Nullable
private ScheduledFuture future; // Locking: lock
public RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
long duration, TimeUnit timeUnit) {
this.powerManager = powerManager;
this.scheduler = scheduler;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
durationMs = MILLISECONDS.convert(duration, timeUnit);
renewTask = this::renew;
}
public void acquire() {
if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag);
synchronized (lock) {
if (wakeLock != null) {
LOG.info("Already acquired");
return;
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
PowerManager.WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
oldWakeLock.release();
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
public void release() {
if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (future == null) throw new AssertionError();
future.cancel(false);
future = null;
wakeLock.release();
wakeLock = null;
}
}
}

View File

@@ -0,0 +1,8 @@
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
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

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,94 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.support.test:monitor:1.0.2:monitor-1.0.2.aar:38ef4fa98a32dc55550ff49bb36a583e178b3a9b830fcb8dcc27bfc4254bc2bc',
'com.android.support.test:runner:1.0.2:runner-1.0.2.aar:f04b9ae342975ba1cb3e4a06e13426e3e6b8a73faa45acba604493d83c9a4f00',
'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf',
'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

@@ -2,7 +2,9 @@ apply plugin: 'java-library'
sourceCompatibility = 1.8 sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle'
dependencies { dependencies {
implementation "com.google.dagger:dagger:2.0.2" implementation "com.google.dagger:dagger:2.0.2"
@@ -14,27 +16,8 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3" testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3" testImplementation "org.hamcrest:hamcrest-core:1.3"
}
dependencyVerification { signature 'org.codehaus.mojo.signature:java16:1.1@signature'
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.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',
]
} }
// needed to make test output available to bramble-core and briar-core // needed to make test output available to bramble-core and briar-core
@@ -49,7 +32,7 @@ artifacts {
testOutput jarTest testOutput jarTest
} }
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs tasks.withType(Test) {
tasks.withType(JavaCompile) { // Use entropy-gathering device specified on command line, if any
useJava6StandardLibrary(it) systemProperty 'java.security.egd', System.getProperty('java.security.egd')
} }

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

@@ -7,6 +7,8 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
@@ -88,6 +90,10 @@ public interface ClientHelper {
BdfDictionary toDictionary(byte[] b, int off, int len) BdfDictionary toDictionary(byte[] b, int off, int len)
throws FormatException; throws FormatException;
BdfDictionary toDictionary(TransportProperties transportProperties);
BdfDictionary toDictionary(Map<TransportId, TransportProperties> map);
BdfList toList(byte[] b, int off, int len) throws FormatException; BdfList toList(byte[] b, int off, int len) throws FormatException;
BdfList toList(byte[] b) throws FormatException; BdfList toList(byte[] b) throws FormatException;
@@ -99,8 +105,15 @@ public interface ClientHelper {
byte[] sign(String label, BdfList toSign, byte[] privateKey) byte[] sign(String label, BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
void verifySignature(String label, byte[] sig, byte[] publicKey, void verifySignature(byte[] signature, String label, BdfList signed,
BdfList signed) throws FormatException, GeneralSecurityException; byte[] publicKey) throws FormatException, GeneralSecurityException;
Author parseAndValidateAuthor(BdfList author) throws FormatException; Author parseAndValidateAuthor(BdfList author) throws FormatException;
TransportProperties parseAndValidateTransportProperties(
BdfDictionary properties) throws FormatException;
Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap(
BdfDictionary properties) throws FormatException;
} }

View File

@@ -12,19 +12,19 @@ public interface ContactGroupFactory {
/** /**
* Creates a group that is not shared with any contacts. * Creates a group that is not shared with any contacts.
*/ */
Group createLocalGroup(ClientId clientId, int clientVersion); Group createLocalGroup(ClientId clientId, int majorVersion);
/** /**
* Creates a group for the given client to share with the given contact. * Creates a group for the given client to share with the given contact.
*/ */
Group createContactGroup(ClientId clientId, int clientVersion, Group createContactGroup(ClientId clientId, int majorVersion,
Contact contact); Contact contact);
/** /**
* Creates a group for the given client to share between the given authors * Creates a group for the given client to share between the given authors
* identified by their AuthorIds. * identified by their AuthorIds.
*/ */
Group createContactGroup(ClientId clientId, int clientVersion, Group createContactGroup(ClientId clientId, int majorVersion,
AuthorId authorId1, AuthorId authorId2); AuthorId authorId1, AuthorId authorId2);
} }

View File

@@ -13,9 +13,9 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
public interface ContactExchangeTask { public interface ContactExchangeTask {
/** /**
* The current version of the contact exchange protocol * The current version of the contact exchange protocol.
*/ */
int PROTOCOL_VERSION = 0; byte PROTOCOL_VERSION = 1;
/** /**
* Label for deriving Alice's header key from the master secret. * Label for deriving Alice's header key from the master secret.

View File

@@ -6,7 +6,7 @@ import javax.annotation.concurrent.Immutable;
/** /**
* Type-safe wrapper for an integer that uniquely identifies a contact within * Type-safe wrapper for an integer that uniquely identifies a contact within
* the scope of a single node. * the scope of the local device.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection; import java.util.Collection;
@@ -13,30 +14,40 @@ import java.util.Collection;
public interface ContactManager { public interface ContactManager {
/** /**
* Registers a hook to be called whenever a contact is added. * Registers a hook to be called whenever a contact is added or removed.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/ */
void registerAddContactHook(AddContactHook hook); void registerContactHook(ContactHook hook);
/** /**
* Registers a hook to be called whenever a contact is removed. * Stores a contact associated with the given local and remote pseudonyms,
*/ * derives and stores transport keys for each transport, and returns an ID
void registerRemoveContactHook(RemoveContactHook hook); * for the contact.
*
/** * @param alice true if the local party is Alice
* Stores a contact within the given transaction associated with the given
* local and remote pseudonyms, and returns an ID for the contact.
*/ */
ContactId addContact(Transaction txn, Author remote, AuthorId local, ContactId addContact(Transaction txn, Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified, SecretKey master, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException; boolean active) throws DbException;
/** /**
* Stores a contact associated with the given local and remote pseudonyms, * Stores a contact associated with the given local and remote pseudonyms
* and returns an ID for the contact. * and returns an ID for the contact.
*/ */
ContactId addContact(Author remote, AuthorId local, ContactId addContact(Transaction txn, Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified, boolean verified, boolean active) throws DbException;
boolean active) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* derives and stores transport keys for each transport, and returns an ID
* for the contact.
*
* @param alice true if the local party is Alice
*/
ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active)
throws DbException;
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.
@@ -94,11 +105,10 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException; throws DbException;
interface AddContactHook { interface ContactHook {
void addingContact(Transaction txn, Contact c) throws DbException;
} void addingContact(Transaction txn, Contact c) throws DbException;
interface RemoveContactHook {
void removingContact(Transaction txn, Contact c) throws DbException; void removingContact(Transaction txn, Contact c) throws DbException;
} }
} }

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.contact;
/**
* Record types for the contact exchange protocol.
*/
public interface RecordTypes {
byte CONTACT_INFO = 0;
}

View File

@@ -67,8 +67,8 @@ public interface CryptoComponent {
* signature created for another purpose * signature created for another purpose
* @return true if the signature was valid, false otherwise. * @return true if the signature was valid, false otherwise.
*/ */
boolean verify(String label, byte[] signedData, byte[] publicKey, boolean verifySignature(byte[] signature, String label, byte[] signed,
byte[] signature) throws GeneralSecurityException; byte[] publicKey) throws GeneralSecurityException;
/** /**
* Returns the hash of the given inputs. The inputs are unambiguously * Returns the hash of the given inputs. The inputs are unambiguously
@@ -91,6 +91,18 @@ public interface CryptoComponent {
*/ */
byte[] mac(String label, SecretKey macKey, byte[]... inputs); byte[] mac(String label, SecretKey macKey, byte[]... inputs);
/**
* Verifies that the given message authentication code is valid for the
* given secret key and inputs.
*
* @param label a namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
* @return true if the MAC was valid, false otherwise.
*/
boolean verifyMac(byte[] mac, String label, SecretKey macKey,
byte[]... inputs);
/** /**
* Encrypts and authenticates the given plaintext so it can be written to * Encrypts and authenticates the given plaintext so it can be written to
* storage. The encryption and authentication keys are derived from the * storage. The encryption and authentication keys are derived from the

View File

@@ -16,4 +16,10 @@ public interface CryptoConstants {
* The maximum length of a signature in bytes. * The maximum length of a signature in bytes.
*/ */
int MAX_SIGNATURE_BYTES = 64; int MAX_SIGNATURE_BYTES = 64;
/**
* The length of a MAC in bytes.
*/
int MAC_BYTES = SecretKey.LENGTH;
} }

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey). * A key pair consisting of a {@link PublicKey} and a {@link PrivateKey}.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -14,9 +14,10 @@ public interface TransportCrypto {
* rotation period from the given master secret. * rotation period from the given master secret.
* *
* @param alice whether the keys are for use by Alice or Bob. * @param alice whether the keys are for use by Alice or Bob.
* @param active whether the keys are usable for outgoing streams.
*/ */
TransportKeys deriveTransportKeys(TransportId t, SecretKey master, TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
long rotationPeriod, boolean alice); long rotationPeriod, boolean alice, boolean active);
/** /**
* Rotates the given transport keys to the given rotation period. If the * Rotates the given transport keys to the given rotation period. If the

View File

@@ -24,9 +24,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
* ); * );
* </pre> * </pre>
*/ */
public static BdfDictionary of(Entry<String, Object>... entries) { public static BdfDictionary of(Entry<String, ?>... entries) {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
for (Entry<String, Object> e : entries) d.put(e.getKey(), e.getValue()); for (Entry<String, ?> e : entries) d.put(e.getKey(), e.getValue());
return d; return d;
} }
@@ -34,7 +34,7 @@ public class BdfDictionary extends TreeMap<String, Object> {
super(); super();
} }
public BdfDictionary(Map<String, Object> m) { public BdfDictionary(Map<String, ?> m) {
super(m); super(m);
} }

View File

@@ -8,6 +8,7 @@ import java.io.IOException;
public interface BdfReader { public interface BdfReader {
int DEFAULT_NESTED_LIMIT = 5; int DEFAULT_NESTED_LIMIT = 5;
int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024;
boolean eof() throws IOException; boolean eof() throws IOException;
@@ -39,13 +40,13 @@ public interface BdfReader {
boolean hasString() throws IOException; boolean hasString() throws IOException;
String readString(int maxLength) throws IOException; String readString() throws IOException;
void skipString() throws IOException; void skipString() throws IOException;
boolean hasRaw() throws IOException; boolean hasRaw() throws IOException;
byte[] readRaw(int maxLength) throws IOException; byte[] readRaw() throws IOException;
void skipRaw() throws IOException; void skipRaw() throws IOException;

View File

@@ -9,5 +9,6 @@ public interface BdfReaderFactory {
BdfReader createReader(InputStream in); BdfReader createReader(InputStream in);
BdfReader createReader(InputStream in, int nestedLimit); BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize);
} }

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.Contact;
import org.briarproject.bramble.api.contact.ContactId; 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.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -18,7 +19,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.ValidationManager; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection; import java.util.Collection;
@@ -43,7 +45,8 @@ public interface DatabaseComponent {
* @throws DataTooOldException if the data uses an older schema than the * @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated * 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. * Waits for any open transactions to finish and closes the database.
@@ -103,10 +106,11 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Stores transport keys for a newly added contact. * Stores the given transport keys for the given contact and returns a
* key set ID.
*/ */
void addTransportKeys(Transaction txn, ContactId c, TransportKeys k) KeySetId addTransportKeys(Transaction txn, ContactId c,
throws DbException; TransportKeys k) throws DbException;
/** /**
* Returns true if the database contains the given contact for the given * Returns true if the database contains the given contact for the given
@@ -128,8 +132,8 @@ public interface DatabaseComponent {
/** /**
* Deletes the message with the given ID. Unlike * Deletes the message with the given ID. Unlike
* {@link #removeMessage(Transaction, MessageId)}, the message ID and any * {@link #removeMessage(Transaction, MessageId)}, the message ID,
* other associated data are not deleted. * dependencies, metadata, and any other associated state are not deleted.
*/ */
void deleteMessage(Transaction txn, MessageId m) throws DbException; void deleteMessage(Transaction txn, MessageId m) throws DbException;
@@ -233,7 +237,8 @@ public interface DatabaseComponent {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Collection<Group> getGroups(Transaction txn, ClientId c) throws DbException; Collection<Group> getGroups(Transaction txn, ClientId c, int majorVersion)
throws DbException;
/** /**
* Returns the given group's visibility to the given contact, or * Returns the given group's visibility to the given contact, or
@@ -258,6 +263,14 @@ public interface DatabaseComponent {
*/ */
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException; Collection<LocalAuthor> getLocalAuthors(Transaction txn) 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;
/** /**
* Returns the IDs of any messages that need to be validated. * Returns the IDs of any messages that need to be validated.
* <p/> * <p/>
@@ -302,9 +315,9 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns the metadata for any messages in the given group with metadata * Returns the metadata for any delivered messages in the given group with
* that matches all entries in the given query. If the query is empty, the * metadata that matches all entries in the given query. If the query is
* metadata for all messages is returned. * empty, the metadata for all delivered messages is returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -320,8 +333,8 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns the metadata for the given delivered and pending message. * Returns the metadata for the given delivered or pending message.
* This is meant to be only used by the ValidationManager * This is only meant to be used by the ValidationManager.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -329,8 +342,8 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns the status of all messages in the given group with respect to * Returns the status of all delivered messages in the given group with
* the given contact. * respect to the given contact.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -339,12 +352,8 @@ public interface DatabaseComponent {
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* Missing dependencies have the state * For missing dependencies and dependencies in other groups, the state
* {@link ValidationManager.State UNKNOWN}. * {@link State UNKNOWN} is returned.
* Dependencies in other groups have the state
* {@link ValidationManager.State INVALID}.
* Note that these states are not set on the dependencies themselves; the
* returned states should only be taken in the context of the given message.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -352,9 +361,9 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns all IDs of messages that depend on the given message. * Returns the IDs and states of all dependents of the given message.
* Messages in other groups that declare a dependency on the given message * Dependents in other groups are not returned. If the given message is
* will be returned even though such dependencies are invalid. * missing, no dependents are returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -369,8 +378,8 @@ public interface DatabaseComponent {
State getMessageState(Transaction txn, MessageId m) throws DbException; State getMessageState(Transaction txn, MessageId m) throws DbException;
/** /**
* Returns the status of the given message with respect to the given * Returns the status of the given delivered message with respect to the
* contact. * given contact.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
@@ -399,15 +408,14 @@ public interface DatabaseComponent {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<ContactId, TransportKeys> getTransportKeys(Transaction txn, Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
TransportId t) throws DbException; throws DbException;
/** /**
* Increments the outgoing stream counter for the given contact and * Increments the outgoing stream counter for the given transport keys.
* transport in the given rotation period .
*/ */
void incrementStreamCounter(Transaction txn, ContactId c, TransportId t, void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
long rotationPeriod) throws DbException; throws DbException;
/** /**
* Merges the given metadata with the existing metadata for the given * Merges the given metadata with the existing metadata for the given
@@ -477,6 +485,12 @@ public interface DatabaseComponent {
*/ */
void removeTransport(Transaction txn, TransportId t) throws DbException; void removeTransport(Transaction txn, TransportId t) throws DbException;
/**
* Removes the given transport keys from the database.
*/
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/** /**
* Marks the given contact as verified. * Marks the given contact as verified.
*/ */
@@ -512,15 +526,21 @@ public interface DatabaseComponent {
Collection<MessageId> dependencies) throws DbException; Collection<MessageId> dependencies) throws DbException;
/** /**
* Sets the reordering window for the given contact and transport in the * Sets the reordering window for the given key set and transport in the
* given rotation period. * given rotation period.
*/ */
void setReorderingWindow(Transaction txn, ContactId c, TransportId t, void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
long rotationPeriod, long base, byte[] bitmap) throws DbException; long rotationPeriod, long base, byte[] bitmap) throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/** /**
* Stores the given transport keys, deleting any keys they have replaced. * Stores the given transport keys, deleting any keys they have replaced.
*/ */
void updateTransportKeys(Transaction txn, void updateTransportKeys(Transaction txn, Collection<KeySet> keys)
Map<ContactId, TransportKeys> keys) throws DbException; throws DbException;
} }

View File

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

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.identity; 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.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status; import org.briarproject.bramble.api.identity.Author.Status;
@@ -9,29 +10,40 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
public interface IdentityManager { 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 * Registers the given local identity with the manager. The identity is
* the db, blocking * 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; LocalAuthor getLocalAuthor() throws DbException;
/** /**
* Returns the cached main local identity, non-blocking, or loads it from * Returns the cached local identity or loads it from the database.
* the db, blocking, within the given Transaction.
*/ */
LocalAuthor getLocalAuthor(Transaction txn) throws DbException; 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; 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; Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;

View File

@@ -7,16 +7,6 @@ public interface KeyAgreementConstants {
*/ */
byte PROTOCOL_VERSION = 4; 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. * The length of the BQP key commitment in bytes.
*/ */

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.keyagreement.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when a BQP task stops listening.
*/
public class KeyAgreementStoppedListeningEvent extends Event {
}

View File

@@ -12,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* Annotation for injecting the executor for long-running IO tasks. Also used * Annotation for injecting the executor for long-running IO tasks. Also used
* for annotating methods that should run on the UI executor. * for annotating methods that should run on the IO executor.
* <p> * <p>
* The contract of this executor is that tasks may be run concurrently, and * The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks may run indefinitely. Tasks * submitting a task will never block. Tasks may run indefinitely. Tasks

View File

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

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.plugin;
public interface FileConstants {
String PROP_PATH = "path";
}

View File

@@ -2,8 +2,9 @@ package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.util.Collection; import java.util.Map;
@NotNullByDefault @NotNullByDefault
public interface Plugin { public interface Plugin {
@@ -39,21 +40,19 @@ public interface Plugin {
boolean isRunning(); boolean isRunning();
/** /**
* Returns true if the plugin's {@link #poll(Collection)} method should be * Returns true if the plugin should be polled periodically to attempt to
* called periodically to attempt to establish connections. * establish connections.
*/ */
boolean shouldPoll(); boolean shouldPoll();
/** /**
* Returns the desired interval in milliseconds between calls to the * Returns the desired interval in milliseconds between polling attempts.
* plugin's {@link #poll(Collection)} method.
*/ */
int getPollingInterval(); int getPollingInterval();
/** /**
* Attempts to establish connections to contacts, passing any created * Attempts to establish connections to the given contacts, passing any
* connections to the callback. To avoid creating redundant connections, * created connections to the callback.
* the plugin may exclude the given contacts from polling.
*/ */
void poll(Collection<ContactId> connected); void poll(Map<ContactId, TransportProperties> contacts);
} }

View File

@@ -1,12 +1,9 @@
package org.briarproject.bramble.api.plugin; package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import java.util.Map;
/** /**
* An interface through which a transport plugin interacts with the rest of * An interface through which a transport plugin interacts with the rest of
* the application. * the application.
@@ -25,17 +22,7 @@ public interface PluginCallback {
TransportProperties getLocalProperties(); TransportProperties getLocalProperties();
/** /**
* Returns the plugin's remote transport properties. * Merges the given settings with the plugin's settings
*/
Map<ContactId, TransportProperties> getRemoteProperties();
/**
* Returns the plugin's remote transport properties for the given contact.
*/
TransportProperties getRemoteProperties(ContactId c);
/**
* Merges the given settings with the namespaced settings
*/ */
void mergeSettings(Settings s); void mergeSettings(Settings s);
@@ -45,34 +32,12 @@ public interface PluginCallback {
void mergeLocalProperties(TransportProperties p); void mergeLocalProperties(TransportProperties p);
/** /**
* Presents the user with a choice among two or more named options and * Signals that the transport is enabled.
* returns the user's response. The message may consist of a translatable
* format string and arguments.
*
* @return an index into the array of options indicating the user's choice,
* or -1 if the user cancelled the choice.
*/
int showChoice(String[] options, String... message);
/**
* Asks the user to confirm an action and returns the user's response. The
* message may consist of a translatable format string and arguments.
*/
boolean showConfirmationMessage(String... message);
/**
* Shows a message to the user. The message may consist of a translatable
* format string and arguments.
*/
void showMessage(String... message);
/**
* Signal that the transport got enabled.
*/ */
void transportEnabled(); void transportEnabled();
/** /**
* Signal that the transport got disabled. * Signals that the transport is disabled.
*/ */
void transportDisabled(); void transportDisabled();
} }

View File

@@ -12,4 +12,6 @@ public interface PluginConfig {
Collection<DuplexPluginFactory> getDuplexFactories(); Collection<DuplexPluginFactory> getDuplexFactories();
Collection<SimplexPluginFactory> getSimplexFactories(); Collection<SimplexPluginFactory> getSimplexFactories();
boolean shouldPoll();
} }

View File

@@ -14,6 +14,7 @@ public interface TorConstants {
String PREF_TOR_NETWORK = "network"; String PREF_TOR_NETWORK = "network";
String PREF_TOR_PORT = "port"; String PREF_TOR_PORT = "port";
String PREF_TOR_DISABLE_BLOCKED = "disableWhenBlocked";
int PREF_TOR_NETWORK_NEVER = 0; int PREF_TOR_NETWORK_NEVER = 0;
int PREF_TOR_NETWORK_WIFI = 1; int PREF_TOR_NETWORK_WIFI = 1;

View File

@@ -22,11 +22,6 @@ public interface TransportConnectionWriter {
*/ */
int getMaxIdleTime(); int getMaxIdleTime();
/**
* Returns the capacity of the transport connection in bytes.
*/
long getCapacity();
/** /**
* Returns an output stream for writing to the transport connection. * Returns an output stream for writing to the transport connection.
*/ */

View File

@@ -1,22 +1,23 @@
package org.briarproject.bramble.api.plugin; package org.briarproject.bramble.api.plugin;
import java.nio.charset.Charset; import org.briarproject.bramble.util.StringUtils;
/** /**
* Type-safe wrapper for a string that uniquely identifies a transport plugin. * Type-safe wrapper for a namespaced string that uniquely identifies a
* transport plugin.
*/ */
public class TransportId { public class TransportId {
/** /**
* The maximum length of transport identifier in UTF-8 bytes. * The maximum length of a transport identifier in UTF-8 bytes.
*/ */
public static int MAX_TRANSPORT_ID_LENGTH = 64; public static int MAX_TRANSPORT_ID_LENGTH = 100;
private final String id; private final String id;
public TransportId(String id) { public TransportId(String id) {
byte[] b = id.getBytes(Charset.forName("UTF-8")); int length = StringUtils.toUtf8(id).length;
if (b.length == 0 || b.length > MAX_TRANSPORT_ID_LENGTH) if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.id = id; this.id = id;
} }

View File

@@ -71,11 +71,6 @@ public abstract class AbstractDuplexTransportConnection
return plugin.getMaxIdleTime(); return plugin.getMaxIdleTime();
} }
@Override
public long getCapacity() {
return Long.MAX_VALUE;
}
@Override @Override
public OutputStream getOutputStream() throws IOException { public OutputStream getOutputStream() throws IOException {
return AbstractDuplexTransportConnection.this.getOutputStream(); return AbstractDuplexTransportConnection.this.getOutputStream();

View File

@@ -1,10 +1,10 @@
package org.briarproject.bramble.api.plugin.duplex; package org.briarproject.bramble.api.plugin.duplex;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -15,12 +15,11 @@ import javax.annotation.Nullable;
public interface DuplexPlugin extends Plugin { public interface DuplexPlugin extends Plugin {
/** /**
* Attempts to create and return a connection to the given contact using * Attempts to create and return a connection using the given transport
* the current transport and configuration properties. Returns null if a * properties. Returns null if a connection cannot be created.
* connection cannot be created.
*/ */
@Nullable @Nullable
DuplexTransportConnection createConnection(ContactId c); DuplexTransportConnection createConnection(TransportProperties p);
/** /**
* Returns true if the plugin supports short-range key agreement. * Returns true if the plugin supports short-range key agreement.

View File

@@ -5,7 +5,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginCallback;
/** /**
* An interface for handling connections created by a duplex transport plugin. * An interface through which a duplex plugin interacts with the rest of the
* application.
*/ */
@NotNullByDefault @NotNullByDefault
public interface DuplexPluginCallback extends PluginCallback { public interface DuplexPluginCallback extends PluginCallback {

View File

@@ -1,10 +1,10 @@
package org.briarproject.bramble.api.plugin.simplex; package org.briarproject.bramble.api.plugin.simplex;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.TransportConnectionReader; import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter; import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -15,18 +15,16 @@ import javax.annotation.Nullable;
public interface SimplexPlugin extends Plugin { public interface SimplexPlugin extends Plugin {
/** /**
* Attempts to create and return a reader for the given contact using the * Attempts to create and return a reader for the given transport
* current transport and configuration properties. Returns null if a reader * properties. Returns null if a reader cannot be created.
* cannot be created.
*/ */
@Nullable @Nullable
TransportConnectionReader createReader(ContactId c); TransportConnectionReader createReader(TransportProperties p);
/** /**
* Attempts to create and return a writer for the given contact using the * Attempts to create and return a writer for the given transport
* current transport and configuration properties. Returns null if a writer * properties. Returns null if a writer cannot be created.
* cannot be created.
*/ */
@Nullable @Nullable
TransportConnectionWriter createWriter(ContactId c); TransportConnectionWriter createWriter(TransportProperties p);
} }

View File

@@ -7,8 +7,8 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter; import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
/** /**
* An interface for handling readers and writers created by a simplex transport * An interface through which a simplex plugin interacts with the rest of the
* plugin. * application.
*/ */
@NotNullByDefault @NotNullByDefault
public interface SimplexPluginCallback extends PluginCallback { public interface SimplexPluginCallback extends PluginCallback {

View File

@@ -15,12 +15,17 @@ public interface TransportPropertyManager {
/** /**
* The unique ID of the transport property client. * The unique ID of the transport property client.
*/ */
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.properties"); ClientId CLIENT_ID = new ClientId("org.briarproject.bramble.properties");
/** /**
* The current version of the transport property client. * The current major version of the transport property client.
*/ */
int CLIENT_VERSION = 0; int MAJOR_VERSION = 0;
/**
* The current minor version of the transport property client.
*/
int MINOR_VERSION = 0;
/** /**
* Stores the given properties received while adding a contact - they will * Stores the given properties received while adding a contact - they will
@@ -37,8 +42,8 @@ public interface TransportPropertyManager {
/** /**
* Returns the local transport properties for all transports. * Returns the local transport properties for all transports.
* <br/> * <p/>
* TODO: Transaction can be read-only when code is simplified * Read-only.
*/ */
Map<TransportId, TransportProperties> getLocalProperties(Transaction txn) Map<TransportId, TransportProperties> getLocalProperties(Transaction txn)
throws DbException; throws DbException;

View File

@@ -0,0 +1,36 @@
package org.briarproject.bramble.api.record;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Record {
public static final int RECORD_HEADER_BYTES = 4;
public static final int MAX_RECORD_PAYLOAD_BYTES = 48 * 1024; // 48 KiB
private final byte protocolVersion, recordType;
private final byte[] payload;
public Record(byte protocolVersion, byte recordType, byte[] payload) {
if (payload.length > MAX_RECORD_PAYLOAD_BYTES)
throw new IllegalArgumentException();
this.protocolVersion = protocolVersion;
this.recordType = recordType;
this.payload = payload;
}
public byte getProtocolVersion() {
return protocolVersion;
}
public byte getRecordType() {
return recordType;
}
public byte[] getPayload() {
return payload;
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.record;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.EOFException;
import java.io.IOException;
@NotNullByDefault
public interface RecordReader {
/**
* Reads and returns the next record.
*
* @throws EOFException if the end of the stream is reached without reading
* a complete record
*/
Record readRecord() throws IOException;
void close() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble.api.record;
import java.io.InputStream;
public interface RecordReaderFactory {
RecordReader createRecordReader(InputStream in);
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.record;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException;
@NotNullByDefault
public interface RecordWriter {
void writeRecord(Record r) throws IOException;
void flush() throws IOException;
void close() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble.api.record;
import java.io.OutputStream;
public interface RecordWriterFactory {
RecordWriter createRecordWriter(OutputStream out);
}

View File

@@ -3,10 +3,14 @@ package org.briarproject.bramble.api.reporting;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
@NotNullByDefault @NotNullByDefault
public interface DevConfig { public interface DevConfig {
PublicKey getDevPublicKey(); PublicKey getDevPublicKey();
String getDevOnionAddress(); String getDevOnionAddress();
File getReportDir();
} }

View File

@@ -23,8 +23,6 @@ public interface DevReporter {
/** /**
* Sends any reports previously stored on disk. * Sends any reports previously stored on disk.
*
* @param reportDir the directory where reports are stored.
*/ */
void sendReports(File reportDir); void sendReports();
} }

View File

@@ -1,19 +1,29 @@
package org.briarproject.bramble.api.sync; package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* Wrapper for a name-spaced string that uniquely identifies a sync client. * Type-safe wrapper for a namespaced string that uniquely identifies a sync
* client.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class ClientId implements Comparable<ClientId> { public class ClientId implements Comparable<ClientId> {
/**
* The maximum length of a client identifier in UTF-8 bytes.
*/
public static int MAX_CLIENT_ID_LENGTH = 100;
private final String id; private final String id;
public ClientId(String id) { public ClientId(String id) {
int length = StringUtils.toUtf8(id).length;
if (length == 0 || length > MAX_CLIENT_ID_LENGTH)
throw new IllegalArgumentException();
this.id = id; this.id = id;
} }

View File

@@ -5,20 +5,43 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPT
public class Group { public class Group {
public enum Visibility { public enum Visibility {
INVISIBLE, // The group is not visible
VISIBLE, // The group is visible but messages are not shared INVISIBLE(0), // The group is not visible
SHARED // The group is visible and messages are shared VISIBLE(1), // The group is visible, messages are accepted but not sent
SHARED(2); // The group is visible, messages are accepted and sent
private final int value;
Visibility(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static Visibility min(Visibility a, Visibility b) {
return a.getValue() < b.getValue() ? a : b;
}
} }
/**
* The current version of the group format.
*/
public static final int FORMAT_VERSION = 1;
private final GroupId id; private final GroupId id;
private final ClientId clientId; private final ClientId clientId;
private final int majorVersion;
private final byte[] descriptor; private final byte[] descriptor;
public Group(GroupId id, ClientId clientId, byte[] descriptor) { public Group(GroupId id, ClientId clientId, int majorVersion,
byte[] descriptor) {
if (descriptor.length > MAX_GROUP_DESCRIPTOR_LENGTH) if (descriptor.length > MAX_GROUP_DESCRIPTOR_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.id = id; this.id = id;
this.clientId = clientId; this.clientId = clientId;
this.majorVersion = majorVersion;
this.descriptor = descriptor; this.descriptor = descriptor;
} }
@@ -36,6 +59,13 @@ public class Group {
return clientId; return clientId;
} }
/**
* Returns the major version of the client to which the group belongs.
*/
public int getMajorVersion() {
return majorVersion;
}
/** /**
* Returns the group's descriptor. * Returns the group's descriptor.
*/ */

View File

@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
public interface GroupFactory { public interface GroupFactory {
/** /**
* Creates a group with the given client ID, client version and descriptor. * Creates a group with the given client ID, major version and descriptor.
*/ */
Group createGroup(ClientId c, int clientVersion, byte[] descriptor); Group createGroup(ClientId c, int majorVersion, byte[] descriptor);
} }

View File

@@ -5,6 +5,11 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LEN
public class Message { public class Message {
/**
* The current version of the message format.
*/
public static final int FORMAT_VERSION = 1;
private final MessageId id; private final MessageId id;
private final GroupId groupId; private final GroupId groupId;
private final long timestamp; private final long timestamp;

View File

@@ -7,5 +7,7 @@ public interface MessageFactory {
Message createMessage(GroupId g, long timestamp, byte[] body); Message createMessage(GroupId g, long timestamp, byte[] body);
Message createMessage(byte[] raw);
Message createMessage(MessageId m, byte[] raw); Message createMessage(MessageId m, byte[] raw);
} }

View File

@@ -16,7 +16,13 @@ public class MessageId extends UniqueId {
/** /**
* Label for hashing messages to calculate their identifiers. * Label for hashing messages to calculate their identifiers.
*/ */
public static final String LABEL = "org.briarproject.bramble/MESSAGE_ID"; public static final String ID_LABEL = "org.briarproject.bramble/MESSAGE_ID";
/**
* Label for hashing blocks of messages.
*/
public static final String BLOCK_LABEL =
"org.briarproject.bramble/MESSAGE_BLOCK";
public MessageId(byte[] id) { public MessageId(byte[] id) {
super(id); super(id);

View File

@@ -2,6 +2,8 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
public interface SyncConstants { public interface SyncConstants {
/** /**
@@ -10,16 +12,8 @@ public interface SyncConstants {
byte PROTOCOL_VERSION = 0; byte PROTOCOL_VERSION = 0;
/** /**
* The length of the record header in bytes. * The maximum length of a group descriptor in bytes.
*/ */
int RECORD_HEADER_LENGTH = 4;
/**
* The maximum length of the record payload in bytes.
*/
int MAX_RECORD_PAYLOAD_LENGTH = 48 * 1024; // 48 KiB
/** The maximum length of a group descriptor in bytes. */
int MAX_GROUP_DESCRIPTOR_LENGTH = 16 * 1024; // 16 KiB int MAX_GROUP_DESCRIPTOR_LENGTH = 16 * 1024; // 16 KiB
/** /**
@@ -40,5 +34,5 @@ public interface SyncConstants {
/** /**
* The maximum number of message IDs in an ack, offer or request record. * The maximum number of message IDs in an ack, offer or request record.
*/ */
int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_LENGTH / UniqueId.LENGTH; int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_BYTES / UniqueId.LENGTH;
} }

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
@NotNullByDefault @NotNullByDefault
public interface RecordReader { public interface SyncRecordReader {
boolean eof() throws IOException; boolean eof() throws IOException;

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.InputStream; import java.io.InputStream;
@NotNullByDefault @NotNullByDefault
public interface RecordReaderFactory { public interface SyncRecordReaderFactory {
RecordReader createRecordReader(InputStream in); SyncRecordReader createRecordReader(InputStream in);
} }

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
@NotNullByDefault @NotNullByDefault
public interface RecordWriter { public interface SyncRecordWriter {
void writeAck(Ack a) throws IOException; void writeAck(Ack a) throws IOException;

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.OutputStream; import java.io.OutputStream;
@NotNullByDefault @NotNullByDefault
public interface RecordWriterFactory { public interface SyncRecordWriterFactory {
RecordWriter createRecordWriter(OutputStream out); SyncRecordWriter createRecordWriter(OutputStream out);
} }

View File

@@ -2,9 +2,9 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
@NotNullByDefault @NotNullByDefault
public interface SyncSessionFactory { public interface SyncSessionFactory {
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
SyncSession createIncomingSession(ContactId c, InputStream in); SyncSession createIncomingSession(ContactId c, InputStream in);
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency, SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
OutputStream out); StreamWriter streamWriter);
SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency, SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
int maxIdleTime, OutputStream out); int maxIdleTime, StreamWriter streamWriter);
} }

View File

@@ -1,8 +1,10 @@
package org.briarproject.bramble.api.sync; 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.DbException;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/** /**
@@ -33,15 +35,21 @@ public interface ValidationManager {
} }
/** /**
* Sets the message validator for the given client. * Registers the message validator for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/ */
void registerMessageValidator(ClientId c, MessageValidator v); void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/** /**
* Sets the incoming message hook for the given client. The hook will be * Registers the incoming message hook for the given client. The hook will
* called once for each incoming message that passes validation. * be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/ */
void registerIncomingMessageHook(ClientId c, IncomingMessageHook hook); void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
interface MessageValidator { interface MessageValidator {

View File

@@ -7,12 +7,12 @@ package org.briarproject.bramble.api.system;
public interface Clock { public interface Clock {
/** /**
* @see {@link System#currentTimeMillis()} * @see System#currentTimeMillis()
*/ */
long currentTimeMillis(); long currentTimeMillis();
/** /**
* @see {@link Thread#sleep(long)} * @see Thread#sleep(long)
*/ */
void sleep(long milliseconds) throws InterruptedException; void sleep(long milliseconds) throws InterruptedException;
} }

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

View File

@@ -6,6 +6,8 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
@@ -16,12 +18,30 @@ public interface KeyManager {
/** /**
* Informs the key manager that a new contact has been added. Derives and * Informs the key manager that a new contact has been added. Derives and
* stores transport keys for communicating with the contact. * stores a set of transport keys for communicating with the contact over
* each transport and returns the key set IDs.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created * {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned. * after this method has returned.
*
* @param alice true if the local party is Alice
* @param active whether the derived keys can be used for outgoing streams
*/ */
void addContact(Transaction txn, ContactId c, SecretKey master, Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
long timestamp, boolean alice) throws DbException; SecretKey master, long timestamp, boolean alice, boolean active)
throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
throws DbException;
/**
* Returns true if we have keys that can be used for outgoing streams to
* the given contact over the given transport.
*/
boolean canSendOutgoingStreams(ContactId c, TransportId t);
/** /**
* Returns a {@link StreamContext} for sending a stream to the given * Returns a {@link StreamContext} for sending a stream to the given

View File

@@ -0,0 +1,47 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* A set of transport keys for communicating with a contact.
*/
@Immutable
@NotNullByDefault
public class KeySet {
private final KeySetId keySetId;
private final ContactId contactId;
private final TransportKeys transportKeys;
public KeySet(KeySetId keySetId, ContactId contactId,
TransportKeys transportKeys) {
this.keySetId = keySetId;
this.contactId = contactId;
this.transportKeys = transportKeys;
}
public KeySetId getKeySetId() {
return keySetId;
}
public ContactId getContactId() {
return contactId;
}
public TransportKeys getTransportKeys() {
return transportKeys;
}
@Override
public int hashCode() {
return keySetId.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof KeySet && keySetId.equals(((KeySet) o).keySetId);
}
}

View File

@@ -0,0 +1,36 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* Type-safe wrapper for an integer that uniquely identifies a set of transport
* keys within the scope of the local device.
* <p/>
* Key sets created on a given device must have increasing identifiers.
*/
@Immutable
@NotNullByDefault
public class KeySetId {
private final int id;
public KeySetId(int id) {
this.id = id;
}
public int getInt() {
return id;
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object o) {
return o instanceof KeySetId && id == ((KeySetId) o).id;
}
}

View File

@@ -10,18 +10,20 @@ public class OutgoingKeys {
private final SecretKey tagKey, headerKey; private final SecretKey tagKey, headerKey;
private final long rotationPeriod, streamCounter; private final long rotationPeriod, streamCounter;
private final boolean active;
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey, public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod) { long rotationPeriod, boolean active) {
this(tagKey, headerKey, rotationPeriod, 0); this(tagKey, headerKey, rotationPeriod, 0, active);
} }
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey, public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod, long streamCounter) { long rotationPeriod, long streamCounter, boolean active) {
this.tagKey = tagKey; this.tagKey = tagKey;
this.headerKey = headerKey; this.headerKey = headerKey;
this.rotationPeriod = rotationPeriod; this.rotationPeriod = rotationPeriod;
this.streamCounter = streamCounter; this.streamCounter = streamCounter;
this.active = active;
} }
public SecretKey getTagKey() { public SecretKey getTagKey() {
@@ -39,4 +41,8 @@ public class OutgoingKeys {
public long getStreamCounter() { public long getStreamCounter() {
return streamCounter; return streamCounter;
} }
public boolean isActive() {
return active;
}
} }

View File

@@ -0,0 +1,19 @@
package org.briarproject.bramble.api.transport;
import java.io.IOException;
import java.io.OutputStream;
/**
* An interface for writing data to a transport connection. Data will be
* encrypted and authenticated before being written to the connection.
*/
public interface StreamWriter {
OutputStream getOutputStream();
/**
* Sends the end of stream marker, informing the recipient that no more
* data will be sent. The connection is flushed but not closed.
*/
void sendEndOfStream() throws IOException;
}

View File

@@ -12,12 +12,12 @@ public interface StreamWriterFactory {
* Creates an {@link OutputStream OutputStream} for writing to a * Creates an {@link OutputStream OutputStream} for writing to a
* transport stream * transport stream
*/ */
OutputStream createStreamWriter(OutputStream out, StreamContext ctx); StreamWriter createStreamWriter(OutputStream out, StreamContext ctx);
/** /**
* Creates an {@link OutputStream OutputStream} for writing to a contact * Creates an {@link OutputStream OutputStream} for writing to a contact
* exchange stream. * exchange stream.
*/ */
OutputStream createContactExchangeStreamWriter(OutputStream out, StreamWriter createContactExchangeStreamWriter(OutputStream out,
SecretKey headerKey); SecretKey headerKey);
} }

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