Compare commits

...

713 Commits

Author SHA1 Message Date
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
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
Torsten Grote
235183a3af Merge branch '1177-blank-viewfinder' into 'master'
Show viewfinder again after connection fails

Closes #1177

See merge request akwizgran/briar!735
2018-03-20 13:13:14 +00:00
akwizgran
701e51dfc8 When resetting, restart camera if we've stopped it. 2018-03-20 11:58:58 +00:00
akwizgran
3361922834 Don't create a stack of QR code fragments. 2018-03-20 11:58:57 +00:00
akwizgran
fcabf697d6 Remove performance logging. 2018-03-20 11:58:57 +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
Torsten Grote
4d502576c9 Merge branch '545-remove-clientid-from-validator-db-methods' into 'master'
Remove client ID from validator's DB methods

See merge request akwizgran/briar!732
2018-03-14 12:39:59 +00: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
akwizgran
5fe68e6f82 Remove client ID from validator's DB methods. 2018-03-09 16:11:58 +00:00
akwizgran
f725c7ab9a Merge branch '1169-settings-npe' into 'master'
Disable settings until they have been loaded

Closes #1169

See merge request akwizgran/briar!726
2018-03-08 15:40:13 +00:00
Torsten Grote
03b4907311 Disable settings until they have been loaded
In practise, this is not noticeable in the UI.
Only when the database is congested, it should become visible and
prevent a crash when the sound setting is clicked.
2018-03-07 15:20:09 -03:00
Torsten Grote
809b9f8919 Update translations 2018-03-07 09:49:46 -03:00
akwizgran
85cc23444c Merge branch 'transport-indicators-no-buttons' into 'master'
Prevent transport indicators from looking like buttons

Closes #185

See merge request akwizgran/briar!714
2018-03-07 10:41:13 +00:00
akwizgran
c073c5c8bd Merge branch '283-key-exchange-connections' into 'master'
Refactor key agreement connection choosing

Closes #283

See merge request akwizgran/briar!711
2018-03-07 10:37:45 +00:00
akwizgran
976c8a9578 Merge branch '1174-link-click-crash' into 'master'
Get unwrapped context when clicking links to prevent crash on Android 4

Closes #1174

See merge request akwizgran/briar!709
2018-03-07 10:36:33 +00:00
akwizgran
d52ca14ebe Merge branch '1168-startup-status-screen' into 'master'
Show status message while opening and migrating DB

Closes #1168

See merge request akwizgran/briar!708
2018-03-07 10:30:11 +00:00
Torsten Grote
a178dbae9e Prevent transport indicators from looking like buttons 2018-03-06 16:58:23 -03:00
akwizgran
9a4f0b8e89 Add more lifecycle states, merge lifecycle events. 2018-03-06 15:21:26 -03:00
Torsten Grote
db7dbfce68 Start NavDrawerActivity only after database was opened and services started 2018-03-06 15:14:37 -03:00
Torsten Grote
80770b0216 Show a status screen when opening the database or applying migrations 2018-03-06 15:14:36 -03:00
Torsten Grote
9f02bbbba1 Do not show splash screen when signed in 2018-03-06 15:14:35 -03:00
Torsten Grote
190aeef34e Passing in reference to FragmentManager when clicking links to prevent crash on Android 4 2018-03-06 15:01:37 -03:00
akwizgran
6fbaae0e5e Merge branch 'fix-intro-fragment' into 'master'
Fix uncentered intro fragment

See merge request akwizgran/briar!712
2018-03-05 10:51:56 +00:00
akwizgran
5cc0f08b8f Merge branch '1154-fix-notification-light' into 'master'
Fix notification light

Closes #1154

See merge request akwizgran/briar!710
2018-03-05 10:49:29 +00:00
goapunk
976460e0b7 fix uncentered intro fragment
Signed-off-by: goapunk <noobie@goapunks.net>
2018-03-03 16:21:34 +01:00
akwizgran
9cdd537600 Refactor key agreement connection choosing. 2018-03-02 13:11:56 +00:00
Torsten Grote
c44a3d01b9 Fix notification light 2018-02-28 12:53:22 -03:00
akwizgran
a8ed86575d Merge branch '1136-startup-failure-ux' into 'master'
Improve UX for startup failures

Closes #1136

See merge request akwizgran/briar!706
2018-02-26 17:18:44 +00:00
Torsten Grote
46406d8d1a Improve UX for startup failures
Show a proper error message when database is too new or too old.
2018-02-26 13:39:07 -03:00
Torsten Grote
05210257a0 Merge branch '1176-startup-failure-crash' into 'master'
Inject StartupFailureActivity to prevent NPE

Closes #1176

See merge request akwizgran/briar!705
2018-02-23 12:24:29 +00:00
akwizgran
d5c89640c1 Inject StartupFailureActivity to prevent NPE. 2018-02-23 09:22:31 +00:00
Torsten Grote
3f1fb1ca1c Merge branch '346-qr-code-optimisations' into 'master'
Improve QR code scanning on phones with high res cameras and slow CPUs

Closes #1068

See merge request akwizgran/briar!699
2018-02-22 18:09:52 +00:00
akwizgran
bfdc79ac60 Use ConstraintLayout for intro fragment. 2018-02-22 17:10:19 +00:00
akwizgran
06897569d4 Add javadoc links. 2018-02-22 17:10:18 +00:00
akwizgran
66e3f6deba Crop camera preview before looking for QR code. 2018-02-22 17:10:16 +00:00
akwizgran
528a52d0f7 Add landscape layout for QR code fragment. 2018-02-22 17:09:33 +00:00
Torsten Grote
d395f0866a Merge branch '1173-qr-code-version' into 'master'
Use first byte of QR code payload for format version

Closes #1173

See merge request akwizgran/briar!702
2018-02-22 16:40:30 +00:00
akwizgran
363dfbc6aa Merge branch '1164-store-bluetooth-properties' into 'master'
Store Bluetooth address and UUID at first startup

Closes #1164

See merge request akwizgran/briar!694
2018-02-22 15:11:01 +00:00
Torsten Grote
c6f2941e74 Merge branch '542-include-requested-messages' into 'master'
Include requested messages when getting next send time

See merge request akwizgran/briar!704
2018-02-22 13:09:44 +00:00
akwizgran
a61cd01336 Address review comments. 2018-02-22 12:52:49 +00:00
akwizgran
10f63ad60b Include requested messages when getting next send time. 2018-02-22 12:46:33 +00:00
akwizgran
0b781cf272 Use first byte of QR code payload for format version. 2018-02-22 11:59:06 +00:00
akwizgran
6dc7277771 Merge branch '542-retransmission' into 'master'
Don't poll for retransmission

Closes #542

See merge request akwizgran/briar!695
2018-02-22 11:07:21 +00:00
akwizgran
d880b14e0c Merge branch '1134-old-qr-code-error' into 'master'
Show an error fragment when an unsupported QR code is scanned

Closes #1134

See merge request akwizgran/briar!675
2018-02-22 10:55:44 +00:00
Torsten Grote
f88c68eff4 Merge branch '545-denormalise-statuses' into 'master'
Add denormalised columns to statuses table

See merge request akwizgran/briar!691
2018-02-19 16:53:55 +00:00
akwizgran
5fce8cbe0a Don't poll for retransmission. 2018-02-19 16:27:04 +00:00
akwizgran
439654e71d Test that visibility change affects expected contacts. 2018-02-19 16:25:02 +00:00
akwizgran
7fe502e3cc Add denormalised columns to statuses table. 2018-02-19 16:07:08 +00:00
akwizgran
aa07d0cadd Merge branch '509-tap-viewfinder-to-auto-focus' into 'master'
Tap viewfinder to restart auto focus

Closes #509

See merge request akwizgran/briar!697
2018-02-19 15:57:49 +00:00
akwizgran
d9cca3d9eb Merge branch '1137-stop-polling-disabled-plugins' into 'master'
Don't poll disabled transport plugins

Closes #1137

See merge request akwizgran/briar!698
2018-02-19 14:45:56 +00:00
Torsten Grote
94c5f61cc3 Merge branch 'raw-qr-codes' into 'master'
Use raw byte mode for QR codes

See merge request akwizgran/briar!696
2018-02-19 14:44:38 +00:00
Torsten Grote
9cce0d8e15 Show an error fragment when an unsupported QR code is scanned 2018-02-19 09:41:16 -03:00
Torsten Grote
44488b5187 Merge branch 'multiset' into 'master'
Use a multiset for counting things

See merge request akwizgran/briar!688
2018-02-19 12:36:01 +00:00
akwizgran
4d6ac13338 Bump DB schema version as public key format has changed. 2018-02-14 14:29:06 +00:00
akwizgran
ef3afa7832 Don't poll disabled transport plugins. 2018-02-10 11:42:21 +00:00
akwizgran
687ea132f6 Tap viewfinder to restart auto focus. 2018-02-09 17:51:49 +00:00
akwizgran
452e544ed1 Use raw byte mode for QR codes. 2018-02-09 16:57:13 +00:00
akwizgran
6b60509122 Add curve25519-java to ProGuard rules. 2018-02-09 16:45:15 +00:00
akwizgran
e01e971822 Merge branch '236-curve25519' into 'master'
Use Curve25519 for key agreement

Closes #236

See merge request akwizgran/briar!693
2018-02-09 10:13:56 +00:00
akwizgran
186a7db8cb Merge branch '236-use-ed25519' into 'master'
Use Ed25519 for signatures

See merge request akwizgran/briar!686
2018-02-09 10:12:56 +00:00
akwizgran
565452f7d3 Don't set running = true until properties have been loaded. 2018-02-08 15:03:49 +00:00
akwizgran
de7e3dd225 Store Bluetooth address and UUID at first startup. 2018-02-08 14:56:04 +00:00
akwizgran
8bdf04a289 Clamp private keys, add test vectors. 2018-02-02 22:24:28 +00:00
akwizgran
56a5b8df87 Use Curve25519 for key agreement. 2018-02-02 17:52:18 +00:00
akwizgran
ad241a14e3 Use WhisperSystems Curve25519 library. 2018-02-02 17:07:43 +00:00
akwizgran
2a7bdcd270 Add Curve25519 and Ed25519 to performance tests.
Note: Curve25519 is tested using standard ECDH and ECDHC over the Curve25519 curve.
2018-02-02 17:06:42 +00:00
Torsten Grote
88c61ecfb5 Merge branch '594-db-migrations' into 'master'
Migrate schema when opening database

Closes #594

See merge request akwizgran/briar!680
2018-02-02 11:49:03 +00:00
Torsten Grote
bee9dbb9c4 Merge branch '545-remove-unnecessary-indexes' into 'master'
Remove unnecessary DB indexes

See merge request akwizgran/briar!687
2018-02-01 17:30:47 +00:00
akwizgran
36e0f97d82 Remove unnecessary DB indexes. 2018-02-01 17:21:17 +00:00
akwizgran
8bb08a2af9 Throw meaningful exceptions for schema errors. 2018-02-01 17:07:54 +00:00
akwizgran
6bf2cb69c5 Use Ed25519 for signatures. 2018-02-01 16:56:50 +00:00
akwizgran
7a1247e325 Add test vectors for Ed25519. 2018-02-01 16:17:51 +00:00
akwizgran
ce5879bdb5 Merge branch '1162-redundant-db-tasks' into 'master'
Avoid queueing redundant DB tasks during sync

Closes #1162

See merge request akwizgran/briar!681
2018-02-01 15:06:43 +00:00
akwizgran
55221a5066 Merge branch '1148-wrong-network-interface' into 'master'
Prefer LAN addresses with longer prefixes

Closes #1148

See merge request akwizgran/briar!659
2018-02-01 10:54:21 +00:00
akwizgran
9e7f1df8e9 Merge branch '1143-screen-overlay-dialog' into 'master'
Don't show screen overlay dialog if all overlay apps have been allowed

Closes #1143

See merge request akwizgran/briar!658
2018-02-01 10:46:41 +00:00
akwizgran
ec7e599143 Merge branch '1116-samsung-back-crash' into 'master'
Workaround for Samsung crash in Android 4.4

Closes #1116

See merge request akwizgran/briar!674
2018-02-01 10:41:09 +00:00
akwizgran
e0a67d1eb9 Remove unused argument. 2018-02-01 10:39:26 +00:00
akwizgran
a50ded2d50 Simplify dialog handling, work around Android bug. 2018-02-01 10:37:56 +00:00
akwizgran
dab9a3e73d Update screen overlay warning text. 2018-02-01 10:36:47 +00:00
akwizgran
dae8e6d759 Re-show dialog when activity resumes or is recreated. 2018-02-01 10:36:47 +00:00
akwizgran
60d38b034d Set layout weight so checkbox is visible. 2018-02-01 10:36:47 +00:00
akwizgran
863c908267 Cache the list of overlay apps. 2018-02-01 10:36:47 +00:00
akwizgran
753068288f Allow filtered taps if all overlay apps are whitelisted. 2018-02-01 10:36:46 +00:00
akwizgran
f9eda0b096 Fix test expectations. 2018-02-01 10:29:05 +00:00
akwizgran
f4401ee524 Add comment. 2018-02-01 10:22:10 +00:00
akwizgran
3dbc3cef56 Apply more than one migration if suitable. 2018-02-01 10:14:34 +00:00
akwizgran
bf4ecd21aa Add a generic multiset implementation. 2018-02-01 09:55:10 +00:00
akwizgran
ea3ada5573 Avoid queueing redundant DB tasks during sync. 2018-01-31 17:26:42 +00:00
akwizgran
9889f86f69 Add unit tests for migration logic. 2018-01-31 15:41:21 +00:00
akwizgran
4d62447a86 Migrate database schema if a migration is available. 2018-01-31 12:07:58 +00:00
akwizgran
7ec05ac0cd Merge branch '790-ask-before-turning-on-bluetooth' into 'master'
Ask before turning on Bluetooth to add a contact

Closes #790

See merge request akwizgran/briar!664
2018-01-29 15:37:41 +00:00
akwizgran
1b2a1d658d Merge branch '1007-samsung-transition-npe-fix' into 'master'
Another attempt at fixing an infamous Samsung activity transition NPE

Closes #1007

See merge request akwizgran/briar!677
2018-01-29 14:20:08 +00:00
Torsten Grote
a2bbc5e455 Another attempt at fixing an infamous Samsung activity transition NPE 2018-01-29 10:55:36 -02:00
Torsten Grote
006cb067ad Update translations
New translations: br, nl, he, sv, cs, ja
2018-01-29 10:33:17 -02:00
Torsten Grote
a2e422a23e Workaround for Samsung crash in Android 4.4
Closes #1116
2018-01-24 11:15:14 -02:00
akwizgran
02cec9bacb Merge branch 'tor-plugin-detect-connectivity-loss' into 'master'
Tor plugin should detect connectivity loss

See merge request akwizgran/briar!670
2018-01-23 17:15:09 +00:00
akwizgran
fcd9b20161 Merge branch 'scrypt' into 'master'
Use scrypt for password-based key derivation

