Compare commits

...

463 Commits

Author SHA1 Message Date
akwizgran
127b9ef244 WIP: Add border to message bubbles on Android 4. 2018-08-06 16:03:03 +01:00
Torsten Grote
474de25e61 Restore old button size and ensure timestamps are not selectable 2018-08-03 16:12:24 -03:00
Torsten Grote
803c0d37bf Give names to colors and clean them up 2018-08-03 15:44:21 -03:00
Torsten Grote
11ff00c26d More Dark Theme Changes after designer feedback 2018-08-03 15:11:33 -03:00
Torsten Grote
23af75ce8d New private message bubbles
This gets rid of all those pesky 9-Patch drawables
2018-08-03 15:11:33 -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
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
759 changed files with 23886 additions and 14001 deletions

2
.gitignore vendored
View File

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

View File

@@ -1,29 +1,27 @@
image: registry.gitlab.com/fdroid/ci-images-base: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
image: briar/ci-image-android:latest
test:
script:
- ./gradlew test
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
after_script:
# this file changes every time but should not be cached
cache:
paths:
- .gradle/wrapper
- .gradle/caches
script:
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon 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 -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>
<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-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 briar-core" run_configuration_type="AndroidJUnit" />
</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,18 @@
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
apply plugin: 'com.android.library'
apply plugin: 'witness'
apply plugin: 'de.undercouch.download'
android {
compileSdkVersion 27
buildToolsVersion '26.0.2'
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 1700
versionName "0.17.0"
versionCode 10013
versionName "1.0.13"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@@ -23,74 +21,133 @@ android {
}
}
configurations {
tor
}
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'org.briarproject:jtorctl:0.3'
tor 'org.briarproject:tor-android:0.2.9.16@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification {
verify = [
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'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.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',
'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',
'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',
'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:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.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',
]
}
ext.torBinaryDir = 'src/main/res/raw'
ext.torVersion = '0.2.9.14'
ext.geoipVersion = '2017-11-06'
ext.torDownloadUrl = 'https://briarproject.org/build/'
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 {
torBinaries.every { key, value ->
preBuild.dependsOn.add(verifyBinary(key, value))
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
}
}

View File