See merge request akwizgran/briar!665
2018-01-22 15:18:36 +00:00
akwizgran
204711e5db Reduce minimum scrypt cost for low-end devices. 2018-01-22 14:39:58 +00:00
akwizgran
64c129d399 Add format version to password-encrypted database key. 2018-01-22 14:39:58 +00:00
akwizgran
6bdb099aa9 Use scrypt for password-based key derivation. 2018-01-22 14:39:49 +00:00
Torsten Grote
3e55be8a82 Merge branch 'change-password-activity' into 'master'
ChangePasswordActivity should extend BriarActivity

See merge request akwizgran/briar!671
2018-01-20 14:11:32 +00:00
akwizgran
8f37957a46 Use scheduler service to schedule connectivity checks. 2018-01-19 12:29:14 +00:00
akwizgran
a5386e0183 Listen for a wider range of connectivity-related events. 2018-01-19 12:28:22 +00:00
akwizgran
117e88bf1f Use Tor's OR connection events to detect lost connectivity. 2018-01-19 12:28:22 +00:00
akwizgran
f47900c4d3 ChangePasswordActivity should extend BriarActivity. 2018-01-19 11:50:27 +00:00
akwizgran
f641e16512 Merge branch 'blake2b' into 'master'
Use BLAKE2b for hashing

See merge request akwizgran/briar!667
2018-01-19 11:04:27 +00:00
akwizgran
df0613f290 Fix import of wrong Immutable annotation. 2018-01-19 09:54:19 +00:00
akwizgran
711475d45a Merge branch '1001-bluetooth-connects-to-contacts' into 'master'
Don't make Bluetooth connections when configured not to

Closes #1001

See merge request akwizgran/briar!663
2018-01-17 11:13:27 +00:00
akwizgran
3fd47fc1c7 Merge branch 'bluetooth-refactoring' into 'master'
Factor shared Bluetooth code into superclass

Closes #831

See merge request akwizgran/briar!662
2018-01-17 11:11:20 +00:00
Torsten Grote
a1a946edea Merge branch '617-author-versioning' into 'master'
Use a versioned format for encoding authors

See merge request akwizgran/briar!661
2018-01-16 18:36:32 +00:00
akwizgran
699b037a3e Remove redundant constant for max blog name length. 2018-01-16 17:39:49 +00:00
akwizgran
e474042af7 Use author encoding and parsing helpers everywhere. 2018-01-16 17:38:21 +00:00
akwizgran
68634e0f28 Add helper method for encoding authors. 2018-01-16 17:22:35 +00:00
akwizgran
1d81110fe5 Bump database schema version. 2018-01-16 15:32:52 +00:00
akwizgran
030b9ef053 Use a versioned format for encoding authors. 2018-01-16 15:30:59 +00:00
akwizgran
7d8d169b0a Merge branch '1092-denormalise-message-metadata' into 'master'
Add denormalised state column to messageMetadata table

Closes #1092

See merge request akwizgran/briar!654
2018-01-16 13:01:49 +00:00
akwizgran
11e2d4ecfb Fix indentation. 2018-01-16 12:54:16 +00:00
Torsten Grote
80ad5d8c7b Merge branch '1145-avoid-unnecessary-db-queries' into 'master'
Avoid unnecessary DB queries when starting clients

Closes #1145

See merge request akwizgran/briar!660
2018-01-16 12:03:49 +00:00
akwizgran
53a15c05aa Merge branch 'prefer-project-modules' into 'master'
Prefer project modules over prebuilt dependencies

See merge request akwizgran/briar!666
2018-01-12 17:33:53 +00:00
akwizgran
45bc6a51b0 Use BLAKE2b for hashing. 2018-01-12 17:33:28 +00:00
akwizgran
db21dcedb1 Prefer project modules over prebuilt dependencies. 2018-01-12 16:28:40 +00:00
akwizgran
96c8274091 Ask before turning on Bluetooth to add a contact. 2018-01-10 17:47:43 +00:00
akwizgran
0c7c465ef7 Remove unnecessary executor calls. 2018-01-10 16:55:17 +00:00
akwizgran
fd6bf42ea4 Don't make Bluetooth connections when configured not to. 2018-01-10 16:51:06 +00:00
akwizgran
0c5976b287 Factor shared Bluetooth code into superclass. 2018-01-10 13:03:07 +00:00
akwizgran
1a4aa7f065 Add tests for link-local addresses. 2018-01-10 11:00:13 +00:00
akwizgran
f11a97631f Avoid unnecessary DB queries when starting clients. 2018-01-07 11:24:41 +00:00
akwizgran
bf953012af Prefer LAN addresses with longer prefixes. 2018-01-05 14:25:10 +00:00
akwizgran
2f049fbead Merge branch '1132-upgrade-tor-0.2.9.14' into 'master'
Upgrade Tor to 0.2.9.14, GeoIP to 2017-11-06

Closes #1132

See merge request akwizgran/briar!653
2017-12-22 13:49:35 +00:00
akwizgran
49a6f2af3a Merge branch '1129-send-on-ctrl-enter' into 'master'
send message on ctrl + enter

Closes #1129

See merge request akwizgran/briar!649
2017-12-22 11:19:31 +00:00
sbkaf
3d6c02c27c send message on ctrl + enter 2017-12-22 11:06:15 +00:00
akwizgran
a1cfc0ec1d Merge branch '545-db-benchmarks' into 'master'
Database performance tests

See merge request akwizgran/briar!652
2017-12-18 18:15:05 +00:00
akwizgran
2f584501fe Add denormalised state column to messageMetadata table. 2017-12-18 18:01:03 +00:00
akwizgran
b524cec6af Upgrade Tor to 0.2.9.14, GeoIP to 2017-11-06. 2017-12-18 15:35:25 +00:00
akwizgran
0a7b810fce Disable logging for DB performance tests only. 2017-12-15 15:43:33 +00:00
akwizgran
f7a3b0f6ca Use diamond operator. 2017-12-15 15:26:25 +00:00
akwizgran
b095dab77a Remove unused test methods. 2017-12-15 15:24:20 +00:00
Torsten Grote
b6b7ab622d Merge branch 'fix-plugin-manager-test' into 'master'
Fix test expectations

See merge request !651
2017-12-14 16:01:50 +00:00
akwizgran
55e674624a Fix test expectations. 2017-12-14 15:47:26 +00:00
akwizgran
88a799df45 Rename some classes that don't involve JDBC. 2017-12-12 16:18:25 +00:00
akwizgran
4bb726ac9a Include test name in trace file name. 2017-12-12 12:17:34 +00:00
akwizgran
5a53665e96 Add trace tests. 2017-12-11 18:08:14 +00:00
akwizgran
cf51a1e299 Add sanity check for performance comparisons. 2017-12-11 17:29:14 +00:00
akwizgran
04802cc8cd Get class name using getClass(). 2017-12-11 16:39:49 +00:00
akwizgran
d0c1be0c32 Add tests to compare benchmarks. 2017-12-11 16:10:07 +00:00
akwizgran
0b9894a0f6 More performance tests. 2017-12-11 16:10:07 +00:00
akwizgran
1a912a29f8 Use the Mann-Whitney U test to determine steady state. 2017-12-11 16:10:07 +00:00
akwizgran
596c140310 Use a single output file for all tests. 2017-12-11 16:10:07 +00:00
akwizgran
302ced1476 Measure the first run to see the extent of warm-up. 2017-12-11 16:10:06 +00:00
akwizgran
3178c16bac Reuse test database to keep runtime reasonable. 2017-12-11 16:10:06 +00:00
akwizgran
341d18656d Add run configurations for DB benchmarks. 2017-12-11 16:10:00 +00:00
akwizgran
074755c0a8 Add database benchmarks. 2017-12-11 16:09:55 +00:00
akwizgran
5d528fce74 Merge branch '1112-screen-filter-crash' into 'master'
Don't show screen filter dialog after onSaveInstanceState()

Closes #1112

See merge request !642
2017-12-07 13:06:37 +00:00
Torsten Grote
c80edc99b2 Merge branch '617-protocol-versioning' into 'master'
Protocol versioning

See merge request !646
2017-12-07 12:17:50 +00:00
akwizgran
33378d9920 Merge branch '1088-huawei-whitelisting' into 'master'
Add button for Huawei's power manager to setup wizard

Closes #1088

See merge request !633
2017-12-05 17:22:44 +00:00
akwizgran
85a6e394b9 Merge branch '1127-notification-channels' into 'master'
Use channels for all notifications

Closes #1127

See merge request !643
2017-12-05 16:48:16 +00:00
akwizgran
f2f98f28a3 Include client version in group ID derivation. 2017-12-05 16:07:17 +00:00
akwizgran
d92e042971 Include protocol version in message ID derivation. 2017-12-05 16:07:17 +00:00
akwizgran
6d6e47409f Include protocol version in group ID derivation. 2017-12-05 16:07:17 +00:00
akwizgran
0084e51263 Include protocol version in key derivation. 2017-12-05 16:07:17 +00:00
akwizgran
32e0b39771 Include protocol version in shared secret derivation. 2017-12-05 16:07:17 +00:00
akwizgran
7bb51f77ec Merge branch '545-hyper-sql' into 'master'
Add HyperSQL as an alternative DB library for testing

See merge request !619
2017-12-05 16:05:42 +00:00
akwizgran
c777a57a7d Merge branch '617-crypto-labels' into 'master'
Use namespaced labels for all crypto operations

See merge request !632
2017-12-05 16:04:35 +00:00
akwizgran
def5966767 Sort order of channel IDs affects UI of Settings app. 2017-12-05 15:41:32 +00:00
akwizgran
14b18e9d42 Merge branch '1120-crash-removing-shutdown-hook' into 'master'
Don't remove shutdown hook when closing DB

Closes #1120

See merge request !644
2017-12-05 14:43:36 +00:00
akwizgran
fcff8d92f3 Don't remove shutdown hook when closing DB. 2017-12-05 12:27:41 +00:00
akwizgran
ea0e00f4ac Use channels for all notifications. 2017-12-05 12:09:22 +00:00
Torsten Grote
f199105f6c Add button for Huawei's power manager to setup wizard 2017-12-04 17:26:19 -02:00
akwizgran
b23c0b599b Don't show screen filter dialog after onSaveInstanceState(). 2017-12-04 15:25:12 +00:00
akwizgran
0327d4f38a Merge branch '1007-samsung-transition-npe' into 'master'
Don't set scene transition for Samsung devices running Android 7.0

Closes #1007

See merge request !640
2017-12-04 14:20:28 +00:00
akwizgran
4397a45519 Add links to protocol specs (which are out of date). 2017-12-04 14:16:49 +00:00
Torsten Grote
365e159539 Don't set scene transition for Samsung devices running Android 7.0 2017-12-04 10:51:32 -02:00
akwizgran
8171dd8bc9 Merge branch 'more-lambdas' into 'master'
Replace a few runnables with lambdas

See merge request !638
2017-12-01 17:42:58 +00:00
akwizgran
c4beb60c22 Add dependency hash for HyperSQL. 2017-12-01 17:41:45 +00:00
Torsten Grote
4b88f0d9f1 Merge branch 'package-name-briar-android' into 'master'
Change package name, bump expiry date

See merge request !637
2017-12-01 16:36:47 +00:00
akwizgran
116419f505 Don't show expiry warning for release builds. 2017-12-01 16:18:47 +00:00
akwizgran
87b2624aa8 Set IS_BETA_BUILD to false. 2017-12-01 16:16:37 +00:00
akwizgran
71fe6f3148 Bump expiry date to 31 December 2018. 2017-12-01 16:11:06 +00:00
akwizgran
21df6cb809 Change package name, version number for release branch. 2017-12-01 15:59:04 +00:00
akwizgran
1f0c385a5c Merge branch '1124-notification-channel-crash' into 'master'
Use NotificationChannel for foreground service to avoid crash on Android 8.1

Closes #1124

See merge request !634
2017-12-01 15:53:05 +00:00
Torsten Grote
986ea05fb2 Use NotificationChannel for foreground service to avoid crash on Android 8.1
This also seems to address #1075 at least on an emulator
2017-12-01 13:44:51 -02:00
akwizgran
90e395506f Remove unnecessary DB_CLOSE_ON_EXIT parameter. 2017-12-01 14:13:37 +00:00
akwizgran
cf54360a93 Rename columns whose names are SQL keywords. 2017-12-01 14:13:33 +00:00
akwizgran
a5d4ea4477 Add HSQLDB as an alternative DB library. 2017-12-01 14:13:26 +00:00
akwizgran
030b52261d Replace a few runnables with lambdas. 2017-12-01 14:01:32 +00:00
akwizgran
a50e13c2e3 Merge branch 'transport-property-manager-cleanup' into 'master'
Simplify management of old transport property updates

See merge request !629
2017-11-30 17:46:15 +00:00
akwizgran
c8326103b4 Merge branch 'git-rev-parse-workaround' 2017-11-30 17:39:33 +00:00
akwizgran
0f2beee813 Use namespaced labels for transport key derivation. 2017-11-30 17:36:04 +00:00
akwizgran
d2348a4e7d Remove method that just wraps a MAC call. 2017-11-30 17:08:59 +00:00
akwizgran
cc87e6fd1f Factor out key agreement crypto from CryptoComponent. 2017-11-30 17:08:59 +00:00
akwizgran
1843aea2a7 Factor out transport crypto from CryptoComponent. 2017-11-30 17:08:59 +00:00
akwizgran
9f7021acd3 Include namespaced labels in crypto operations. 2017-11-30 17:08:56 +00:00
Torsten Grote
ddea031cbf Merge branch '1110-signature-labels' into 'master'
Don't use ClientId.toString() for signature labels

Closes #1110

See merge request !631
2017-11-30 17:03:07 +00:00
akwizgran
f0d8532f71 Specify 7 characters for Git revision. 2017-11-30 16:55:41 +00:00
akwizgran
4883d157dc Simplify management of old transport property updates. 2017-11-30 16:43:33 +00:00
akwizgran
a1bec1e927 Merge branch 'ed25519' into 'master'
Add support for Ed25519 signatures

See merge request !627
2017-11-30 16:22:04 +00:00
akwizgran
48918f4727 Bumped version numbers for beta release. 2017-11-30 13:35:43 +00:00
akwizgran
303b5bd395 Merge branch 'target-sdk-26' into 'master'
Target API version 26, upgrade support library

See merge request !626
2017-11-29 17:38:12 +00:00
akwizgran
37d4d79c64 Don't rethrow SignatureException as RuntimeException. 2017-11-29 17:29:32 +00:00
akwizgran
05bc3f6a71 Don't use ClientId.toString() for signature labels. 2017-11-29 16:57:00 +00:00
akwizgran
8b3960781a Fix a typo. 2017-11-23 17:34:40 +00:00
akwizgran
97733a52c8 Updated translations. 2017-11-23 17:03:15 +00:00
akwizgran
89dcbec599 Upgrade Gradle plugin to 3.0.1. 2017-11-23 17:01:16 +00:00
akwizgran
6497809fe1 Merge branch '1103-dont-ask-again-doze' into 'master'
Show Doze Mode Warning with Don't Ask Again Option

Closes #1103

See merge request !625
2017-11-23 16:23:39 +00:00
akwizgran
f3de4f53c5 Add ProGuard rule to keep EdDSA classes. 2017-11-23 16:18:30 +00:00
akwizgran
166fc2948c Add support for Ed25519 signatures. 2017-11-23 16:17:41 +00:00
akwizgran
9f3a63d8c4 Don't unregister receiver unless it was registered. 2017-11-22 11:37:58 +00:00
akwizgran
748fa77d94 Move doze receiver out of BriarService. 2017-11-22 11:07:28 +00:00
Torsten Grote
4ca86ee4eb Address review comments 2017-11-21 16:01:07 -02:00
Torsten Grote
ec2f372933 Remember that app entered doze mode and inform user when returning 2017-11-21 15:55:00 -02:00
Torsten Grote
4267800db2 Allow Account Creation without Doze White-listing 2017-11-21 15:55:00 -02:00
Torsten Grote
bb8cb9bcbb Show Doze Dialog only after startup and provide "don't ask again" option 2017-11-21 15:54:59 -02:00
akwizgran
d5b9e15ee1 Bump compileSdkVersion to match support library. 2017-11-21 17:33:40 +00:00
akwizgran
43ee3246f6 Remove redundant casts from findViewById. 2017-11-21 17:29:21 +00:00
akwizgran
b56724dee5 Set target SDK version to 26, upgrade support library. 2017-11-21 17:29:21 +00:00
akwizgran
92748ac872 Accept build tools license for CI. 2017-11-21 17:28:11 +00:00
akwizgran
b89686c287 Merge branch 'upgrade-gradle-witness' into 'master'
Upgrade Gradle Witness

See merge request !623
2017-11-21 17:11:06 +00:00
akwizgran
a34692630b Use testImplementation for Mockito. 2017-11-21 17:03:38 +00:00
akwizgran
735208562a Use java-library plugin for Java modules. 2017-11-21 16:35:08 +00:00
akwizgran
49826fdc56 Use new Gradle configurations for Android modules. 2017-11-21 16:35:08 +00:00
akwizgran
e8c54a609c Upgrade Gradle Witness. 2017-11-21 16:35:03 +00:00
akwizgran
ece2c51358 A few more Java 8 changes in merged code. 2017-11-21 16:21:15 +00:00
akwizgran
3ec8af4661 Merge branch 'use-java-8-language-features' into 'master'
Use java 8 language features

See merge request !621
2017-11-21 15:22:52 +00:00
Torsten Grote
77a08596fe Merge branch '764-bdf-list-dictionary-not-thread-safe' into 'master'
BdfList and BdfDictionary don't need to be thread-safe

Closes #764

See merge request !614
2017-11-21 13:00:23 +00:00
akwizgran
879f699b2b A few more lambdas. 2017-11-21 10:51:37 -02:00
akwizgran
d7383a3361 Effectively final. 2017-11-21 10:51:35 -02:00
akwizgran
a5b321a93b Multi-catch. 2017-11-21 10:49:10 -02:00
akwizgran
5fa6b0ca1c Lambdas. 2017-11-21 10:49:08 -02:00
akwizgran
27328afe3c Diamond operators. 2017-11-21 10:45:47 -02:00
Torsten Grote
2d26af1ae2 Merge branch 'java-8-language-features' into 'master'
Support Java 8 language features

See merge request !620
2017-11-21 12:09:27 +00:00
Torsten Grote
6db8f33e8f Merge branch 'log-network-usage' into 'master'
Log network usage at shutdown

See merge request !616
2017-11-21 11:45:42 +00:00
akwizgran
d6a7e6d52c Resolve merge conflicts.
# Conflicts:
#   briar-android/build.gradle
#   briar-android/src/test/java/org/briarproject/briar/android/login/SetupActivityTest.java
2017-11-21 10:27:31 +00:00
akwizgran
df99b3b666 Merge branch '1085-startup-wizard' into 'master'
Setup Wizard that asks for Doze Mode exception

Closes #1085 and #1018

See merge request !603
2017-11-21 09:40:10 +00:00
akwizgran
0f1c9f4fe2 Refactored tests for account setup and changing password. 2017-11-20 14:11:31 -02:00
Torsten Grote
5dcd5f79dc Test PasswordFragment account creation individually 2017-11-20 11:52:06 -02:00
Torsten Grote
8a81171739 Setup Wizard that asks for Doze Mode exception
Keep checking if we are whitelisted and request it if not
2017-11-20 11:52:05 -02:00
akwizgran
1c4f20f76f Merge branch 'simply-build-gradle' into 'master'
Simply bramble-androids's build.gradle

See merge request !622
2017-11-17 16:11:00 +00:00
goapunk
f84fa588f6 simply bramble-androids's build.gradle
Signed-off-by: goapunk <noobie@goapunks.net>
2017-11-17 16:43:07 +01:00
akwizgran
e30e34f342 Include java.lang.invoke classes in bootstrap classpath. 2017-11-16 15:26:05 +00:00
akwizgran
fc93ced067 Download the Android support repository for CI. 2017-11-16 12:54:57 +00:00
akwizgran
bb7df72d31 Compile against OpenJDK 6 standard library for CI. 2017-11-16 12:54:50 +00:00
akwizgran
f8425658e4 Support Java 8 language features in Java modules. 2017-11-16 11:46:35 +00:00
akwizgran
53c8cf09b6 Support Java 8 language features in Android modules. 2017-11-16 11:46:34 +00:00
akwizgran
9f29bf4949 Upgrade Gradle and Android Gradle plugin 2017-11-16 11:46:32 +00:00
akwizgran
98e2adf794 Fix Dagger setup, remove android-apt plugin. 2017-11-16 11:46:02 +00:00
Torsten Grote
2a43e0b0ed Merge branch '545-simple-db-indexes' into 'master'
Add some simple indexes to the DB

See merge request !618
2017-11-09 12:10:07 +00:00
akwizgran
773ae73820 Updated translations. 2017-11-09 12:05:21 +00:00
akwizgran
009db57bc5 Merge branch '482-delete-old-transport-property-updates' into 'master'
Delete old transport property updates

Closes #482

See merge request !617
2017-11-09 11:59:00 +00:00
akwizgran
5e98126e77 Completely remove old local updates from the database. 2017-11-09 10:58:51 +00:00
akwizgran
bd7ebfd83a Unit tests for TransportPropertyManagerImpl. 2017-11-08 16:44:26 +00:00
akwizgran
10f41ef157 Log network usage at shutdown. 2017-11-08 14:46:56 +00:00
akwizgran
1dd4960109 Transactions that delete old updates must be read-write. 2017-11-08 14:23:30 +00:00
akwizgran
75413b6c86 Delete old transport property updates.
Some of this code is only needed for backward compatibility - it can be removed when we break compatibility for 1.0.
2017-11-08 09:47:59 +00:00
akwizgran
b2180582a7 BdfList and BdfDictionary don't need to be thread-safe.
Same goes for Metadata.
2017-11-06 15:20:21 +00:00
akwizgran
8211ce7ae3 Add some simple indexes to the DB. 2017-11-03 15:06:34 +00:00
akwizgran
e6b1597fa7 Upgraded Gradle to 3.5. 2017-10-26 18:07:20 +01:00
akwizgran
8937d3cd9c Updated translations. 2017-10-24 17:01:11 +01:00
akwizgran
51f320d147 Merge branch '992-wake-lock-tag' into 'master'
Change wake lock tag

Closes #992 and #1087

See merge request !612
2017-10-24 13:36:26 +00:00
goapunk
e402a894bb Change wake lock tag
Signed-off-by: goapunk <noobie@goapunks.net>
2017-10-24 13:45:27 +02:00
Torsten Grote
9b577f1219 Merge branch 'remove-location-permission' into 'master'
Remove unused location permission

See merge request !611
2017-10-18 16:31:56 +00:00
akwizgran
220f678403 Removed unused location permission. 2017-10-18 14:05:11 +01:00
akwizgran
4173fc4daa Merge branch '1045-preference-divider' into 'master'
Don't use a custom widget to separate preference categories

Closes #1045

See merge request !609
2017-10-17 17:03:13 +00:00
Torsten Grote
c6756d2145 Merge branch 'gradle-plugin-2.3.3' into 'master'
Upgrade Gradle plugin and build tools

See merge request !610
2017-10-17 16:14:53 +00:00
akwizgran
6731f6eeb5 Added checksum for Gradle download. 2017-10-17 17:01:46 +01:00
akwizgran
6f7f8b40e3 Upgraded Gradle plugin and build tools. 2017-10-17 15:31:28 +01:00
akwizgran
1a83b2c99b Bumped version number for beta release. 2017-10-17 09:41:11 +01:00
akwizgran
f641fae1c7 Added new translations. 2017-10-16 17:10:53 +01:00
akwizgran
deb43d9872 Updated translations. 2017-10-16 17:08:07 +01:00
akwizgran
cee4e1305e Merge branch 'extend-expiry' into 'master'
Extend expiry and show a green snackbar about it once

See merge request !606
2017-10-12 17:03:26 +00:00
akwizgran
a1f989c43c Use black text for the expiry extension notice. 2017-10-12 17:51:57 +01:00
akwizgran
b67abadbac Use a setting to record whether update notice has been shown 2017-10-12 17:51:57 +01:00
Torsten Grote
8c29c85696 Extend expiry and show a green snackbar about it once 2017-10-12 17:51:57 +01:00
akwizgran
4fe4c298d7 Don't use a custom widget to separate preference categories. 2017-10-11 17:35:05 +01:00
akwizgran
13d35229d5 Merge branch '1091-reduce-polling-queries' into 'master'
Reduce number of DB queries used when polling for connections

Closes #1091

See merge request !604
2017-10-11 13:45:14 +00:00
Torsten Grote
f0137b41b6 Merge branch 'accept-sdk-license-agreement-for-ci' into 'master'
Accept build tools license agreement for CI runner

See merge request !607
2017-10-11 13:24:25 +00:00
akwizgran
b221d21903 Accept all SDK license agreements for CI runner. 2017-10-11 14:18:02 +01:00
Torsten Grote
8bac202626 Add Hindi, Finnish and Basque translations 2017-10-10 10:04:22 -03:00
Torsten Grote
973151c949 Merge branch 'report-bluetooth-and-wifi-support' into 'master'
Report Bluetooth LE and Wi-Fi Direct support in crash reports and feedback

See merge request !605
2017-10-10 12:16:29 +00:00
akwizgran
ed26ab78a5 Merge branch '158-permission-requests' into 'master'
Add permission requests for Android 6+

Closes #158

See merge request !601
2017-10-10 10:40:14 +00:00
akwizgran
8454b2d235 Code cleanup, shortened button text to help with layout. 2017-10-10 11:33:07 +01:00
akwizgran
91d0f89f60 Removed unused import. 2017-10-10 11:08:40 +01:00
akwizgran
e074672e86 Reduce DB queries for looking up transport properties. 2017-10-10 10:59:39 +01:00
akwizgran
6c1901fe5b Reduced DB queries when polling for LAN connections. 2017-10-09 15:20:03 +01:00
goapunk
49052be627 Add permission requests for Android 6+
* Add request for the camera

Signed-off-by: goapunk <noobie@goapunks.net>
2017-10-04 13:17:51 +02:00
Torsten Grote
5b5b540630 Merge branch '299-disable-bluetooth-at-shutdown' into 'master'
Disable Bluetooth at shutdown if we enabled it

See merge request !602
2017-10-03 15:38:22 +00:00
akwizgran
9993bac3a1 Disable Bluetooth at shutdown if we enabled it. 2017-10-03 15:59:07 +01:00
akwizgran
3c95988693 Merge branch '539-clear-notifications' into 'master'
Don't show dismissed notifications again when items are removed

Closes #539

See merge request !600
2017-10-02 14:46:54 +00:00
akwizgran
fc5c3b470e Merge branch 'patch-1' into 'master'
Contacts, on your side

See merge request !594
2017-10-02 13:14:00 +00:00
akwizgran
53f05a72ba Removed logging. 2017-09-29 15:31:25 +01:00
akwizgran
2c10ae7d06 Clear notifications when dismissed.
Also fixed an issue with notifications alerting again when items
were removed.
2017-09-29 15:23:27 +01:00
akwizgran
6b9010c557 Merge branch '703-create-test-data' into 'master'
Add an option to debug builds to create fake test data

Closes #703

See merge request !595
2017-09-28 10:37:03 +00:00
Torsten Grote
1bf0fdfa81 Add an option to debug builds to create fake test data 2017-09-27 13:55:29 -03:00
Torsten Grote
237759aac0 Add Simplified Chinese translation 2017-09-27 13:32:07 -03:00
akwizgran
2a141e0a97 Merge branch 'disableAaptCruncher' into 'master'
Disable PNG crunching for reproducibility

See merge request !596
2017-09-27 16:04:23 +00:00
akwizgran
d6900be68e Merge branch '1051-fix-pink' into 'master'
Fix pink navigation drawer items with current support library

Closes #1051

See merge request !598
2017-09-27 16:02:22 +00:00
Torsten Grote
a35d7c7204 Fix pink navigation drawer items with current support library 2017-09-27 12:09:06 -03:00
Torsten Grote
86287f9241 Merge branch 'spongy-castle-158' into 'master'
Upgrade Spongy Castle to 1.58

See merge request !597
2017-09-27 15:01:15 +00:00
akwizgran
0b2e3dd96f Upgrade Spongy Castle to 1.58. 2017-09-27 15:54:37 +01:00
Torsten Grote
90aa1d1ce7 Disable PNG crunching for reproducibility
This can help to prevent non-determinism introduced by the crunching
process.

More information:
e48f9f0773

With enabled and disabled crunching,
the size of the signed release APK was 17809681 bytes.

Related to #164
2017-09-27 11:35:25 -03:00
Michael Rogers
ef2286ab53 Bumped version number for beta release. 2017-09-20 14:51:10 +01:00
akwizgran
47b25f3221 Merge branch '1064-rss-date-npe' into 'master'
Fix NPE when some RSS items don't have dates and add test

Closes #1064

See merge request !591
2017-09-20 12:21:06 +00:00
Torsten Grote
c30bfa12ce Fix NPE when some RSS items don't have dates and add test 2017-09-20 09:11:06 -03:00
akwizgran
d0fc04251d Merge branch 'three-new-langs' into 'master'
Add Norwegian Bokmål, Occitan (post 1500) and Serbian

See merge request !593
2017-09-20 11:15:44 +00:00
akwizgran
dcbb41eb7a Merge branch '1069-forum-sharing-exception' into 'master'
Fix crash when sharing a forum while it was just shared with us

Closes #1069

See merge request !592
2017-09-20 11:14:20 +00:00
Allan Nordhøy
5c51259269 "Connection aborted!" no und 2017-09-19 19:39:57 +00:00
Allan Nordhøy
7eefa07052 Contact connections → contacts
by us → on your side
2017-09-19 18:56:22 +00:00
Torsten Grote
999bdf8866 Add Norwegian Bokmål, Occitan (post 1500) and Serbian 2017-09-19 14:47:39 -03:00
Torsten Grote
911c0c0fd9 Fix crash when sharing a forum while it was just shared with us 2017-09-19 14:30:57 -03:00
akwizgran
99d8cc64a6 Merge branch '1024-message-tree-npe' into 'master'
Don't add threaded messages to the UI before their parents

Closes #1024