@@ -0,0 +1,129 @@
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.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.getSimpleName());
@Inject
NetworkManager networkManager;
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final Context appContext = getTargetContext();
private final CircumventionProvider circumventionProvider;
private final List<String> bridges;
private TorPluginFactory factory;
private volatile int currentBridge = 0;
public BridgeTest() {
super();
circumventionProvider = 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(bridges.get(currentBridge));
}
};
bridges = new CircumventionProviderImpl(appContext).getBridges();
}
@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();
factory = new TorPluginFactory(ioExecutor, scheduler, appContext,
networkManager, locationUtils, eventBus, torSocketFactory,
backoffFactory, circumventionProvider, clock);
}
@Test
public void testBridges() throws Exception {
assertTrue(bridges.size() > 0);
for (int i = 0; i < bridges.size(); i++) {
testBridge(i);
}
}
private void testBridge(int bridge) throws Exception {
DuplexPlugin duplexPlugin =
factory.createPlugin(new TorPluginCallBack());
assertNotNull(duplexPlugin);
TorPlugin plugin = (TorPlugin) duplexPlugin;
currentBridge = bridge;
LOG.warning("Testing " + bridges.get(currentBridge));
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 android.support.test.InstrumentationRegistry;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
class ApplicationModule {
@Provides
@Singleton
Application provideApplication() {
return (Application) InstrumentationRegistry.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"
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_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application

View File

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

View File

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

View File

@@ -0,0 +1,142 @@
package org.briarproject.bramble.network;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Level.INFO;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG =
Logger.getLogger(AndroidNetworkManager.class.getName());
// See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final Context appContext;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver networkStateReceiver = null;
@Inject
AndroidNetworkManager(@Scheduler ScheduledExecutorService scheduler,
EventBus eventBus, Application app) {
this.scheduler = scheduler;
this.eventBus = eventBus;
this.appContext = app.getApplicationContext();
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(ACTION_SCREEN_ON);
filter.addAction(ACTION_SCREEN_OFF);
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
appContext.registerReceiver(networkStateReceiver, filter);
}
@Override
public void stopService() {
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
}
@Override
public NetworkStatus getNetworkStatus() {
ConnectivityManager cm = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
assert cm != null;
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_ON;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -55,10 +56,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
// Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null;
AndroidBluetoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Backoff backoff,
DuplexPluginCallback callback, int maxLatency) {
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency);
this.androidExecutor = androidExecutor;
this.appContext = appContext;
}
@@ -143,7 +146,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try {
if (ss != null) ss.close();
} 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) {
return new AndroidBluetoothTransportConnection(this, s);
return new AndroidBluetoothTransportConnection(this,
connectionLimiter, s);
}
@Override
@@ -182,7 +186,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try {
if (c != null) c.close();
} 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
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl();
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(ioExecutor,
androidExecutor, appContext, secureRandom, backoff, callback,
MAX_LATENCY);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, ioExecutor, androidExecutor, appContext,
secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -14,10 +14,14 @@ import java.io.OutputStream;
class AndroidBluetoothTransportConnection
extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionManager;
private final BluetoothSocket socket;
AndroidBluetoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionManager,
BluetoothSocket socket) {
super(plugin);
this.connectionManager = connectionManager;
this.socket = socket;
}
@@ -33,6 +37,10 @@ class AndroidBluetoothTransportConnection
@Override
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;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
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.logging.Logger;
import javax.annotation.Nullable;
import javax.net.SocketFactory;
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.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
@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 =
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
private volatile BroadcastReceiver networkStateReceiver = null;
private final WifiManager wifiManager;
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff,
Context appContext, DuplexPluginCallback callback, int maxLatency,
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
int 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);
assert connectivityManager != null;
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault();
}
@Override
public void start() {
if (used.getAndSet(true)) throw new IllegalStateException();
running = true;
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
appContext.registerReceiver(networkStateReceiver, filter);
updateConnectionStatus();
}
@Override
public void stop() {
running = false;
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
tryToClose(socket);
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
protected Socket createSocket() throws IOException {
return socketFactory.createSocket();
}
@Override
public void onReceive(Context ctx, Intent i) {
if (!running) return;
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
if (net != null && net.getType() == TYPE_WIFI && net.isConnected()) {
LOG.info("Connected to Wi-Fi");
if (socket == null || socket.isClosed()) bind();
} else {
LOG.info("Not connected to Wi-Fi");
tryToClose(socket);
}
@Override
protected Collection<InetAddress> getLocalIpAddresses() {
// If the device doesn't have wifi, don't open any sockets
if (wifiManager == null) return emptyList();
// If we're connected to a wifi network, use that network
WifiInfo info = wifiManager.getConnectionInfo();
if (info != null && info.getIpAddress() != 0)
return singletonList(intToInetAddress(info.getIpAddress()));
// If we're running an access point, return its address
if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
return singletonList(WIFI_AP_ADDRESS);
// 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 org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -27,12 +28,14 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
private final Context appContext;
public AndroidLanTcpPluginFactory(Executor ioExecutor,
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
BackoffFactory backoffFactory, Context appContext) {
this.ioExecutor = ioExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
this.appContext = appContext;
}
@@ -51,7 +54,9 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new AndroidLanTcpPlugin(ioExecutor, backoff, appContext,
callback, MAX_LATENCY, MAX_IDLE_TIME);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}
}

View File

@@ -0,0 +1,32 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.util.List;
// TODO: Create a module for this so it doesn't have to be public
public interface CircumventionProvider {
/**
* Countries where Tor is blocked, i.e. vanilla Tor connection won't work.
*
* See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
* and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
*/
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
/**
* Countries where vanilla bridge connection are likely to work.
* Should be a subset of {@link #BLOCKED}.
*/
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
boolean isTorProbablyBlocked(String countryCode);
boolean doBridgesWork(String countryCode);
@IoExecutor
List<String> getBridges();
}

View File

@@ -0,0 +1,70 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.content.res.Resources;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
// TODO: Create a module for this so it doesn't need to be public
public class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges";
private final Context ctx;
@Nullable
private volatile List<String> bridges = null;
@Inject
public CircumventionProviderImpl(Context ctx) {
this.ctx = ctx;
}
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BRIDGES));
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
@Override
public boolean doBridgesWork(String countryCode) {
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
}
@Override
@IoExecutor
public List<String> getBridges() {
if (this.bridges != null) return this.bridges;
Resources res = ctx.getResources();
int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
ctx.getPackageName());
InputStream is = ctx.getResources().openRawResource(resId);
Scanner scanner = new Scanner(is);
List<String> bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (!line.startsWith("#")) bridges.add(line);
}
scanner.close();
this.bridges = bridges;
return bridges;
}
}

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