See merge request !585
2017-09-19 15:37:58 +00:00
akwizgran
ba727d7568 Don't add threaded messages to the UI before their parents. 2017-09-19 16:31:27 +01:00
Torsten Grote
ed01048f9f Merge branch 'remove-old-bluetooth-code' into 'master'
Remove old Bluetooth code and location permission

See merge request !584
2017-09-19 14:16:13 +00:00
Torsten Grote
043ee3c58e Merge branch '1044-crash-when-setting-ringtone' into 'master'
Don't crash if the chosen ringtone can't be loaded

Closes #1044

See merge request !586
2017-09-19 13:11:44 +00:00
Torsten Grote
6e0af7deda Merge branch '1060-upgrade-tor' into 'master'
Upgrade Tor to 0.2.9.12

Closes #1060

See merge request !590
2017-09-19 12:14:55 +00:00
akwizgran
9591db2097 Upgrade Tor to 0.2.9.12.
Libevent 2.0.22-stable, OpenSSL 1.0.2l and GeoIP 2017-09-06.
2017-09-19 12:49:22 +01:00
akwizgran
329a4c64f6 Merge branch '1028-lost-reply-id' into 'master'
Keep the reply ID up to date in ThreadListActivity

Closes #1028

See merge request !587
2017-09-18 15:10:38 +00:00
Torsten Grote
79015bc5ae Merge branch '1042-catch-npe-when-getting-socket-streams' into 'master'
Catch NPE when getting socket input/output streams

Closes #1042

See merge request !589
2017-09-18 14:55:08 +00:00
akwizgran
27422ab9f9 Catch NPE when getting socket input/output streams.
Works around a bug in Android 7, fixed in 7.1.
2017-09-18 15:47:12 +01:00
Torsten Grote
abcb682498 Merge branch '1040-rss-feed-illegal-argument-exception' into 'master'
Catch IllegalArgumentException when parsing RSS feed

Closes #1040

See merge request !588
2017-09-18 14:38:22 +00:00
akwizgran
5044127c46 Catch IllegalArgumentException when parsing RSS feed. 2017-09-18 15:26:12 +01:00
akwizgran
0e4b8ca62e Keep the activity's reply ID up to date. 2017-09-18 15:13:16 +01:00
akwizgran
822017c69c Don't crash if the chosen ringtone can't be loaded. 2017-09-18 13:37:10 +01:00
akwizgran
eb6561b93d Updated translations for German, French and Russian. 2017-09-15 10:40:05 +01:00
akwizgran
eb9d0c00a8 Report Bluetooth LE and Wi-Fi Direct support. 2017-08-16 12:21:13 +01:00
Michael Rogers
d24b1884a2 Removed old Bluetooth code and the location permission it requires. 2017-08-11 12:42:47 +01:00
Michael Rogers
078534889e Bumped version number for beta release. 2017-08-04 15:16:51 +01:00
Torsten Grote
e92713006a Fix string in Spanish translation 2017-08-04 10:57:43 -03:00
akwizgran
18f43f3bc1 Merge branch '871-rss-feeds-lost' into 'master'
Fix bug where RSS feeds got lost when a fetching error occured

Closes #871

See merge request !583
2017-08-04 13:52:26 +00:00
akwizgran
a4118b40e1 Merge branch 'debug-build-alongside-beta' into 'master'
Make debug builds installable alongside official beta build

See merge request !582
2017-08-02 16:54:25 +00:00
Torsten Grote
de29fbc324 Fix bug where RSS feeds got lost when a fetching error occured 2017-08-01 15:32:51 -03:00
Torsten Grote
3197dcf9b5 Merge branch 'checked-camera-exceptions' into 'master'
Throw checked exceptions for camera errors

See merge request !580
2017-08-01 16:54:45 +00:00
akwizgran
35aad409fd Merge branch '994-notification-sound-delay' into 'master'
Always play a notification sound, if at least 2sec after last one

Closes #994

See merge request !581
2017-08-01 16:20:35 +00:00
Torsten Grote
08ce6a7331 Change app name for debug builds 2017-08-01 13:08:12 -03:00
Torsten Grote
33a0099065 Make debug builds installable alongside official beta build 2017-08-01 12:57:11 -03:00
Torsten Grote
34d20fafda Always play a notification sound, if at least 2sec after last one
This is the same behavior as Signal.
We might want to adjust the delay later on.

This is also introduces a new BriarNotificationBuilder as a first step
to clean up the Notification Manager code.
2017-08-01 12:47:11 -03:00
Michael Rogers
aafddcd0f0 Bumped version number for beta release (for real this time). 2017-08-01 16:43:47 +01:00
akwizgran
0d6983b4ef Throw checked exceptions for camera errors. 2017-08-01 15:56:20 +01:00
akwizgran
69bfb72171 Merge branch '1002-cam-get-params-npe' into 'master'
Catch RuntimeException when getting camera parameters

See merge request !579
2017-08-01 13:56:45 +00:00
Torsten Grote
1aa33ec9b2 Catch RuntimeException when getting camera parameters 2017-08-01 10:49:04 -03:00
akwizgran
6702df1e22 Merge branch '1008-qr-decoding-crash' into 'master'
Catch IllegalArgumentException when decoding QrCode

Closes #1008

See merge request !578
2017-08-01 13:36:09 +00:00
akwizgran
c1748c9a86 Bumped version number for beta release. 2017-08-01 14:32:05 +01:00
akwizgran
9df624c62a Merge branch '1009-camera-npe' into 'master'
Prevent NPE in CameraView

Closes #1009 and #997

See merge request !577
2017-08-01 13:29:33 +00:00
Torsten Grote
0ee6197d7f Catch IllegalArgumentException when decoding QrCode 2017-08-01 10:21:02 -03:00
Torsten Grote
b03a7dce3e Catch runtime exception when setting best camera parameters
Closes #997
2017-08-01 10:09:21 -03:00
Torsten Grote
6c59d7dd5f Prevent NPE in CameraView
This prevents crashes, but still might cause the camera to not show up
thus preventing the user from adding contacts.
2017-08-01 09:41:42 -03:00
934 changed files with 44305 additions and 28287 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,20 +1,31 @@
image: registry.gitlab.com/fdroid/ci-images-base:latest
cache:
paths:
- .gradle/wrapper
- .gradle/caches
before_script:
- export GRADLE_USER_HOME=$PWD/.gradle
# - export ANDROID_COMPILE_SDK=`sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' app/build.gradle`
# - echo y | android --silent update sdk --no-ui --filter android-${ANDROID_COMPILE_SDK}
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:
image: briar/reproducer:latest
script:
- cd /opt/briar-reproducer
- ./reproduce.py ${CI_COMMIT_REF_NAME}
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

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.H2DatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<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

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.HyperSqlDatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<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,104 +1,121 @@
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 23
buildToolsVersion "23.0.3"
compileSdkVersion 27
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 14
targetSdkVersion 22
versionCode 14
versionName "0.14"
targetSdkVersion 26
versionCode 10011
versionName "1.0.11"
consumerProguardFiles 'proguard-rules.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
configurations {
tor
}
dependencies {
compile project(':bramble-core')
compile fileTree(dir: 'libs', include: '*.jar')
provided 'javax.annotation:jsr250-api:1.0'
implementation project(path: ':bramble-core', configuration: 'default')
implementation 'org.briarproject:jtorctl:0.3'
tor 'org.briarproject:tor-android:0.2.9.15@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
}
def torBinaryDir = 'src/main/res/raw'
task downloadTorGeoIp(type: Download) {
src 'https://briarproject.org/build/geoip-2017-05-02.zip'
dest "$torBinaryDir/geoip.zip"
onlyIfNewer true
}
task downloadTorBinaryArm(type: Download) {
src 'https://briarproject.org/build/tor-0.2.9.11-arm.zip'
dest "$torBinaryDir/tor_arm.zip"
onlyIfNewer true
}
task downloadTorBinaryArmPie(type: Download) {
src 'https://briarproject.org/build/tor-0.2.9.11-arm-pie.zip'
dest "$torBinaryDir/tor_arm_pie.zip"
onlyIfNewer true
}
task downloadTorBinaryX86(type: Download) {
src 'https://briarproject.org/build/tor-0.2.9.11-x86.zip'
dest "$torBinaryDir/tor_x86.zip"
onlyIfNewer true
}
task downloadTorBinaryX86Pie(type: Download) {
src 'https://briarproject.org/build/tor-0.2.9.11-x86-pie.zip'
dest "$torBinaryDir/tor_x86_pie.zip"
onlyIfNewer true
}
task verifyTorGeoIp(type: Verify, dependsOn: 'downloadTorGeoIp') {
src "$torBinaryDir/geoip.zip"
algorithm 'SHA-256'
checksum '51f4d1272fb867e1f3b36b67a584e2a33c40b40f62305457d799fd399cd77c9b'
}
task verifyTorBinaryArm(type: Verify, dependsOn: 'downloadTorBinaryArm') {
src "$torBinaryDir/tor_arm.zip"
algorithm 'SHA-256'
checksum '1da6008663a8ad98b349e62acbbf42c379f65ec504fa467cb119c187cd5a4c6b'
}
task verifyTorBinaryArmPie(type: Verify, dependsOn: 'downloadTorBinaryArmPie') {
src "$torBinaryDir/tor_arm_pie.zip"
algorithm 'SHA-256'
checksum 'eb061f880829e05f104690ac744848133f2dacef04759d425a2cff0df32c271e'
}
task verifyTorBinaryX86(type: Verify, dependsOn: 'downloadTorBinaryX86') {
src "$torBinaryDir/tor_x86.zip"
algorithm 'SHA-256'
checksum 'f5308aff8303daca082f82227d02b51ddedba4ab1d1420739ada0427ae5dbb41'
}
task verifyTorBinaryX86Pie(type: Verify, dependsOn: 'downloadTorBinaryX86Pie') {
src "$torBinaryDir/tor_x86_pie.zip"
algorithm 'SHA-256'
checksum '889a6c81ac73d05d35ed610ca5a913cee44d333e4ae1749c2a107f2f7dd8197b'
dependencyVerification {
verify = [
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86',
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550',
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9',
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.briarproject:tor-android:0.2.9.15:tor-android-0.2.9.15.zip:34a6474ee219ffa52e0f3393e917dda6ed03d320b02247d4fa5075aa4094ee6d',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10',
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040',
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
]
}
project.afterEvaluate {
preBuild.dependsOn {
[
'verifyTorGeoIp',
'verifyTorBinaryArm',
'verifyTorBinaryArmPie',
'verifyTorBinaryX86',
'verifyTorBinaryX86Pie'
]
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
}
}

View File

@@ -8,6 +8,10 @@
-dontwarn dagger.**
-dontnote dagger.**
-keep class net.i2p.crypto.eddsa.** { *; }
-keep class org.whispersystems.curve25519.** { *; }
-dontwarn sun.misc.Unsafe
-dontnote com.google.common.**

View File

@@ -11,8 +11,6 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Since API 23, this is needed to add contacts via Bluetooth -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="false"

View File

@@ -1,12 +1,10 @@
package org.briarproject.bramble;
import org.briarproject.bramble.plugin.AndroidPluginModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module;
@Module(includes = {
AndroidPluginModule.class,
AndroidSystemModule.class
})
public class BrambleAndroidModule {

View File

@@ -1,65 +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.plugin.droidtooth.DroidtoothPluginFactory;
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 javax.net.SocketFactory;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidPluginModule {
@Provides
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
AndroidExecutor androidExecutor, SecureRandom random,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Application app, LocationUtils locationUtils, DevReporter reporter,
EventBus eventBus) {
Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
androidExecutor, appContext, random, backoffFactory);
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
locationUtils, reporter, eventBus, torSocketFactory,
backoffFactory);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
backoffFactory, appContext);
final 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

@@ -0,0 +1,210 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.Closeable;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
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
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG =
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
private final AndroidExecutor androidExecutor;
private final Context appContext;
private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null;
// Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null;
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Backoff backoff,
DuplexPluginCallback callback, int maxLatency) {
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency);
this.androidExecutor = androidExecutor;
this.appContext = appContext;
}
@Override
public void start() throws PluginException {
super.start();
// Listen for changes to the Bluetooth state
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
receiver = new BluetoothStateReceiver();
appContext.registerReceiver(receiver, filter);
}
@Override
public void stop() {
super.stop();
if (receiver != null) appContext.unregisterReceiver(receiver);
}
@Override
void initialiseAdapter() throws IOException {
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
// with a message queue, so submit it to the AndroidExecutor
try {
adapter = androidExecutor.runOnBackgroundThread(
BluetoothAdapter::getDefaultAdapter).get();
} catch (InterruptedException | ExecutionException e) {
throw new IOException(e);
}
if (adapter == null)
throw new IOException("Bluetooth is not supported");
}
@Override
boolean isAdapterEnabled() {
return adapter != null && adapter.isEnabled();
}
@Override
void enableAdapter() {
if (adapter != null && !adapter.isEnabled()) {
if (adapter.enable()) {
LOG.info("Enabling Bluetooth");
wasEnabledByUs = true;
} else {
LOG.info("Could not enable Bluetooth");
}
}
}
@Override
void disableAdapterIfEnabledByUs() {
if (isAdapterEnabled() && wasEnabledByUs) {
if (adapter.disable()) LOG.info("Disabling Bluetooth");
else LOG.info("Could not disable Bluetooth");
wasEnabledByUs = false;
}
}
@Override
void setEnabledByUs() {
wasEnabledByUs = true;
}
@Override
@Nullable
String getBluetoothAddress() {
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
return address.isEmpty() ? null : address;
}
@Override
BluetoothServerSocket openServerSocket(String uuid) throws IOException {
return adapter.listenUsingInsecureRfcommWithServiceRecord(
"RFCOMM", UUID.fromString(uuid));
}
@Override
void tryToClose(@Nullable BluetoothServerSocket ss) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
@Override
DuplexTransportConnection acceptConnection(BluetoothServerSocket ss)
throws IOException {
return wrapSocket(ss.accept());
}
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
return new AndroidBluetoothTransportConnection(this,
connectionLimiter, s);
}
@Override
boolean isValidAddress(String address) {
return BluetoothAdapter.checkBluetoothAddress(address);
}
@Override
DuplexTransportConnection connectTo(String address, String uuid)
throws IOException {
BluetoothDevice d = adapter.getRemoteDevice(address);
UUID u = UUID.fromString(uuid);
BluetoothSocket s = null;
try {
s = d.createInsecureRfcommSocketToServiceRecord(u);
s.connect();
return wrapSocket(s);
} catch (IOException e) {
tryToClose(s);
throw e;
}
}
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
int state = intent.getIntExtra(EXTRA_STATE, 0);
if (state == STATE_ON) onAdapterEnabled();
else if (state == STATE_OFF) onAdapterDisabled();
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
if (scanMode == SCAN_MODE_NONE) {
LOG.info("Scan mode: None");
} else if (scanMode == SCAN_MODE_CONNECTABLE) {
LOG.info("Scan mode: Connectable");
} else if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
LOG.info("Scan mode: Discoverable");
}
}
}
}

View File

@@ -1,7 +1,8 @@
package org.briarproject.bramble.plugin.droidtooth;
package org.briarproject.bramble.plugin.bluetooth;
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;
@@ -20,7 +21,7 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
@Immutable
@NotNullByDefault
public class DroidtoothPluginFactory implements DuplexPluginFactory {
public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
@@ -31,15 +32,18 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
private final AndroidExecutor androidExecutor;
private final Context appContext;
private final SecureRandom secureRandom;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
public DroidtoothPluginFactory(Executor ioExecutor,
public AndroidBluetoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, BackoffFactory backoffFactory) {
SecureRandom secureRandom, EventBus eventBus,
BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor;
this.appContext = appContext;
this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
}
@@ -55,9 +59,14 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
@Override
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl();
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext,
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, ioExecutor, androidExecutor, appContext,
secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin);
return plugin;
}
}

View File

@@ -1,4 +1,4 @@
package org.briarproject.bramble.plugin.droidtooth;
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
@@ -11,12 +11,17 @@ import java.io.InputStream;
import java.io.OutputStream;
@NotNullByDefault
class DroidtoothTransportConnection extends AbstractDuplexTransportConnection {
class AndroidBluetoothTransportConnection
extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionManager;
private final BluetoothSocket socket;
DroidtoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionManager,
BluetoothSocket socket) {
super(plugin);
this.connectionManager = connectionManager;
this.socket = socket;
}
@@ -32,6 +37,10 @@ class DroidtoothTransportConnection extends AbstractDuplexTransportConnection {
@Override
protected void closeConnection(boolean exception) throws IOException {
socket.close();
try {
socket.close();
} finally {
connectionManager.connectionClosed(this);
}
}
}

View File

@@ -1,682 +0,0 @@
package org.briarproject.bramble.plugin.droidtooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.PseudoRandom;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginException;
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.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class DroidtoothPlugin implements DuplexPlugin {
private static final Logger LOG =
Logger.getLogger(DroidtoothPlugin.class.getName());
private static final String FOUND =
"android.bluetooth.device.action.FOUND";
private static final String DISCOVERY_FINISHED =
"android.bluetooth.adapter.action.DISCOVERY_FINISHED";
private final Executor ioExecutor;
private final AndroidExecutor androidExecutor;
private final Context appContext;
private final SecureRandom secureRandom;
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final int maxLatency;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false;
private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null;
private volatile BluetoothServerSocket socket = null;
// Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null;
DroidtoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Backoff backoff,
DuplexPluginCallback callback, int maxLatency) {
this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor;
this.appContext = appContext;
this.secureRandom = secureRandom;
this.backoff = backoff;
this.callback = callback;
this.maxLatency = maxLatency;
}
@Override
public TransportId getId() {
return ID;
}
@Override
public int getMaxLatency() {
return maxLatency;
}
@Override
public int getMaxIdleTime() {
// Bluetooth detects dead connections so we don't need keepalives
return Integer.MAX_VALUE;
}
@Override
public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException();
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
// with a message queue, so submit it to the AndroidExecutor
try {
adapter = androidExecutor.runOnBackgroundThread(
new Callable<BluetoothAdapter>() {
@Override
public BluetoothAdapter call() throws Exception {
return BluetoothAdapter.getDefaultAdapter();
}
}).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.warning("Interrupted while getting BluetoothAdapter");
throw new PluginException(e);
} catch (ExecutionException e) {
throw new PluginException(e);
}
if (adapter == null) {
LOG.info("Bluetooth is not supported");
throw new PluginException();
}
running = true;
// Listen for changes to the Bluetooth state
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
receiver = new BluetoothStateReceiver();
appContext.registerReceiver(receiver, filter);
// If Bluetooth is enabled, bind a socket
if (adapter.isEnabled()) {
bind();
} else {
// Enable Bluetooth if settings allow
if (callback.getSettings().getBoolean(PREF_BT_ENABLE, false)) {
wasEnabledByUs = true;
if (adapter.enable()) LOG.info("Enabling Bluetooth");
else LOG.info("Could not enable Bluetooth");
} else {
LOG.info("Not enabling Bluetooth");
}
}
}
private void bind() {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
if (!isRunning()) return;
String address = AndroidUtils.getBluetoothAddress(appContext,
adapter);
if (LOG.isLoggable(INFO))
LOG.info("Local address " + scrubMacAddress(address));
if (!StringUtils.isNullOrEmpty(address)) {
// Advertise the Bluetooth address to contacts
TransportProperties p = new TransportProperties();
p.put(PROP_ADDRESS, address);
callback.mergeLocalProperties(p);
}
// Bind a server socket to accept connections from contacts
BluetoothServerSocket ss;
try {
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
"RFCOMM", getUuid());
} catch (IOException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
return;
}
if (!isRunning()) {
tryToClose(ss);
return;
}
LOG.info("Socket bound");
socket = ss;
backoff.reset();
callback.transportEnabled();
acceptContactConnections();
}
});
}
private UUID getUuid() {
String uuid = callback.getLocalProperties().get(PROP_UUID);
if (uuid == null) {
byte[] random = new byte[UUID_BYTES];
secureRandom.nextBytes(random);
uuid = UUID.nameUUIDFromBytes(random).toString();
TransportProperties p = new TransportProperties();
p.put(PROP_UUID, uuid);
callback.mergeLocalProperties(p);
}
return UUID.fromString(uuid);
}
private void tryToClose(@Nullable BluetoothServerSocket ss) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
callback.transportDisabled();
}
}
private void acceptContactConnections() {
while (isRunning()) {
BluetoothSocket s;
try {
s = socket.accept();
} catch (IOException e) {
// This is expected when the socket is closed
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
return;
}
if (LOG.isLoggable(INFO)) {
String address = s.getRemoteDevice().getAddress();
LOG.info("Connection from " + scrubMacAddress(address));
}
backoff.reset();
callback.incomingConnectionCreated(wrapSocket(s));
}
}
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
return new DroidtoothTransportConnection(this, s);
}
@Override
public void stop() {
running = false;
if (receiver != null) appContext.unregisterReceiver(receiver);
tryToClose(socket);
// Disable Bluetooth if we enabled it and it's still enabled
if (wasEnabledByUs && adapter.isEnabled()) {
if (adapter.disable()) LOG.info("Disabling Bluetooth");
else LOG.info("Could not disable Bluetooth");
}
}
@Override
public boolean isRunning() {
return running && adapter != null && adapter.isEnabled();
}
@Override
public boolean shouldPoll() {
return true;
}
@Override
public int getPollingInterval() {
return backoff.getPollingInterval();
}
@Override
public void poll(Collection<ContactId> connected) {
if (!isRunning()) return;
backoff.increment();
// Try to connect to known devices in parallel
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
final ContactId c = e.getKey();
if (connected.contains(c)) continue;
final String address = e.getValue().get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
final String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(new Runnable() {
@Override
public void run() {
if (!running) return;
BluetoothSocket s = connect(address, uuid);
if (s != null) {
backoff.reset();
callback.outgoingConnectionCreated(c, wrapSocket(s));
}
}
});
}
}
@Nullable
private BluetoothSocket connect(String address, String uuid) {
// Validate the address
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
if (LOG.isLoggable(WARNING))
// not scrubbing here to be able to figure out the problem
LOG.warning("Invalid address " + address);
return null;
}
// Validate the UUID
UUID u;
try {
u = UUID.fromString(uuid);
} catch (IllegalArgumentException e) {
if (LOG.isLoggable(WARNING)) LOG.warning("Invalid UUID " + uuid);
return null;
}
// Try to connect
BluetoothDevice d = adapter.getRemoteDevice(address);
BluetoothSocket s = null;
try {
s = d.createInsecureRfcommSocketToServiceRecord(u);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
s.connect();
if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubMacAddress(address));
return s;
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Failed to connect to " + scrubMacAddress(address)
+ ": " + e);
}
tryToClose(s);
return null;
}
}
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
@Override
public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null;
TransportProperties p = callback.getRemoteProperties().get(c);
if (p == null) return null;
String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null;
String uuid = p.get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) return null;
BluetoothSocket s = connect(address, uuid);
if (s == null) return null;
return new DroidtoothTransportConnection(this, s);
}
@Override
public boolean supportsInvitations() {
return true;
}
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) {
if (!isRunning()) return null;
// Use the invitation codes to generate the UUID
byte[] b = r.nextBytes(UUID_BYTES);
UUID uuid = UUID.nameUUIDFromBytes(b);
if (LOG.isLoggable(INFO)) LOG.info("Invitation UUID " + uuid);
// Bind a server socket for receiving invitation connections
BluetoothServerSocket ss;
try {
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
"RFCOMM", uuid);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
// Create the background tasks
CompletionService<BluetoothSocket> complete =
new ExecutorCompletionService<>(ioExecutor);
List<Future<BluetoothSocket>> futures = new ArrayList<>();
if (alice) {
// Return the first connected socket
futures.add(complete.submit(new ListeningTask(ss)));
futures.add(complete.submit(new DiscoveryTask(uuid.toString())));
} else {
// Return the first socket with readable data
futures.add(complete.submit(new ReadableTask(
new ListeningTask(ss))));
futures.add(complete.submit(new ReadableTask(
new DiscoveryTask(uuid.toString()))));
}
BluetoothSocket chosen = null;
try {
Future<BluetoothSocket> f = complete.poll(timeout, MILLISECONDS);
if (f == null) return null; // No task completed within the timeout
chosen = f.get();
return new DroidtoothTransportConnection(this, chosen);
} catch (InterruptedException e) {
LOG.info("Interrupted while exchanging invitations");
Thread.currentThread().interrupt();
return null;
} catch (ExecutionException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
} finally {
// Closing the socket will terminate the listener task
tryToClose(ss);
closeSockets(futures, chosen);
}
}
private void closeSockets(final List<Future<BluetoothSocket>> futures,
@Nullable final BluetoothSocket chosen) {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
for (Future<BluetoothSocket> f : futures) {
try {
if (f.cancel(true)) {
LOG.info("Cancelled task");
} else {
BluetoothSocket s = f.get();
if (s != null && s != chosen) {
LOG.info("Closing unwanted socket");
s.close();
}
}
} catch (InterruptedException e) {
LOG.info("Interrupted while closing sockets");
return;
} catch (ExecutionException | IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
}
}
}
});
}
@Override
public boolean supportsKeyAgreement() {
return true;
}
@Override
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
if (!isRunning()) return null;
// There's no point listening if we can't discover our own address
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
if (address.isEmpty()) return null;
// No truncation necessary because COMMIT_LENGTH = 16
UUID uuid = UUID.nameUUIDFromBytes(commitment);
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
// Bind a server socket for receiving invitation connections
BluetoothServerSocket ss;
try {
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
"RFCOMM", uuid);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
BdfList descriptor = new BdfList();
descriptor.add(TRANSPORT_ID_BLUETOOTH);
descriptor.add(StringUtils.macToBytes(address));
return new BluetoothKeyAgreementListener(descriptor, ss);
}
@Override
public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, BdfList descriptor, long timeout) {
if (!isRunning()) return null;
String address;
try {
address = parseAddress(descriptor);
} catch (FormatException e) {
LOG.info("Invalid address in key agreement descriptor");
return null;
}
// No truncation necessary because COMMIT_LENGTH = 16
UUID uuid = UUID.nameUUIDFromBytes(commitment);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to key agreement UUID " + uuid);
BluetoothSocket s = connect(address, uuid.toString());
if (s == null) return null;
return new DroidtoothTransportConnection(this, s);
}
private String parseAddress(BdfList descriptor) throws FormatException {
byte[] mac = descriptor.getRaw(1);
if (mac.length != 6) throw new FormatException();
return StringUtils.macToString(mac);
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
int state = intent.getIntExtra(EXTRA_STATE, 0);
if (state == STATE_ON) {
LOG.info("Bluetooth enabled");
bind();
} else if (state == STATE_OFF) {
LOG.info("Bluetooth disabled");
tryToClose(socket);
}
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
if (scanMode == SCAN_MODE_NONE) {
LOG.info("Scan mode: None");
} else if (scanMode == SCAN_MODE_CONNECTABLE) {
LOG.info("Scan mode: Connectable");
} else if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
LOG.info("Scan mode: Discoverable");
}
}
}
private class DiscoveryTask implements Callable<BluetoothSocket> {
private final String uuid;
private DiscoveryTask(String uuid) {
this.uuid = uuid;
}
@Override
public BluetoothSocket call() throws Exception {
// Repeat discovery until we connect or get interrupted
while (true) {
// Discover nearby devices
LOG.info("Discovering nearby devices");
List<String> addresses = discoverDevices();
if (addresses.isEmpty()) {
LOG.info("No devices discovered");
continue;
}
// Connect to any device with the right UUID
for (String address : addresses) {
BluetoothSocket s = connect(address, uuid);
if (s != null) {
LOG.info("Outgoing connection");
return s;
}
}
}
}
private List<String> discoverDevices() throws InterruptedException {
IntentFilter filter = new IntentFilter();
filter.addAction(FOUND);
filter.addAction(DISCOVERY_FINISHED);
DiscoveryReceiver disco = new DiscoveryReceiver();
appContext.registerReceiver(disco, filter);
LOG.info("Starting discovery");
adapter.startDiscovery();
return disco.waitForAddresses();
}
}
private static class DiscoveryReceiver extends BroadcastReceiver {
private final CountDownLatch finished = new CountDownLatch(1);
private final List<String> addresses = new CopyOnWriteArrayList<>();
@Override
public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
if (action.equals(DISCOVERY_FINISHED)) {
LOG.info("Discovery finished");
ctx.unregisterReceiver(this);
finished.countDown();
} else if (action.equals(FOUND)) {
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
if (LOG.isLoggable(INFO)) {
LOG.info("Discovered device: " +
scrubMacAddress(d.getAddress()));
}
addresses.add(d.getAddress());
}
}
private List<String> waitForAddresses() throws InterruptedException {
finished.await();
List<String> shuffled = new ArrayList<>(addresses);
Collections.shuffle(shuffled);
return shuffled;
}
}
private static class ListeningTask implements Callable<BluetoothSocket> {
private final BluetoothServerSocket serverSocket;
private ListeningTask(BluetoothServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
@Override
public BluetoothSocket call() throws IOException {
BluetoothSocket s = serverSocket.accept();
LOG.info("Incoming connection");
return s;
}
}
private static class ReadableTask implements Callable<BluetoothSocket> {
private final Callable<BluetoothSocket> connectionTask;
private ReadableTask(Callable<BluetoothSocket> connectionTask) {
this.connectionTask = connectionTask;
}
@Override
public BluetoothSocket call() throws Exception {
BluetoothSocket s = connectionTask.call();
InputStream in = s.getInputStream();
while (in.available() == 0) {
LOG.info("Waiting for data");
Thread.sleep(1000);
}
LOG.info("Data available");
return s;
}
}
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
private final BluetoothServerSocket ss;
private BluetoothKeyAgreementListener(BdfList descriptor,
BluetoothServerSocket ss) {
super(descriptor);
this.ss = ss;
}
@Override
public Callable<KeyAgreementConnection> listen() {
return new Callable<KeyAgreementConnection>() {
@Override
public KeyAgreementConnection call() throws IOException {
BluetoothSocket s = ss.accept();
if (LOG.isLoggable(INFO))
LOG.info(ID.getString() + ": Incoming connection");
return new KeyAgreementConnection(
new DroidtoothTransportConnection(
DroidtoothPlugin.this, s), ID);
}
};
}
@Override
public void close() {
try {
ss.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
}
}

View File

@@ -5,37 +5,84 @@ 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.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.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.WIFI_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
@NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin {
// See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private static final int WIFI_AP_STATE_ENABLED = 13;
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());
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 ScheduledExecutorService scheduler;
private final Context appContext;
private final ConnectivityManager connectivityManager;
@Nullable
private final WifiManager wifiManager;
@Nullable
private volatile BroadcastReceiver networkStateReceiver = null;
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff,
Context appContext, DuplexPluginCallback callback, int maxLatency,
int maxIdleTime) {
AndroidLanTcpPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Backoff backoff, Context appContext, DuplexPluginCallback callback,
int maxLatency, int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
this.scheduler = scheduler;
this.appContext = appContext;
ConnectivityManager connectivityManager = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager == null) throw new AssertionError();
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault();
}
@Override
@@ -44,7 +91,9 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
running = true;
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
IntentFilter filter = new IntentFilter();
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
appContext.registerReceiver(networkStateReceiver, filter);
}
@@ -56,21 +105,92 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
tryToClose(socket);
}
@Override
protected Socket createSocket() throws IOException {
return socketFactory.createSocket();
}
@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();
}
private class NetworkStateReceiver extends BroadcastReceiver {
@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();
if (isApEnabledEvent(i)) {
// The state change may be broadcast before the AP address is
// visible, so delay handling the event
scheduler.schedule(this::handleConnectivityChange, 1, SECONDS);
} else {
LOG.info("Not connected to Wi-Fi");
tryToClose(socket);
handleConnectivityChange();
}
}
private void handleConnectivityChange() {
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();
}
}
private boolean isApEnabledEvent(Intent i) {
return WIFI_AP_STATE_CHANGED_ACTION.equals(i.getAction()) &&
i.getIntExtra(EXTRA_WIFI_STATE, 0) == WIFI_AP_STATE_ENABLED;
}
}
}

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.concurrent.Immutable;
@@ -27,12 +28,15 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final BackoffFactory backoffFactory;
private final Context appContext;
public AndroidLanTcpPluginFactory(Executor ioExecutor,
BackoffFactory backoffFactory, Context appContext) {
ScheduledExecutorService scheduler, BackoffFactory backoffFactory,
Context appContext) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.backoffFactory = backoffFactory;
this.appContext = appContext;
}
@@ -51,7 +55,7 @@ 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);
return new AndroidLanTcpPlugin(ioExecutor, scheduler, backoff,
appContext, callback, MAX_LATENCY, MAX_IDLE_TIME);
}
}