@@ -1,26 +1,24 @@
package org.briarproject.bramble.plugin.tor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.FileObserver;
import android.os.PowerManager;
import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -31,12 +29,12 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
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.reporting.DevReporter;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.RenewableWakeLock;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable;
@@ -50,6 +48,7 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -57,14 +56,9 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
@@ -72,17 +66,9 @@ import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
@@ -90,12 +76,14 @@ import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
@MethodsNotNullByDefault
@@ -106,50 +94,52 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
};
private static final String OWNER = "__OwningControllerProcess";
private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
private static final int COOKIE_TIMEOUT_MS = 3000;
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
// This tag may prevent Huawei's power manager from killing us
private static final String WAKE_LOCK_TAG = "LocationManagerService";
private static final Logger LOG =
Logger.getLogger(TorPlugin.class.getName());
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Executor ioExecutor, connectionStatusExecutor;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final DevReporter reporter;
private final SocketFactory torSocketFactory;
private final Clock clock;
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile;
private final PowerManager.WakeLock wakeLock;
private final Lock connectionStatusLock;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final RenewableWakeLock wakeLock;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false;
private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
private volatile BroadcastReceiver networkStateReceiver = null;
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils,
DevReporter reporter, SocketFactory torSocketFactory,
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, CircumventionProvider circumventionProvider,
Backoff backoff, DuplexPluginCallback callback,
String architecture, int maxLatency, int maxIdleTime) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.torSocketFactory = torSocketFactory;
this.clock = clock;
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
this.circumventionProvider = circumventionProvider;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
@@ -162,12 +152,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
Object o = appContext.getSystemService(POWER_SERVICE);
PowerManager pm = (PowerManager) o;
// This tag will prevent Huawei's powermanager from killing us.
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService");
wakeLock.setReferenceCounted(false);
connectionStatusLock = new ReentrantLock();
// Don't execute more than one connection status check at a time
connectionStatusExecutor =
new PoliteExecutor("TorPlugin", ioExecutor, 1);
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
}
@Override
@@ -190,18 +181,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (used.getAndSet(true)) throw new IllegalStateException();
// Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets();
LOG.info("Starting Tor");
// Watch for the auth cookie file being updated
try {
cookieFile.getParentFile().mkdirs();
cookieFile.createNewFile();
} catch (IOException e) {
throw new PluginException(e);
}
CountDownLatch latch = new CountDownLatch(1);
FileObserver obs = new WriteObserver(cookieFile, latch);
obs.startWatching();
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Start a new Tor process
LOG.info("Starting Tor");
String torPath = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid());
@@ -240,11 +223,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
throw new PluginException();
}
// Wait for the auth cookie file to be created/updated
if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
throw new PluginException();
long start = clock.currentTimeMillis();
while (cookieFile.length() < 32) {
if (clock.currentTimeMillis() - start > COOKIE_TIMEOUT_MS) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
throw new PluginException();
}
Thread.sleep(COOKIE_POLLING_INTERVAL_MS);
}
LOG.info("Auth cookie created");
} catch (InterruptedException e) {
LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt();
@@ -271,14 +259,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} catch (IOException e) {
throw new PluginException(e);
}
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(ACTION_SCREEN_ON);
filter.addAction(ACTION_SCREEN_OFF);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
appContext.registerReceiver(networkStateReceiver, filter);
// Check whether we're online
updateConnectionStatus(networkManager.getNetworkStatus());
// Bind a server socket to receive incoming hidden service connections
bind();
}
@@ -338,7 +320,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin;
}
private InputStream getConfigInputStream() throws IOException {
private InputStream getConfigInputStream() {
int resId = getResourceId("torrc");
return appContext.getResources().openRawResource(resId);
}
@@ -352,7 +334,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (c != null) c.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
}
}
@@ -360,7 +342,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (s != null) s.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
}
}
@@ -369,7 +351,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
File[] children = f.listFiles();
if (children != null) for (File child : children) listFiles(child);
} else {
LOG.info(f.getAbsolutePath());
LOG.info(f.getAbsolutePath() + " " + f.length());
}
}
@@ -389,14 +371,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
private void sendDevReports() {
ioExecutor.execute(() -> {
// TODO: Trigger this with a TransportEnabledEvent
File reportDir = AndroidUtils.getReportDir(appContext);
reporter.sendReports(reportDir);
});
}
private void bind() {
ioExecutor.execute(() -> {
// If there's already a port number stored in config, reuse it
@@ -410,7 +384,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
tryToClose(ss);
return;
}
@@ -436,7 +410,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (ss != null) ss.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
} finally {
callback.transportDisabled();
}
@@ -455,7 +429,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
response = controlConnection.addOnion(portLines);
else response = controlConnection.addOnion(privKey, portLines);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
return;
}
if (!response.containsKey(HS_ADDRESS)) {
@@ -510,12 +484,21 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
private void enableBridges(boolean enable) throws IOException {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf);
} else {
controlConnection.setConf("UseBridges", "0");
}
}
@Override
public void stop() throws PluginException {
public void stop() {
running = false;
tryToClose(socket);
if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
if (controlSocket != null && controlConnection != null) {
try {
LOG.info("Stopping Tor");
@@ -523,7 +506,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
controlConnection.shutdownTor("TERM");
controlSocket.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
logException(LOG, WARNING, e);
}
}
wakeLock.release();
@@ -545,20 +528,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
@Override
public void poll(Collection<ContactId> connected) {
public void poll(Map<ContactId, TransportProperties> contacts) {
if (!isRunning()) return;
backoff.increment();
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
ContactId c = e.getKey();
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
connectAndCallBack(e.getKey(), e.getValue());
}
}
private void connectAndCallBack(ContactId c, TransportProperties p) {
ioExecutor.execute(() -> {
if (!isRunning()) return;
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
@@ -568,13 +547,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
@Override
public DuplexTransportConnection createConnection(ContactId c) {
public DuplexTransportConnection createConnection(TransportProperties p) {
if (!isRunning()) return null;
return createConnection(callback.getRemoteProperties(c));
}
@Nullable
private DuplexTransportConnection createConnection(TransportProperties p) {
String onion = p.get(PROP_ONION);
if (StringUtils.isNullOrEmpty(onion)) return null;
if (!ONION.matcher(onion).matches()) {
@@ -586,7 +560,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubOnion(onion));
controlConnection.forgetHiddenService(onion);
s = torSocketFactory.createSocket(onion + ".onion", 80);
s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO))
@@ -624,10 +597,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
connectionStatus.getAndSetCircuitBuilt()) {
LOG.info("First circuit built");
backoff.reset();
if (isRunning()) {
sendDevReports();
callback.transportEnabled();
}
if (isRunning()) callback.transportEnabled();
}
}
@@ -638,8 +608,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
if (status.equals("CLOSED") || status.equals("FAILED"))
updateConnectionStatus(); // Check whether we've lost connectivity
if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus());
}
}
@Override
@@ -656,10 +628,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
connectionStatus.setBootstrapped();
backoff.reset();
if (isRunning()) {
sendDevReports();
callback.transportEnabled();
}
if (isRunning()) callback.transportEnabled();
}
}
@@ -669,107 +638,70 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Descriptor uploaded");
}
private static class WriteObserver extends FileObserver {
private final CountDownLatch latch;
private WriteObserver(File file, CountDownLatch latch) {
super(file.getAbsolutePath(), CLOSE_WRITE);
this.latch = latch;
}
@Override
public void onEvent(int event, @Nullable String path) {
stopWatching();
latch.countDown();
}
}
@Override
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) {
LOG.info("Tor settings updated");
updateConnectionStatus();
updateConnectionStatus(networkManager.getNetworkStatus());
}
} else if (e instanceof NetworkStatusEvent) {
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
}
}
private void updateConnectionStatus() {
ioExecutor.execute(() -> {
private void updateConnectionStatus(NetworkStatus status) {
connectionStatusExecutor.execute(() -> {
if (!running) return;
boolean online = status.isConnected();
boolean wifi = status.isWifi();
String country = locationUtils.getCurrentCountry();
boolean blocked =
circumventionProvider.isTorProbablyBlocked(country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
boolean disableWhenBlocked =
s.getBoolean(PREF_TOR_DISABLE_BLOCKED, true);
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi);
if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country);
}
try {
connectionStatusLock.lock();
updateConnectionStatusLocked();
} finally {
connectionStatusLock.unlock();
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
enableNetwork(false);
} else if (blocked) {
if (circumventionProvider.doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else if (disableWhenBlocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else {
LOG.info("Enabling network but country is blocked");
enableBridges(false);
enableNetwork(true);
}
} else {
LOG.info("Enabling network");
enableBridges(false);
enableNetwork(true);
}
} catch (IOException e) {
logException(LOG, WARNING, e);
}
});
}
// Locking: connectionStatusLock
private void updateConnectionStatusLocked() {
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry();
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi);
if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country);
}
try {
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (blocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
enableNetwork(false);
} else {
LOG.info("Enabling network");
enableNetwork(true);
}
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
private void scheduleConnectionStatusUpdate() {
Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, 1, MINUTES);
Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
if (!running) return;
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
updateConnectionStatus();
if (ACTION_SCREEN_ON.equals(action)
|| ACTION_SCREEN_OFF.equals(action)) {
scheduleConnectionStatusUpdate();
}
}
}
private static class ConnectionStatus {
// All of the following are locking: this
@@ -788,7 +720,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private synchronized void enableNetwork(boolean enable) {
networkEnabled = enable;
circuitBuilt = false;
if (!enable) circuitBuilt = false;
}
private synchronized boolean isConnected() {

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.os.Build;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -12,7 +13,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
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.util.AndroidUtils;
@@ -39,25 +40,30 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final DevReporter reporter;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final CircumventionProvider circumventionProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, DevReporter reporter,
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory) {
BackoffFactory backoffFactory,
CircumventionProvider circumventionProvider, Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.circumventionProvider = circumventionProvider;
this.clock = clock;
}
@Override
@@ -94,8 +100,9 @@ public class TorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, reporter, torSocketFactory, backoff, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME);
networkManager, locationUtils, torSocketFactory, clock,
circumventionProvider, backoff, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

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

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Build;
@@ -10,11 +11,15 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE;
public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
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,
BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake
@SuppressLint("HardwareIds")
String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake
@@ -51,19 +57,6 @@ public class AndroidUtils {
&& !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) {
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

@@ -2,6 +2,7 @@ apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness'
dependencies {
@@ -14,6 +15,8 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
dependencyVerification {
@@ -26,6 +29,9 @@ dependencyVerification {
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
@@ -33,6 +39,7 @@ dependencyVerification {
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}
@@ -48,8 +55,3 @@ task jarTest(type: Jar, dependsOn: testClasses) {
artifacts {
testOutput jarTest
}
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
tasks.withType(JavaCompile) {
useJava6StandardLibrary(it)
}

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.identity.Author;
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.Message;
import org.briarproject.bramble.api.sync.MessageId;
@@ -88,6 +90,10 @@ public interface ClientHelper {
BdfDictionary toDictionary(byte[] b, int off, int len)
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) throws FormatException;
@@ -99,8 +105,15 @@ public interface ClientHelper {
byte[] sign(String label, BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException;
void verifySignature(String label, byte[] sig, byte[] publicKey,
BdfList signed) throws FormatException, GeneralSecurityException;
void verifySignature(byte[] signature, String label, BdfList signed,
byte[] publicKey) throws FormatException, GeneralSecurityException;
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.
*/
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.
*/
Group createContactGroup(ClientId clientId, int clientVersion,
Group createContactGroup(ClientId clientId, int majorVersion,
Contact contact);
/**
* Creates a group for the given client to share between the given authors
* identified by their AuthorIds.
*/
Group createContactGroup(ClientId clientId, int clientVersion,
Group createContactGroup(ClientId clientId, int majorVersion,
AuthorId authorId1, AuthorId authorId2);
}

View File

@@ -13,9 +13,9 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
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.

View File

@@ -6,7 +6,7 @@ import javax.annotation.concurrent.Immutable;
/**
* 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
@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.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
@@ -13,30 +14,40 @@ import java.util.Collection;
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.
*/
void registerRemoveContactHook(RemoveContactHook hook);
/**
* Stores a contact within the given transaction associated with the given
* local and remote pseudonyms, and returns an ID for the contact.
* 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(Transaction txn, Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified,
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.
*/
ContactId addContact(Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException;
ContactId addContact(Transaction txn, Author remote, AuthorId local,
boolean verified, 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.
@@ -94,11 +105,10 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
interface AddContactHook {
void addingContact(Transaction txn, Contact c) throws DbException;
}
interface ContactHook {
void addingContact(Transaction txn, Contact c) throws DbException;
interface RemoveContactHook {
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
* @return true if the signature was valid, false otherwise.
*/
boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException;
boolean verifySignature(byte[] signature, String label, byte[] signed,
byte[] publicKey) throws GeneralSecurityException;
/**
* 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);
/**
* 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
* 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.
*/
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;
/**
* 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
@NotNullByDefault

View File

@@ -14,9 +14,10 @@ public interface TransportCrypto {
* rotation period from the given master secret.
*
* @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,
long rotationPeriod, boolean alice);
long rotationPeriod, boolean alice, boolean active);
/**
* 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>
*/
public static BdfDictionary of(Entry<String, Object>... entries) {
public static BdfDictionary of(Entry<String, ?>... entries) {
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;
}
@@ -34,7 +34,7 @@ public class BdfDictionary extends TreeMap<String, Object> {
super();
}
public BdfDictionary(Map<String, Object> m) {
public BdfDictionary(Map<String, ?> m) {
super(m);
}

View File

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

View File

@@ -9,5 +9,6 @@ public interface BdfReaderFactory {
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.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -18,7 +19,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer;
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 java.util.Collection;
@@ -43,7 +45,8 @@ public interface DatabaseComponent {
* @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated
*/
boolean open(@Nullable MigrationListener listener) throws DbException;
boolean open(SecretKey key, @Nullable MigrationListener listener)
throws DbException;
/**
* Waits for any open transactions to finish and closes the database.
@@ -103,10 +106,11 @@ public interface DatabaseComponent {
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)
throws DbException;
KeySetId addTransportKeys(Transaction txn, ContactId c,
TransportKeys k) throws DbException;
/**
* 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
* {@link #removeMessage(Transaction, MessageId)}, the message ID and any
* other associated data are not deleted.
* {@link #removeMessage(Transaction, MessageId)}, the message ID,
* dependencies, metadata, and any other associated state are not deleted.
*/
void deleteMessage(Transaction txn, MessageId m) throws DbException;
@@ -233,7 +237,8 @@ public interface DatabaseComponent {
* <p/>
* 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
@@ -258,6 +263,14 @@ public interface DatabaseComponent {
*/
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.
* <p/>
@@ -302,9 +315,9 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns the metadata for any messages in the given group with metadata
* that matches all entries in the given query. If the query is empty, the
* metadata for all messages is returned.
* Returns the metadata for any delivered messages in the given group with
* metadata that matches all entries in the given query. If the query is
* empty, the metadata for all delivered messages is returned.
* <p/>
* Read-only.
*/
@@ -320,8 +333,8 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns the metadata for the given delivered and pending message.
* This is meant to be only used by the ValidationManager
* Returns the metadata for the given delivered or pending message.
* This is only meant to be used by the ValidationManager.
* <p/>
* Read-only.
*/
@@ -329,8 +342,8 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns the status of all messages in the given group with respect to
* the given contact.
* Returns the status of all delivered messages in the given group with
* respect to the given contact.
* <p/>
* Read-only.
*/
@@ -339,12 +352,8 @@ public interface DatabaseComponent {
/**
* Returns the IDs and states of all dependencies of the given message.
* Missing dependencies have the state
* {@link ValidationManager.State UNKNOWN}.
* 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.
* For missing dependencies and dependencies in other groups, the state
* {@link State UNKNOWN} is returned.
* <p/>
* Read-only.
*/
@@ -352,9 +361,9 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns all IDs of messages that depend on the given message.
* Messages in other groups that declare a dependency on the given message
* will be returned even though such dependencies are invalid.
* Returns the IDs and states of all dependents of the given message.
* Dependents in other groups are not returned. If the given message is
* missing, no dependents are returned.
* <p/>
* Read-only.
*/
@@ -369,8 +378,8 @@ public interface DatabaseComponent {
State getMessageState(Transaction txn, MessageId m) throws DbException;
/**
* Returns the status of the given message with respect to the given
* contact.
* Returns the status of the given delivered message with respect to the
* given contact.
* <p/>
* Read-only.
*/
@@ -399,15 +408,14 @@ public interface DatabaseComponent {
* <p/>
* Read-only.
*/
Map<ContactId, TransportKeys> getTransportKeys(Transaction txn,
TransportId t) throws DbException;
Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
throws DbException;
/**
* Increments the outgoing stream counter for the given contact and
* transport in the given rotation period .
* Increments the outgoing stream counter for the given transport keys.
*/
void incrementStreamCounter(Transaction txn, ContactId c, TransportId t,
long rotationPeriod) throws DbException;
void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* 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;
/**
* Removes the given transport keys from the database.
*/
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* Marks the given contact as verified.
*/
@@ -512,15 +526,21 @@ public interface DatabaseComponent {
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.
*/
void setReorderingWindow(Transaction txn, ContactId c, TransportId t,
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
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.
*/
void updateTransportKeys(Transaction txn,
Map<ContactId, TransportKeys> keys) throws DbException;
void updateTransportKeys(Transaction txn, Collection<KeySet> keys)
throws DbException;
}

View File

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

View File

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

View File

@@ -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
* for annotating methods that should run on the UI executor.
* for annotating methods that should run on the IO executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks may run indefinitely. Tasks

View File

@@ -1,13 +1,12 @@
package org.briarproject.bramble.api.lifecycle;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
/**
* Manages the lifecycle of the app, starting {@link Client Clients}, starting
* and stopping {@link Service Services}, shutting down
@@ -18,7 +17,7 @@ import javax.annotation.Nullable;
public interface LifecycleManager {
/**
* The result of calling {@link #startServices(String)}.
* The result of calling {@link #startServices(SecretKey)}.
*/
enum StartResult {
ALREADY_RUNNING,
@@ -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);
/**
* 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);
/**
* 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);
/**
* Opens the {@link DatabaseComponent}, optionally creates a local author
* with the provided nickname, and starts any registered
* {@link Client Clients} and {@link Service Services}.
* Opens the {@link DatabaseComponent} using the given key and starts any
* registered {@link Client Clients} and {@link Service Services}.
*/
StartResult startServices(@Nullable String nickname);
StartResult startServices(SecretKey dbKey);
/**
* Stops any registered {@link Service Services}, shuts down any

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,9 @@
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.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import java.util.Map;
/**
* An interface through which a transport plugin interacts with the rest of
* the application.
@@ -25,17 +22,7 @@ public interface PluginCallback {
TransportProperties getLocalProperties();
/**
* Returns the plugin's remote transport properties.
*/
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
* Merges the given settings with the plugin's settings
*/
void mergeSettings(Settings s);
@@ -45,34 +32,12 @@ public interface PluginCallback {
void mergeLocalProperties(TransportProperties p);
/**
* Presents the user with a choice among two or more named options and
* 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.
* Signals that the transport is enabled.
*/
void transportEnabled();
/**
* Signal that the transport got disabled.
* Signals that the transport is disabled.
*/
void transportDisabled();
}

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,23 @@
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 {
/**
* 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;
public TransportId(String id) {
byte[] b = id.getBytes(Charset.forName("UTF-8"));
if (b.length == 0 || b.length > MAX_TRANSPORT_ID_LENGTH)
int length = StringUtils.toUtf8(id).length;
if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH)
throw new IllegalArgumentException();
this.id = id;
}

View File

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

View File

@@ -1,10 +1,10 @@
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.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable;
@@ -15,12 +15,11 @@ import javax.annotation.Nullable;
public interface DuplexPlugin extends Plugin {
/**
* Attempts to create and return a connection to the given contact using
* the current transport and configuration properties. Returns null if a
* connection cannot be created.
* Attempts to create and return a connection using the given transport
* properties. Returns null if a connection cannot be created.
*/
@Nullable
DuplexTransportConnection createConnection(ContactId c);
DuplexTransportConnection createConnection(TransportProperties p);
/**
* 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;
/**
* 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
public interface DuplexPluginCallback extends PluginCallback {

View File

@@ -1,10 +1,10 @@
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.plugin.Plugin;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable;
@@ -15,18 +15,16 @@ import javax.annotation.Nullable;
public interface SimplexPlugin extends Plugin {
/**
* Attempts to create and return a reader for the given contact using the
* current transport and configuration properties. Returns null if a reader
* cannot be created.
* Attempts to create and return a reader for the given transport
* properties. Returns null if a reader cannot be created.
*/
@Nullable
TransportConnectionReader createReader(ContactId c);
TransportConnectionReader createReader(TransportProperties p);
/**
* Attempts to create and return a writer for the given contact using the
* current transport and configuration properties. Returns null if a writer
* cannot be created.
* Attempts to create and return a writer for the given transport
* properties. Returns null if a writer cannot be created.
*/
@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;
/**
* An interface for handling readers and writers created by a simplex transport
* plugin.
* An interface through which a simplex plugin interacts with the rest of the
* application.
*/
@NotNullByDefault
public interface SimplexPluginCallback extends PluginCallback {

View File

@@ -15,12 +15,17 @@ public interface TransportPropertyManager {
/**
* 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
@@ -37,8 +42,8 @@ public interface TransportPropertyManager {
/**
* Returns the local transport properties for all transports.
* <br/>
* TODO: Transaction can be read-only when code is simplified
* <p/>
* Read-only.
*/
Map<TransportId, TransportProperties> getLocalProperties(Transaction txn)
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.nullsafety.NotNullByDefault;
import java.io.File;
@NotNullByDefault
public interface DevConfig {
PublicKey getDevPublicKey();
String getDevOnionAddress();
File getReportDir();
}

View File

@@ -23,8 +23,6 @@ public interface DevReporter {
/**
* 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;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
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
@NotNullByDefault
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;
public ClientId(String id) {
int length = StringUtils.toUtf8(id).length;
if (length == 0 || length > MAX_CLIENT_ID_LENGTH)
throw new IllegalArgumentException();
this.id = id;
}

View File

@@ -5,20 +5,43 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPT
public class Group {
public enum Visibility {
INVISIBLE, // The group is not visible
VISIBLE, // The group is visible but messages are not shared
SHARED // The group is visible and messages are shared
INVISIBLE(0), // The group is not visible
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 ClientId clientId;
private final int majorVersion;
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)
throw new IllegalArgumentException();
this.id = id;
this.clientId = clientId;
this.majorVersion = majorVersion;
this.descriptor = descriptor;
}
@@ -36,6 +59,13 @@ public class Group {
return clientId;
}
/**
* Returns the major version of the client to which the group belongs.
*/
public int getMajorVersion() {
return majorVersion;
}
/**
* Returns the group's descriptor.
*/

View File

@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
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 {
/**
* The current version of the message format.
*/
public static final int FORMAT_VERSION = 1;
private final MessageId id;
private final GroupId groupId;
private final long timestamp;

View File

@@ -7,5 +7,7 @@ public interface MessageFactory {
Message createMessage(GroupId g, long timestamp, byte[] body);
Message createMessage(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.
*/
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) {
super(id);

View File

@@ -2,6 +2,8 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
public interface SyncConstants {
/**
@@ -10,16 +12,8 @@ public interface SyncConstants {
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
/**
@@ -40,5 +34,5 @@ public interface SyncConstants {
/**
* 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;
@NotNullByDefault
public interface RecordReader {
public interface SyncRecordReader {
boolean eof() throws IOException;

View File

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

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.OutputStream;
@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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.InputStream;
import java.io.OutputStream;
@NotNullByDefault
public interface SyncSessionFactory {
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
SyncSession createIncomingSession(ContactId c, InputStream in);
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
OutputStream out);
StreamWriter streamWriter);
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;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
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
* called once for each incoming message that passes validation.
* Registers the incoming message hook for the given client. The hook will
* be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, IncomingMessageHook hook);
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
interface MessageValidator {

View File

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

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.plugin.TransportId;
import java.util.Map;
import javax.annotation.Nullable;
/**
@@ -16,12 +18,30 @@ public interface KeyManager {
/**
* 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
* 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,
long timestamp, boolean alice) throws DbException;
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
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

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 long rotationPeriod, streamCounter;
private final boolean active;
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod) {
this(tagKey, headerKey, rotationPeriod, 0);
long rotationPeriod, boolean active) {
this(tagKey, headerKey, rotationPeriod, 0, active);
}
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
long rotationPeriod, long streamCounter) {
long rotationPeriod, long streamCounter, boolean active) {
this.tagKey = tagKey;
this.headerKey = headerKey;
this.rotationPeriod = rotationPeriod;
this.streamCounter = streamCounter;
this.active = active;
}
public SecretKey getTagKey() {
@@ -39,4 +41,8 @@ public class OutgoingKeys {
public long getStreamCounter() {
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
* transport stream
*/
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
StreamWriter createStreamWriter(OutputStream out, StreamContext ctx);
/**
* Creates an {@link OutputStream OutputStream} for writing to a contact
* exchange stream.
*/
OutputStream createContactExchangeStreamWriter(OutputStream out,
StreamWriter createContactExchangeStreamWriter(OutputStream out,
SecretKey headerKey);
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.ui;
public interface UiCallback {
/**
* Presents the user with a choice among two or more named options and
* 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);
}

View File

@@ -0,0 +1,50 @@
package org.briarproject.bramble.api.versioning;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class ClientMajorVersion implements Comparable<ClientMajorVersion> {
private final ClientId clientId;
private final int majorVersion;
public ClientMajorVersion(ClientId clientId, int majorVersion) {
this.clientId = clientId;
this.majorVersion = majorVersion;
}
public ClientId getClientId() {
return clientId;
}
public int getMajorVersion() {
return majorVersion;
}
@Override
public boolean equals(Object o) {
if (o instanceof ClientMajorVersion) {
ClientMajorVersion cv = (ClientMajorVersion) o;
return clientId.equals(cv.clientId)
&& majorVersion == cv.majorVersion;
}
return false;
}
@Override
public int hashCode() {
return (clientId.hashCode() << 16) + majorVersion;
}
@Override
public int compareTo(ClientMajorVersion cv) {
int compare = clientId.compareTo(cv.clientId);
if (compare != 0) return compare;
return majorVersion - cv.majorVersion;
}
}

View File

@@ -0,0 +1,46 @@
package org.briarproject.bramble.api.versioning;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group.Visibility;
@NotNullByDefault
public interface ClientVersioningManager {
/**
* The unique ID of the versioning client.
*/
ClientId CLIENT_ID = new ClientId("org.briarproject.bramble.versioning");
/**
* The current major version of the versioning client.
*/
int MAJOR_VERSION = 0;
/**
* Registers a client that will be advertised to contacts. The hook will
* be called when the visibility of the client changes. This method should
* be called before {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerClient(ClientId clientId, int majorVersion, int minorVersion,
ClientVersioningHook hook);
/**
* Returns the visibility of the given client with respect to the given
* contact.
*/
Visibility getClientVisibility(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException;
interface ClientVersioningHook {
void onClientVisibilityChanging(Transaction txn, Contact c,
Visibility v) throws DbException;
}
}

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