View File

@@ -10,14 +10,13 @@ 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.crypto.PseudoRandom;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
@@ -32,12 +31,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;
@@ -52,14 +51,16 @@ import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
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.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
@@ -70,10 +71,14 @@ 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;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
@@ -85,27 +90,32 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_
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
@ParametersNotNullByDefault
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final String PROP_ONION = "onion";
private static final String[] EVENTS = {
"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 Executor ioExecutor, connectionStatusExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
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;
@@ -113,7 +123,9 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile;
private final PowerManager.WakeLock wakeLock;
private final RenewableWakeLock wakeLock;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false;
@@ -122,16 +134,17 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private volatile TorControlConnection controlConnection = null;
private volatile BroadcastReceiver networkStateReceiver = null;
TorPlugin(Executor ioExecutor, Context appContext,
LocationUtils locationUtils, DevReporter reporter,
SocketFactory torSocketFactory, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
int maxLatency, int maxIdleTime) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.torSocketFactory = torSocketFactory;
this.clock = clock;
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
@@ -147,10 +160,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;
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "TorPlugin");
wakeLock.setReferenceCounted(false);
// 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
@@ -173,18 +189,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());
@@ -203,11 +211,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (LOG.isLoggable(INFO)) {
Scanner stdout = new Scanner(torProcess.getInputStream());
Scanner stderr = new Scanner(torProcess.getErrorStream());
while (stdout.hasNextLine() || stderr.hasNextLine()){
if(stdout.hasNextLine()) {
while (stdout.hasNextLine() || stderr.hasNextLine()) {
if (stdout.hasNextLine()) {
LOG.info(stdout.nextLine());
}
if(stderr.hasNextLine()){
if (stderr.hasNextLine()) {
LOG.info(stderr.nextLine());
}
}
@@ -223,11 +231,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();
@@ -256,7 +269,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
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);
// Bind a server socket to receive incoming hidden service connections
bind();
@@ -317,7 +334,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);
}
@@ -331,7 +348,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);
}
}
@@ -339,7 +356,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);
}
}
@@ -348,7 +365,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());
}
}
@@ -368,58 +385,38 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
private void sendDevReports() {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
// TODO: Trigger this with a TransportEnabledEvent
File reportDir = AndroidUtils.getReportDir(appContext);
reporter.sendReports(reportDir);
}
});
}
private void bind() {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
// If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get(PREF_TOR_PORT);
int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString);
// Bind a server socket to receive connections from Tor
ServerSocket ss = null;
try {
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);
tryToClose(ss);
return;
}
if (!running) {
tryToClose(ss);
return;
}
socket = ss;
// Store the port number
final String localPort = String.valueOf(ss.getLocalPort());
Settings s = new Settings();
s.put(PREF_TOR_PORT, localPort);
callback.mergeSettings(s);
// Create a hidden service if necessary
ioExecutor.execute(new Runnable() {
@Override
public void run() {
publishHiddenService(localPort);
}
});
backoff.reset();
// Accept incoming hidden service connections from Tor
acceptContactConnections(ss);
ioExecutor.execute(() -> {
// If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get(PREF_TOR_PORT);
int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString);
// Bind a server socket to receive connections from Tor
ServerSocket ss = null;
try {
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));
} catch (IOException e) {
logException(LOG, WARNING, e);
tryToClose(ss);
return;
}
if (!running) {
tryToClose(ss);
return;
}
socket = ss;
// Store the port number
String localPort = String.valueOf(ss.getLocalPort());
Settings s = new Settings();
s.put(PREF_TOR_PORT, localPort);
callback.mergeSettings(s);
// Create a hidden service if necessary
ioExecutor.execute(() -> publishHiddenService(localPort));
backoff.reset();
// Accept incoming hidden service connections from Tor
acceptContactConnections(ss);
});
}
@@ -427,7 +424,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();
}
@@ -446,7 +443,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)) {
@@ -502,7 +499,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
@Override
public void stop() throws PluginException {
public void stop() {
running = false;
tryToClose(socket);
if (networkStateReceiver != null)
@@ -514,7 +511,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();
@@ -536,32 +533,27 @@ 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();
// TODO: Pass properties to connectAndCallBack()
for (ContactId c : callback.getRemoteProperties().keySet())
if (!connected.contains(c)) connectAndCallBack(c);
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
connectAndCallBack(e.getKey(), e.getValue());
}
}
private void connectAndCallBack(final ContactId c) {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
DuplexTransportConnection d = createConnection(c);
if (d != null) {
backoff.reset();
callback.outgoingConnectionCreated(c, d);
}
private void connectAndCallBack(ContactId c, TransportProperties p) {
ioExecutor.execute(() -> {
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
callback.outgoingConnectionCreated(c, d);
}
});
}
@Override
public DuplexTransportConnection createConnection(ContactId c) {
public DuplexTransportConnection createConnection(TransportProperties p) {
if (!isRunning()) return null;
TransportProperties p = callback.getRemoteProperties().get(c);
if (p == null) return null;
String onion = p.get(PROP_ONION);
if (StringUtils.isNullOrEmpty(onion)) return null;
if (!ONION.matcher(onion).matches()) {
@@ -589,17 +581,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
@Override
public boolean supportsInvitations() {
return false;
}
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) {
throw new UnsupportedOperationException();
}
@Override
public boolean supportsKeyAgreement() {
return false;
@@ -612,7 +593,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, BdfList descriptor, long timeout) {
byte[] commitment, BdfList descriptor) {
throw new UnsupportedOperationException();
}
@@ -622,10 +603,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();
}
}
@@ -636,6 +614,8 @@ 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
}
@Override
@@ -652,10 +632,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();
}
}
@@ -665,22 +642,6 @@ 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, String path) {
stopWatching();
latch.countDown();
}
}
@Override
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
@@ -693,60 +654,65 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
private void updateConnectionStatus() {
ioExecutor.execute(new Runnable() {
@Override
public void run() {
if (!running) return;
connectionStatusExecutor.execute(() -> {
if (!running) return;
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry();
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
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);
}
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);
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) {
logException(LOG, WARNING, 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;
if (CONNECTIVITY_ACTION.equals(i.getAction())) {
LOG.info("Detected connectivity change");
updateConnectionStatus();
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();
}
}
}
@@ -769,7 +735,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

@@ -12,11 +12,12 @@ 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;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
@@ -36,24 +37,27 @@ public class TorPluginFactory implements DuplexPluginFactory {
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final LocationUtils locationUtils;
private final DevReporter reporter;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor, Context appContext,
LocationUtils locationUtils, DevReporter reporter,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory) {
public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.clock = clock;
}
@Override
@@ -89,9 +93,9 @@ public class TorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, appContext, locationUtils,
reporter, torSocketFactory, backoff, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, torSocketFactory, clock, backoff, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import org.briarproject.bramble.util.IoUtils;
import java.io.IOException;
import java.io.InputStream;
@@ -21,12 +22,12 @@ class TorTransportConnection extends AbstractDuplexTransportConnection {
@Override
protected InputStream getInputStream() throws IOException {
return socket.getInputStream();
return IoUtils.getInputStream(socket);
}
@Override
protected OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
return IoUtils.getOutputStream(socket);
}
@Override

View File

@@ -27,14 +27,11 @@ class AndroidExecutorImpl implements AndroidExecutor {
@Inject
AndroidExecutorImpl(Application app) {
uiHandler = new Handler(app.getApplicationContext().getMainLooper());
loop = new Runnable() {
@Override
public void run() {
Looper.prepare();
backgroundHandler = new Handler();
startLatch.countDown();
Looper.loop();
}
loop = () -> {
Looper.prepare();
backgroundHandler = new Handler();
startLatch.countDown();
Looper.loop();
};
}

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,7 +1,9 @@
package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.provider.Settings;
@@ -10,11 +12,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 +41,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,17 +58,28 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
public static void deleteAppData(Context ctx) {
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children != null) {
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File child : children) {
if (!child.getName().equals("lib"))
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
new File(dataDir, "cache").mkdir();
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
public static File getReportDir(Context ctx) {

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

@@ -1,30 +1,46 @@
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness'
dependencies {
compile "com.google.dagger:dagger:2.0.2"
compile 'com.google.dagger:dagger-compiler:2.0.2'
compile 'com.google.code.findbugs:jsr305:3.0.2'
implementation "com.google.dagger:dagger:2.0.2"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
testCompile 'junit:junit:4.12'
testCompile "org.jmock:jmock:2.8.2"
testCompile "org.jmock:jmock-junit4:2.8.2"
testCompile "org.jmock:jmock-legacy:2.8.2"
testCompile "org.hamcrest:hamcrest-library:1.3"
testCompile "org.hamcrest:hamcrest-core:1.3"
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"
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
dependencyVerification {
verify = [
'com.google.dagger:dagger:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger-compiler:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.code.findbugs:jsr305:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'com.google.dagger:dagger-producers:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.guava:guava:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}

View File

@@ -0,0 +1,101 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
public class Multiset<T> {
private final Map<T, Integer> map = new HashMap<>();
private int total = 0;
/**
* Returns how many items the multiset contains in total.
*/
public int getTotal() {
return total;
}
/**
* Returns how many unique items the multiset contains.
*/
public int getUnique() {
return map.size();
}
/**
* Returns how many of the given item the multiset contains.
*/
public int getCount(T t) {
Integer count = map.get(t);
return count == null ? 0 : count;
}
/**
* Adds the given item to the multiset and returns how many of the item
* the multiset now contains.
*/
public int add(T t) {
Integer count = map.get(t);
if (count == null) count = 0;
map.put(t, count + 1);
total++;
return count + 1;
}
/**
* Removes the given item from the multiset and returns how many of the
* item the multiset now contains.
* @throws NoSuchElementException if the item is not in the multiset.
*/
public int remove(T t) {
Integer count = map.get(t);
if (count == null) throw new NoSuchElementException();
if (count == 1) map.remove(t);
else map.put(t, count - 1);
total--;
return count - 1;
}
/**
* Removes all occurrences of the given item from the multiset.
*/
public int removeAll(T t) {
Integer count = map.remove(t);
if (count == null) return 0;
total -= count;
return count;
}
/**
* Returns true if the multiset contains any occurrences of the given item.
*/
public boolean contains(T t) {
return map.containsKey(t);
}
/**
* Removes all items from the multiset.
*/
public void clear() {
map.clear();
total = 0;
}
/**
* Returns the set of unique items the multiset contains. The returned set
* is unmodifiable.
*/
public Set<T> keySet() {
return Collections.unmodifiableSet(map.keySet());
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api;
import java.io.IOException;
/**
* An exception that indicates an unrecoverable version mismatch.
*/
public class UnsupportedVersionException extends IOException {
}

View File

@@ -23,7 +23,7 @@ public class BdfMessageContext {
}
public BdfMessageContext(BdfDictionary dictionary) {
this(dictionary, Collections.<MessageId>emptyList());
this(dictionary, Collections.emptyList());
}
public BdfDictionary getDictionary() {

View File

@@ -5,7 +5,10 @@ import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
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;
@@ -87,16 +90,30 @@ 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;
BdfList toList(Message m) throws FormatException;
BdfList toList(Author a);
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,18 +12,19 @@ public interface ContactGroupFactory {
/**
* Creates a group that is not shared with any contacts.
*/
Group createLocalGroup(ClientId clientId);
Group createLocalGroup(ClientId clientId, int majorVersion);
/**
* Creates a group for the given client to share with the given contact.
*/
Group createContactGroup(ClientId clientId, Contact contact);
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, AuthorId authorId1,
AuthorId authorId2);
Group createContactGroup(ClientId clientId, int majorVersion,
AuthorId authorId1, AuthorId authorId2);
}

View File

@@ -12,6 +12,32 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
@NotNullByDefault
public interface ContactExchangeTask {
/**
* The current version of the contact exchange protocol.
*/
byte PROTOCOL_VERSION = 1;
/**
* Label for deriving Alice's header key from the master secret.
*/
String ALICE_KEY_LABEL =
"org.briarproject.bramble.contact/ALICE_HEADER_KEY";
/**
* Label for deriving Bob's header key from the master secret.
*/
String BOB_KEY_LABEL = "org.briarproject.bramble.contact/BOB_HEADER_KEY";
/**
* Label for deriving Alice's key binding nonce from the master secret.
*/
String ALICE_NONCE_LABEL = "org.briarproject.bramble.contact/ALICE_NONCE";
/**
* Label for deriving Bob's key binding nonce from the master secret.
*/
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
/**
* Exchanges contact information with a remote peer.
*/

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(String)}.
*/
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

@@ -1,17 +1,17 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.TransportKeys;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import javax.annotation.Nullable;
@NotNullByDefault
public interface CryptoComponent {
SecretKey generateSecretKey();
PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom();
KeyPair generateAgreementKeyPair();
@@ -24,163 +24,84 @@ public interface CryptoComponent {
KeyParser getMessageKeyParser();
/** Generates a random invitation code. */
int generateBTInvitationCode();
/**
* Derives a confirmation code from the given master secret.
* @param alice whether the code is for use by Alice or Bob.
*/
int deriveBTConfirmationCode(SecretKey master, boolean alice);
/**
* Derives a stream header key from the given master secret.
* @param alice whether the key is for use by Alice or Bob.
*/
SecretKey deriveHeaderKey(SecretKey master, boolean alice);
/**
* Derives a message authentication code key from the given master secret.
* @param alice whether the key is for use by Alice or Bob.
*/
SecretKey deriveMacKey(SecretKey master, boolean alice);
/**
* Derives a nonce from the given master secret for one of the parties to
* sign.
* @param alice whether the nonce is for use by Alice or Bob.
*/
byte[] deriveSignatureNonce(SecretKey master, boolean alice);
/**
* Derives a commitment to the provided public key.
* <p/>
* Part of BQP.
* Derives another secret key from the given secret key.
*
* @param publicKey the public key
* @return the commitment to the provided public key.
* @param label a namespaced label indicating the purpose of the derived
* key, to prevent it from being repurposed or colliding with a key derived
* for another purpose
*/
byte[] deriveKeyCommitment(byte[] publicKey);
SecretKey deriveKey(String label, SecretKey k, byte[]... inputs);
/**
* Derives a common shared secret from two public keys and one of the
* corresponding private keys.
* <p/>
* Part of BQP.
*
* @param theirPublicKey the ephemeral public key of the remote party
* @param ourKeyPair our ephemeral keypair
* @param alice true if ourKeyPair belongs to Alice
* @param label a namespaced label indicating the purpose of this shared
* secret, to prevent it from being repurposed or colliding with a shared
* secret derived for another purpose
* @param theirPublicKey the public key of the remote party
* @param ourKeyPair the key pair of the local party
* @return the shared secret
* @throws GeneralSecurityException
*/
SecretKey deriveSharedSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
KeyPair ourKeyPair, byte[]... inputs)
throws GeneralSecurityException;
/**
* Derives the content of a confirmation record.
* <p/>
* Part of BQP.
* Signs the given byte[] with the given private key.
*
* @param sharedSecret the common shared secret
* @param theirPayload the commit payload from the remote party
* @param ourPayload the commit payload we sent
* @param theirPublicKey the ephemeral public key of the remote party
* @param ourKeyPair our ephemeral keypair
* @param alice true if ourKeyPair belongs to Alice
* @param aliceRecord true if the confirmation record is for use by Alice
* @return the confirmation record
*/
byte[] deriveConfirmationRecord(SecretKey sharedSecret,
byte[] theirPayload, byte[] ourPayload,
byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice, boolean aliceRecord);
/**
* Derives a master secret from the given shared secret.
* <p/>
* Part of BQP.
*
* @param sharedSecret the common shared secret
* @return the master secret
*/
SecretKey deriveMasterSecret(SecretKey sharedSecret);
/**
* Derives a master secret from two public keys and one of the corresponding
* private keys.
* <p/>
* This is a helper method that calls
* deriveMasterSecret(deriveSharedSecret(theirPublicKey, ourKeyPair, alice))
*
* @param theirPublicKey the ephemeral public key of the remote party
* @param ourKeyPair our ephemeral keypair
* @param alice true if ourKeyPair belongs to Alice
* @return the shared secret
* @throws GeneralSecurityException
*/
SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
/**
* Derives initial transport keys for the given transport in the given
* rotation period from the given master secret.
* @param alice whether the keys are for use by Alice or Bob.
*/
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
long rotationPeriod, boolean alice);
/**
* Rotates the given transport keys to the given rotation period. If the
* keys are for a future rotation period they are not rotated.
*/
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
/** Encodes the pseudo-random tag that is used to recognise a stream. */
void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
long streamNumber);
/**
* Signs the given byte[] with the given PrivateKey.
*
* @param label A label specific to this signature
* to ensure that the signature cannot be repurposed
* @param label a namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* signature created for another purpose
*/
byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signedData
* and the given publicKey.
* Verifies that the given signature is valid for the signed data
* and the given public key.
*
* @param label A label that was specific to this signature
* to ensure that the signature cannot be repurposed
* @param label a namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* 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
* combined by prefixing each input with its length.
*
* @param label A label specific to this hash to ensure that hashes
* calculated for distinct purposes don't collide.
* @param label a namespaced label indicating the purpose of this hash, to
* prevent it from being repurposed or colliding with a hash created for
* another purpose
*/
byte[] hash(String label, byte[]... inputs);
/**
* Returns the length of hashes produced by
* the {@link CryptoComponent#hash(String, byte[]...)} method.
*/
int getHashLength();
/**
* Returns a message authentication code with the given key over the
* given inputs. The inputs are unambiguously combined by prefixing each
* input with its length.
*
* @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
*/
byte[] mac(SecretKey macKey, byte[]... inputs);
byte[] mac(String label, SecretKey macKey, byte[]... inputs);
/**
* Verifies that the given message authentication code is valid for the
* given secret key and inputs.
*
* @param label a namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
* @return true if the MAC was valid, false otherwise.
*/
boolean verifyMac(byte[] mac, String label, SecretKey macKey,
byte[]... inputs);
/**
* Encrypts and authenticates the given plaintext so it can be written to
@@ -196,6 +117,7 @@ public interface CryptoComponent {
* given password. Returns null if the ciphertext cannot be decrypted and
* authenticated (for example, if the password is wrong).
*/
@Nullable
byte[] decryptWithPassword(byte[] ciphertext, String password);
/**

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.crypto;
public interface CryptoConstants {
/**
* The maximum length of an agreement public key in bytes.
*/
int MAX_AGREEMENT_PUBLIC_KEY_BYTES = 32;
/**
* The maximum length of a signature public key in bytes.
*/
int MAX_SIGNATURE_PUBLIC_KEY_BYTES = 32;
/**
* 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

@@ -0,0 +1,50 @@
package org.briarproject.bramble.api.crypto;
/**
* Crypto operations for the key agreement protocol - see
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md
*/
public interface KeyAgreementCrypto {
/**
* Hash label for public key commitment.
*/
String COMMIT_LABEL = "org.briarproject.bramble.keyagreement/COMMIT";
/**
* Key derivation label for confirmation record.
*/
String CONFIRMATION_KEY_LABEL =
"org.briarproject.bramble.keyagreement/CONFIRMATION_KEY";
/**
* MAC label for confirmation record.
*/
String CONFIRMATION_MAC_LABEL =
"org.briarproject.bramble.keyagreement/CONFIRMATION_MAC";
/**
* Derives a commitment to the provided public key.
*
* @param publicKey the public key
* @return the commitment to the provided public key.
*/
byte[] deriveKeyCommitment(PublicKey publicKey);
/**
* Derives the content of a confirmation record.
*
* @param sharedSecret the common shared secret
* @param theirPayload the key exchange payload of the remote party
* @param ourPayload the key exchange payload of the local party
* @param theirPublicKey the ephemeral public key of the remote party
* @param ourKeyPair our ephemeral key pair of the local party
* @param alice true if the local party is Alice
* @param aliceRecord true if the confirmation record is for use by Alice
* @return the confirmation record
*/
byte[] deriveConfirmationRecord(SecretKey sharedSecret,
byte[] theirPayload, byte[] ourPayload,
PublicKey theirPublicKey, KeyPair ourKeyPair,
boolean alice, boolean aliceRecord);
}

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

@@ -1,12 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* A deterministic pseudo-random number generator.
*/
@NotNullByDefault
public interface PseudoRandom {
byte[] nextBytes(int bytes);
}

View File

@@ -14,8 +14,9 @@ public interface StreamDecrypterFactory {
StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx);
/**
* Creates a {@link StreamDecrypter} for decrypting an invitation stream.
* Creates a {@link StreamDecrypter} for decrypting a contact exchange
* stream.
*/
StreamDecrypter createInvitationStreamDecrypter(InputStream in,
StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
SecretKey headerKey);
}

View File

@@ -14,8 +14,9 @@ public interface StreamEncrypterFactory {
StreamEncrypter createStreamEncrypter(OutputStream out, StreamContext ctx);
/**
* Creates a {@link StreamEncrypter} for encrypting an invitation stream.
* Creates a {@link StreamEncrypter} for encrypting a contact exchange
* stream.
*/
StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
StreamEncrypter createContactExchangeStreamDecrypter(OutputStream out,
SecretKey headerKey);
}

View File

@@ -0,0 +1,33 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.TransportKeys;
/**
* Crypto operations for the transport security protocol - see
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BTP.md
*/
public interface TransportCrypto {
/**
* Derives initial transport keys for the given transport in the given
* 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, boolean active);
/**
* Rotates the given transport keys to the given rotation period. If the
* keys are for the given period or any later period they are not rotated.
*/
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
/**
* Encodes the pseudo-random tag that is used to recognise a stream.
*/
void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
long streamNumber);
}

View File

@@ -4,11 +4,14 @@ import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
@NotThreadSafe
public class BdfDictionary extends TreeMap<String, Object> {
public static final Object NULL_VALUE = new Object();
@@ -21,9 +24,9 @@ public class BdfDictionary extends ConcurrentSkipListMap<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;
}
@@ -31,7 +34,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
super();
}
public BdfDictionary(Map<String, Object> m) {
public BdfDictionary(Map<String, ?> m) {
super(m);
}

View File

@@ -3,15 +3,17 @@ package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
public class BdfList extends Vector<Object> {
@NotThreadSafe
public class BdfList extends ArrayList<Object> {
/**
* Factory method for constructing lists inline.

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

@@ -1,11 +0,0 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException;
@NotNullByDefault
public interface ObjectReader<T> {
T readObject(BdfReader r) throws IOException;
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when the database uses a newer schema than the current code.
*/
public class DataTooNewException extends DbException {
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when the database uses an older schema than the current code and
* cannot be migrated.
*/
public class DataTooOldException extends DbException {
}

View File

@@ -18,7 +18,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;
@@ -37,8 +38,13 @@ public interface DatabaseComponent {
/**
* Opens the database and returns true if the database already existed.
*
* @throws DataTooNewException if the data uses a newer schema than the
* current code
* @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated
*/
boolean open() throws DbException;
boolean open(@Nullable MigrationListener listener) throws DbException;
/**
* Waits for any open transactions to finish and closes the database.
@@ -98,10 +104,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
@@ -122,8 +129,9 @@ public interface DatabaseComponent {
throws DbException;
/**
* Deletes the message with the given ID. The message ID and any other
* associated data are not deleted.
* Deletes the message with the given ID. Unlike
* {@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;
@@ -227,7 +235,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
@@ -253,31 +262,38 @@ public interface DatabaseComponent {
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the IDs of any messages that need to be validated by the given
* client.
* Returns the IDs of all delivered messages in the given group.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToValidate(Transaction txn, ClientId c)
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
throws DbException;
/**
* Returns the IDs of any messages that need to be validated.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToValidate(Transaction txn)
throws DbException;
/**
* Returns the IDs of any messages that are valid but pending delivery due
* to dependencies on other messages for the given client.
* Returns the IDs of any messages that are pending delivery due to
* dependencies on other messages.
* <p/>
* Read-only.
*/
Collection<MessageId> getPendingMessages(Transaction txn, ClientId c)
Collection<MessageId> getPendingMessages(Transaction txn)
throws DbException;
/**
* Returns the IDs of any messages from the given client
* that have a shared dependent, but are still not shared themselves.
* Returns the IDs of any messages that have shared dependents but have
* not yet been shared themselves.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToShare(Transaction txn,
ClientId c) throws DbException;
Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
@@ -297,9 +313,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.
*/
@@ -315,8 +331,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.
*/
@@ -324,8 +340,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.
*/
@@ -334,12 +350,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.
*/
@@ -347,9 +359,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.
*/
@@ -364,14 +376,24 @@ 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.
*/
MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m)
throws DbException;
/*
* Returns the next time (in milliseconds since the Unix epoch) when a
* message is due to be sent to the given contact. The returned value may
* be zero if a message is due to be sent immediately, or Long.MAX_VALUE if
* no messages are scheduled to be sent.
* <p/>
* Read-only.
*/
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
/**
* Returns all settings in the given namespace.
* <p/>
@@ -384,15 +406,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
@@ -452,11 +473,22 @@ public interface DatabaseComponent {
*/
void removeLocalAuthor(Transaction txn, AuthorId a) throws DbException;
/**
* Removes a message (and all associated state) from the database.
*/
void removeMessage(Transaction txn, MessageId m) throws DbException;
/**
* Removes a transport (and all associated state) from the database.
*/
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.
*/
@@ -492,15 +524,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

@@ -14,6 +14,8 @@ public interface DatabaseConfig {
File getDatabaseDirectory();
File getDatabaseKeyDirectory();
void setEncryptionKey(SecretKey key);
@Nullable

View File

@@ -1,11 +1,11 @@
package org.briarproject.bramble.api.db;
import java.util.Hashtable;
import java.util.TreeMap;
import javax.annotation.concurrent.ThreadSafe;
import javax.annotation.concurrent.NotThreadSafe;
@ThreadSafe
public class Metadata extends Hashtable<String, byte[]> {
@NotThreadSafe
public class Metadata extends TreeMap<String, byte[]> {
/**
* Special value to indicate that a key is being removed.

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.db;
public interface MigrationListener {
/**
* This is called when a migration is started while opening the database.
* It will be called once for each migration being applied.
*/
void onMigrationRun();
}

View File

@@ -45,7 +45,7 @@ public class Transaction {
* committed.
*/
public void attach(Event e) {
if (events == null) events = new ArrayList<Event>();
if (events == null) events = new ArrayList<>();
events.add(e);
}

View File

@@ -1,11 +1,13 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.UnsupportedEncodingException;
import org.briarproject.bramble.util.StringUtils;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
/**
* A pseudonym for a user.
*/
@@ -17,20 +19,25 @@ public class Author {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
}
/**
* The current version of the author structure.
*/
public static final int FORMAT_VERSION = 1;
private final AuthorId id;
private final int formatVersion;
private final String name;
private final byte[] publicKey;
public Author(AuthorId id, String name, byte[] publicKey) {
int length;
try {
length = name.getBytes("UTF-8").length;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
if (length == 0 || length > AuthorConstants.MAX_AUTHOR_NAME_LENGTH)
public Author(AuthorId id, int formatVersion, String name,
byte[] publicKey) {
int nameLength = StringUtils.toUtf8(name).length;
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)
throw new IllegalArgumentException();
this.id = id;
this.formatVersion = formatVersion;
this.name = name;
this.publicKey = publicKey;
}
@@ -42,6 +49,13 @@ public class Author {
return id;
}
/**
* Returns the version of the author structure used to create the author.
*/
public int getFormatVersion() {
return formatVersion;
}
/**
* Returns the author's name.
*/

View File

@@ -1,5 +1,8 @@
package org.briarproject.bramble.api.identity;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_PUBLIC_KEY_BYTES;
public interface AuthorConstants {
/**
@@ -8,26 +11,14 @@ public interface AuthorConstants {
int MAX_AUTHOR_NAME_LENGTH = 50;
/**
* The maximum length of a public key in bytes.
* <p>
* Public keys use SEC1 format: 0x04 x y, where x and y are unsigned
* big-endian integers.
* <p>
* For a 256-bit elliptic curve, the maximum length is 2 * 256 / 8 + 1.
* The maximum length of a public key in bytes. This applies to the
* signature algorithm used by the current {@link Author format version}.
*/
int MAX_PUBLIC_KEY_LENGTH = 65;
int MAX_PUBLIC_KEY_LENGTH = MAX_SIGNATURE_PUBLIC_KEY_BYTES;
/**
* The maximum length of a signature in bytes.
* <p>
* A signature is an ASN.1 DER sequence containing two integers, r and s.
* The format is 0x30 len1 0x02 len2 r 0x02 len3 s, where len1 is
* len(0x02 len2 r 0x02 len3 s) as a DER length, len2 is len(r) as a DER
* length, len3 is len(s) as a DER length, and r and s are signed
* big-endian integers of minimal length.
* <p>
* For a 256-bit elliptic curve, the lengths are one byte each, so the
* maximum length is 2 * 256 / 8 + 8.
* The maximum length of a signature in bytes. This applies to the
* signature algorithm used by the current {@link Author format version}.
*/
int MAX_SIGNATURE_LENGTH = 72;
int MAX_SIGNATURE_LENGTH = MAX_SIGNATURE_BYTES;
}

View File

@@ -5,8 +5,27 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AuthorFactory {
/**
* Creates an author with the current format version and the given name and
* public key.
*/
Author createAuthor(String name, byte[] publicKey);
/**
* Creates an author with the given format version, name and public key.
*/
Author createAuthor(int formatVersion, String name, byte[] publicKey);
/**
* Creates a local author with the current format version and the given
* name and keys.
*/
LocalAuthor createLocalAuthor(String name, byte[] publicKey,
byte[] privateKey);
/**
* Creates a local author with the given format version, name and keys.
*/
LocalAuthor createLocalAuthor(int formatVersion, String name,
byte[] publicKey, byte[] privateKey);
}

View File

@@ -16,7 +16,7 @@ public class AuthorId extends UniqueId {
/**
* Label for hashing authors to calculate their identities.
*/
public static final String LABEL = "org.briarproject.bramble.AUTHOR_ID";
public static final String LABEL = "org.briarproject.bramble/AUTHOR_ID";
public AuthorId(byte[] id) {
super(id);

View File

@@ -14,9 +14,9 @@ public class LocalAuthor extends Author {
private final byte[] privateKey;
private final long created;
public LocalAuthor(AuthorId id, String name, byte[] publicKey,
byte[] privateKey, long created) {
super(id, name, publicKey);
public LocalAuthor(AuthorId id, int formatVersion, String name,
byte[] publicKey, byte[] privateKey, long created) {
super(id, formatVersion, name, publicKey);
this.privateKey = privateKey;
this.created = created;
}

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.api.invitation;
public interface InvitationConstants {
/**
* The connection timeout in milliseconds.
*/
long CONNECTION_TIMEOUT = 60 * 1000;
/**
* The confirmation timeout in milliseconds.
*/
long CONFIRMATION_TIMEOUT = 60 * 1000;
/**
* The number of bits in an invitation or confirmation code. Codes must fit
* into six decimal digits.
*/
int CODE_BITS = 19;
}

View File

@@ -1,47 +0,0 @@
package org.briarproject.bramble.api.invitation;
/**
* An interface for receiving updates about the state of an
* {@link InvitationTask}.
*/
public interface InvitationListener {
/** Called if a connection to the remote peer is established. */
void connectionSucceeded();
/**
* Called if a connection to the remote peer cannot be established. This
* indicates that the protocol has ended unsuccessfully.
*/
void connectionFailed();
/** Called if key agreement with the remote peer succeeds. */
void keyAgreementSucceeded(int localCode, int remoteCode);
/**
* Called if key agreement with the remote peer fails or the connection is
* lost. This indicates that the protocol has ended unsuccessfully.
*/
void keyAgreementFailed();
/** Called if the remote peer's confirmation check succeeds. */
void remoteConfirmationSucceeded();
/**
* Called if remote peer's confirmation check fails or the connection is
* lost. This indicates that the protocol has ended unsuccessfully.
*/
void remoteConfirmationFailed();
/**
* Called if the exchange of pseudonyms succeeds. This indicates that the
* protocol has ended successfully.
*/
void pseudonymExchangeSucceeded(String remoteName);
/**
* Called if the exchange of pseudonyms fails or the connection is lost.
* This indicates that the protocol has ended unsuccessfully.
*/
void pseudonymExchangeFailed();
}

View File

@@ -1,85 +0,0 @@
package org.briarproject.bramble.api.invitation;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* A snapshot of the state of an {@link InvitationTask}.
*/
@Immutable
@NotNullByDefault
public class InvitationState {
private final int localInvitationCode, remoteInvitationCode;
private final int localConfirmationCode, remoteConfirmationCode;
private final boolean connected, connectionFailed;
private final boolean localCompared, remoteCompared;
private final boolean localMatched, remoteMatched;
@Nullable
private final String contactName;
public InvitationState(int localInvitationCode, int remoteInvitationCode,
int localConfirmationCode, int remoteConfirmationCode,
boolean connected, boolean connectionFailed, boolean localCompared,
boolean remoteCompared, boolean localMatched,
boolean remoteMatched, @Nullable String contactName) {
this.localInvitationCode = localInvitationCode;
this.remoteInvitationCode = remoteInvitationCode;
this.localConfirmationCode = localConfirmationCode;
this.remoteConfirmationCode = remoteConfirmationCode;
this.connected = connected;
this.connectionFailed = connectionFailed;
this.localCompared = localCompared;
this.remoteCompared = remoteCompared;
this.localMatched = localMatched;
this.remoteMatched = remoteMatched;
this.contactName = contactName;
}
public int getLocalInvitationCode() {
return localInvitationCode;
}
public int getRemoteInvitationCode() {
return remoteInvitationCode;
}
public int getLocalConfirmationCode() {
return localConfirmationCode;
}
public int getRemoteConfirmationCode() {
return remoteConfirmationCode;
}
public boolean getConnected() {
return connected;
}
public boolean getConnectionFailed() {
return connectionFailed;
}
public boolean getLocalCompared() {
return localCompared;
}
public boolean getRemoteCompared() {
return remoteCompared;
}
public boolean getLocalMatched() {
return localMatched;
}
public boolean getRemoteMatched() {
return remoteMatched;
}
@Nullable
public String getContactName() {
return contactName;
}
}

View File

@@ -1,38 +0,0 @@
package org.briarproject.bramble.api.invitation;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* A task for exchanging invitations with a remote peer.
*/
@NotNullByDefault
public interface InvitationTask {
/**
* Adds a listener to be informed of state changes and returns the
* task's current state.
*/
InvitationState addListener(InvitationListener l);
/**
* Removes the given listener.
*/
void removeListener(InvitationListener l);
/**
* Asynchronously starts the connection process.
*/
void connect();
/**
* Asynchronously informs the remote peer that the local peer's
* confirmation codes matched.
*/
void localConfirmationSucceeded();
/**
* Asynchronously informs the remote peer that the local peer's
* confirmation codes did not match.
*/
void localConfirmationFailed();
}

View File

@@ -1,15 +0,0 @@
package org.briarproject.bramble.api.invitation;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Creates tasks for exchanging invitations with remote peers.
*/
@NotNullByDefault
public interface InvitationTaskFactory {
/**
* Creates a task using the given local and remote invitation codes.
*/
InvitationTask createTask(int localCode, int remoteCode);
}

View File

@@ -3,9 +3,9 @@ package org.briarproject.bramble.api.keyagreement;
public interface KeyAgreementConstants {
/**
* The current version of the BQP protocol.
* The current version of the BQP protocol. Version number 89 is reserved.
*/
byte PROTOCOL_VERSION = 2;
byte PROTOCOL_VERSION = 4;
/**
* The length of the record header in bytes.
@@ -22,7 +22,10 @@ public interface KeyAgreementConstants {
*/
int COMMIT_LENGTH = 16;
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
/**
* The connection timeout in milliseconds.
*/
long CONNECTION_TIMEOUT = 20 * 1000;
/**
* The transport identifier for Bluetooth.
@@ -33,4 +36,16 @@ public interface KeyAgreementConstants {
* The transport identifier for LAN.
*/
int TRANSPORT_ID_LAN = 1;
/**
* Label for deriving the shared secret.
*/
String SHARED_SECRET_LABEL =
"org.briarproject.bramble.keyagreement/SHARED_SECRET";
/**
* Label for deriving the master secret.
*/
String MASTER_SECRET_LABEL =
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
}

View File

@@ -2,7 +2,7 @@ package org.briarproject.bramble.api.keyagreement;
import org.briarproject.bramble.api.data.BdfList;
import java.util.concurrent.Callable;
import java.io.IOException;
/**
* An class for managing a particular key agreement listener.
@@ -24,11 +24,11 @@ public abstract class KeyAgreementListener {
}
/**
* Starts listening for incoming connections, and returns a Callable that
* will return a KeyAgreementConnection when an incoming connection is
* received.
* Blocks until an incoming connection is received and returns it.
*
* @throws IOException if an error occurs or {@link #close()} is called.
*/
public abstract Callable<KeyAgreementConnection> listen();
public abstract KeyAgreementConnection accept() throws IOException;
/**
* Closes the underlying server socket.

View File

@@ -1,15 +0,0 @@
package org.briarproject.bramble.api.keyagreement;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Manages tasks for conducting key agreements with remote peers.
*/
@NotNullByDefault
public interface KeyAgreementTaskFactory {
/**
* Gets the current key agreement task.
*/
KeyAgreementTask createTask();
}

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

@@ -21,21 +21,42 @@ public interface LifecycleManager {
* The result of calling {@link #startServices(String)}.
*/
enum StartResult {
ALREADY_RUNNING, DB_ERROR, SERVICE_ERROR, SUCCESS
ALREADY_RUNNING,
DB_ERROR,
DATA_TOO_OLD_ERROR,
DATA_TOO_NEW_ERROR,
SERVICE_ERROR,
SUCCESS
}
/**
* Registers a {@link Service} to be started and stopped.
* The state the lifecycle can be in.
* Returned by {@link #getLifecycleState()}
*/
enum LifecycleState {
STARTING, MIGRATING_DATABASE, STARTING_SERVICES, RUNNING, STOPPING;
public boolean isAfter(LifecycleState state) {
return ordinal() > state.ordinal();
}
}
/**
* Registers a {@link Service} to be started and stopped. This method
* should be called before {@link #startServices(String)}.
*/
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(String)}.
*/
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(String)}.
*/
void registerForShutdown(ExecutorService e);
@@ -71,4 +92,10 @@ public interface LifecycleManager {
* the {@link DatabaseComponent} to be closed before returning.
*/
void waitForShutdown() throws InterruptedException;
/**
* Returns the current state of the lifecycle.
*/
LifecycleState getLifecycleState();
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.lifecycle.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
/**
* An event that is broadcast when the app enters a new lifecycle state.
*/
public class LifecycleEvent extends Event {
private final LifecycleState state;
public LifecycleEvent(LifecycleState state) {
this.state = state;
}
public LifecycleState getLifecycleState() {
return state;
}
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.lifecycle.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the app is shutting down.
*/
public class ShutdownEvent extends Event {
}

View File

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

View File

@@ -4,5 +4,10 @@ public interface LanTcpConstants {
TransportId ID = new TransportId("org.briarproject.bramble.lan");
// a transport property (shared with contacts)
String PROP_IP_PORTS = "ipPorts";
// a local setting
String PREF_LAN_IP_PORTS = "ipPorts";
}

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,12 +22,7 @@ public interface PluginCallback {
TransportProperties getLocalProperties();
/**
* Returns the plugin's remote transport properties.
*/
Map<ContactId, TransportProperties> getRemoteProperties();
/**
* Merges the given settings with the namespaced settings
* Merges the given settings with the plugin's settings
*/
void mergeSettings(Settings s);
@@ -40,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

@@ -32,11 +32,6 @@ public interface PluginManager {
*/
Collection<DuplexPlugin> getDuplexPlugins();
/**
* Returns any duplex plugins that support invitations.
*/
Collection<DuplexPlugin> getInvitationPlugins();
/**
* Returns any duplex plugins that support key agreement.
*/

View File

@@ -4,6 +4,8 @@ public interface TorConstants {
TransportId ID = new TransportId("org.briarproject.bramble.tor");
String PROP_ONION = "onion";
int SOCKS_PORT = 59050;
int CONTROL_PORT = 59051;
@@ -16,4 +18,5 @@ public interface TorConstants {
int PREF_TOR_NETWORK_NEVER = 0;
int PREF_TOR_NETWORK_WIFI = 1;
int PREF_TOR_NETWORK_ALWAYS = 2;
}

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,11 +1,10 @@
package org.briarproject.bramble.api.plugin.duplex;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.PseudoRandom;
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;
@@ -16,26 +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);
/**
* Returns true if the plugin supports exchanging invitations.
*/
boolean supportsInvitations();
/**
* Attempts to create and return an invitation connection to the remote
* peer. Returns null if no connection can be established within the given
* time.
*/
@Nullable
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice);
DuplexTransportConnection createConnection(TransportProperties p);
/**
* Returns true if the plugin supports short-range key agreement.
@@ -51,9 +35,9 @@ public interface DuplexPlugin extends Plugin {
/**
* Attempts to connect to the remote peer specified in the given descriptor.
* Returns null if no connection can be established within the given time.
* Returns null if no connection can be established.
*/
@Nullable
DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, BdfList descriptor, long timeout);
byte[] remoteCommitment, BdfList descriptor);
}

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

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that informs the Bluetooth plugin that we have enabled the
* Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class BluetoothEnabledEvent extends Event {
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to disable the Bluetooth adapter if
* we previously enabled it.
*/
@Immutable
@NotNullByDefault
public class DisableBluetoothEvent extends Event {
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to enable the Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class EnableBluetoothEvent extends Event {
}

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,7 +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 major version of the transport property client.
*/
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
@@ -32,8 +42,8 @@ public interface TransportPropertyManager {
/**
* Returns the local transport properties for all transports.
* <br/>
* Read-Only
* <p/>
* Read-only.
*/
Map<TransportId, TransportProperties> getLocalProperties(Transaction txn)
throws DbException;
@@ -49,6 +59,13 @@ public interface TransportPropertyManager {
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException;
/**
* Returns the remote transport properties for the given contact and
* transport.
*/
TransportProperties getRemoteProperties(ContactId c, TransportId t)
throws DbException;
/**
* Merges the given properties with the existing local properties for the
* given transport.

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;
}
@@ -36,4 +46,8 @@ public class ClientId implements Comparable<ClientId> {
return id.hashCode();
}
@Override
public String toString() {
return 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 and descriptor.
* Creates a group with the given client ID, major version and descriptor.
*/
Group createGroup(ClientId c, byte[] descriptor);
Group createGroup(ClientId c, int majorVersion, byte[] descriptor);
}

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