Compare commits

...

855 Commits

Author SHA1 Message Date
akwizgran
459538e40c Bump version numbers for beta release. 2017-12-22 14:43:03 +00:00
akwizgran
183f501761 Merge branch '1132-upgrade-tor-0.2.9.14' into 'maintenance-0.16'
Beta: Upgrade Tor to 0.2.9.14, GeoIP to 2017-11-06

See merge request akwizgran/briar!657
2017-12-22 14:10:52 +00:00
akwizgran
65ee5f539b Upgrade Tor to 0.2.9.14, GeoIP to 2017-11-06. 2017-12-22 13:52:45 +00:00
akwizgran
604339326c Merge branch '1129-send-on-ctrl-enter' into 'maintenance-0.16'
Beta: Send message on ctrl + enter

See merge request akwizgran/briar!656
2017-12-22 11:49:55 +00:00
sbkaf
0acec1343f send message on ctrl + enter 2017-12-22 11:32:15 +00:00
akwizgran
0434756bbd Merge branch '1133-extend-expiry-period' into 'maintenance-0.16'
Extend expiry date, show extension notification

See merge request akwizgran/briar!655
2017-12-22 11:23:40 +00:00
akwizgran
e233433140 Extend expiry date, show extension notification. 2017-12-22 10:58:11 +00:00
akwizgran
c63f285f53 Bumped version numbers for beta release. 2017-12-07 14:13:11 +00:00
akwizgran
0800188718 Merge branch '1112-screen-filter-crash' into 'maintenance-0.16'
Beta: Don't show screen filter dialog after onSaveInstanceState().

See merge request !650
2017-12-07 13:29:27 +00:00
akwizgran
6188e48beb Don't show screen filter dialog after onSaveInstanceState(). 2017-12-07 13:07:07 +00:00
akwizgran
5726e29b56 Merge branch '1088-huawei-whitelisting' into 'maintenance-0.16'
Beta: Add button for Huawei's power manager to setup wizard

See merge request !648
2017-12-07 13:05:34 +00:00
Torsten Grote
5d70399de0 Add button for Huawei's power manager to setup wizard 2017-12-05 15:26:14 -02:00
akwizgran
73202dde5e Merge branch '1127-notification-channels' into 'maintenance-0.16'
Beta: Use channels for all notifications

See merge request !647
2017-12-05 17:03:37 +00:00
akwizgran
a98ac8233c Sort order of channel IDs affects UI of Settings app. 2017-12-05 16:49:31 +00:00
akwizgran
bee3e244fc Use channels for all notifications. 2017-12-05 16:49:31 +00:00
akwizgran
da25999a15 Merge branch '1120-crash-removing-shutdown-hook' into 'maintenance-0.16'
Beta: Don't remove shutdown hook when closing DB

See merge request !645
2017-12-05 14:58:56 +00:00
akwizgran
62049df342 Don't remove shutdown hook when closing DB. 2017-12-05 14:46:07 +00:00
akwizgran
024e5aa90f Bumped version numbers for beta release. 2017-12-04 14:43:27 +00:00
akwizgran
6d791481d5 Merge branch '1007-samsung-transition-npe-beta' into 'maintenance-0.16'
Beta: Don't set scene transition for Samsung devices running Android 7.0

See merge request !641
2017-12-04 14:35:39 +00:00
Torsten Grote
0a807d0893 Don't set scene transition for Samsung devices running Android 7.0 2017-12-04 10:58:20 -02:00
akwizgran
23596bbdd4 Merge branch origin/maintenance-0.16 into maintenance-0.16 2017-12-01 17:19:42 +00:00
Torsten Grote
fe79954138 Merge branch 'briar-beta-app-name' into 'maintenance-0.16'
Change app name for beta debug builds

See merge request !636
2017-12-01 16:43:45 +00:00
akwizgran
9902c023ca Bump version number for beta release. 2017-12-01 16:30:18 +00:00
akwizgran
e8baee6734 Specify 7 characters for Git revision.
(cherry picked from commit f0d8532)
2017-12-01 16:29:45 +00:00
akwizgran
a8dc029e56 Change app name for beta debug builds. 2017-12-01 16:21:20 +00:00
akwizgran
74e3fee7aa Merge branch '1124-notification-channel-crash-beta' into 'maintenance-0.16'
Beta: Use NotificationChannel for foreground service to avoid crash on Android 8.1

See merge request !635
2017-12-01 16:00:53 +00:00
Torsten Grote
05aac696b7 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:47:02 -02: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
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
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
Michael Rogers
050191f0ef Bumped version number for beta release. 2017-08-01 12:31:47 +01:00
akwizgran
4b5a19ce5d Merge branch 'update-translations' into 'master'
Update translations, add Turkish and Russian

See merge request !575
2017-08-01 09:28:17 +00:00
akwizgran
7c4dd991b9 Merge branch '1016-reblog-runtime-error' into 'master'
Runtime error fix due to window requests

Closes #1016 and #1007

See merge request !576
2017-08-01 09:25:39 +00:00
Ernir Erlingsson
8455569e88 moved window requests above onCreate 2017-07-30 22:42:03 +02:00
Torsten Grote
d25676559c Update translations, add Turkish and Russian 2017-07-29 11:03:51 -03:00
Michael Rogers
a9437f7985 Bumped version number for beta release. 2017-07-28 18:01:19 +01:00
akwizgran
8141a97fc9 Merge branch '1015-recent-emoji-crash' into 'master'
Prevent a crash caused by empty emoji

Closes #1015

See merge request !571
2017-07-28 16:59:02 +00:00
Torsten Grote
db842bd7e4 Prevent a crash caused by empty emoji
The crash happens because the serialization of recently used emoji uses
';' to separate the emojis.
One of the ASCII emojis however has a ';' in the beginning.
When this one is used by the user,
it causes an empty string to be returned when deserializing.

This commit prevents the crash by changing the separator to a tab.
It uses a different settings string to store the emoji,
so users will lose the list of recently used emoji when they update to
this version.

PS. That wasn't my idea ;)
2017-07-28 13:49:51 -03:00
Torsten Grote
6dbec3a864 Merge branch 'enable-logging-for-beta-builds' into 'master'
Enable logging for beta builds

See merge request !573
2017-07-28 15:58:01 +00:00
akwizgran
29f658cf4d Merge branch '1006-blog-crash' into 'master'
Prevent crash in blog by ensuring a listener always exists

Closes #1006

See merge request !574
2017-07-28 15:53:43 +00:00
akwizgran
ca83744a84 Merge branch 'close-feed-stream' into 'master'
Close InputStream from RSS feed and prevent NPE

See merge request !572
2017-07-28 15:48:01 +00:00
Torsten Grote
d91a9e2be4 Prevent crash in blog by ensuring a listener always exists 2017-07-28 12:42:56 -03:00
akwizgran
8408c3f467 Enable logging for beta builds.
Some devices were logging and others not, due to the log level being set in the SplashScreenActivity constructor.
2017-07-28 16:41:24 +01:00
Torsten Grote
544c83a64c Close InputStream from RSS feed and prevent NPE 2017-07-28 10:38:01 -03:00
Michael Rogers
3800cd5e4f Bumped version number for beta release. 2017-07-28 11:17:09 +01:00
akwizgran
259f2cd419 Merge branch '993-fix-full-text-blog-posts' into 'master'
Show blog posts with full text when clicked

Closes #993

See merge request !570
2017-07-26 11:01:38 +00:00
Torsten Grote
20eb022c36 Show blog posts with full text when clicked
This fixes a regression that was introduced in !551.
2017-07-25 15:50:04 -03:00
akwizgran
531e555b52 Bumped version number for beta release. 2017-07-25 18:43:19 +01:00
akwizgran
a9024aa34b Merge branch '955-shared-with-update' into 'master'
Fix "shared with" counter not being updated

Closes #955

See merge request !569
2017-07-25 17:40:40 +00:00
akwizgran
d4e3b7842c Merge branch 'blog-sharing-tests' into 'master'
Add unit tests for BlogSharingManager

See merge request !567
2017-07-25 17:40:29 +00:00
Torsten Grote
167fddfbcc Add unit tests for BlogSharingManager 2017-07-25 12:45:36 -03:00
Torsten Grote
a48d642648 Fix UI bug in CreateForumActivity and adapt group creation 2017-07-25 12:32:53 -03:00
Torsten Grote
9a70f054c7 Use proper GroupId when reacting to accepted invitations
Fixes #955
2017-07-25 10:03:13 -03:00
Torsten Grote
ca43d13bd6 Merge branch 'inject-properties-module-eager-singletons' into 'master'
Inject properties module's eager singletons

See merge request !568
2017-07-25 12:55:59 +00:00
akwizgran
5b71004179 Inject properties module's eager singletons. 2017-07-25 13:49:15 +01:00
akwizgran
63befccdbf Bumped expiry time and version number for beta release. 2017-07-21 11:52:09 +01:00
akwizgran
4ecf7c02d0 Merge branch '979-duplicate-blog-session' into 'master'
Fix Blog Sharing Sessions

Closes #979

See merge request !566
2017-07-21 10:27:21 +00:00
Torsten Grote
f25badc18c Move responsibility for pre-sharing blogs to sharing manager
to have all the code related to that in one place,
so it is easier to maintain and to spot bugs.

This also checks that only blogs without an existing sharing session
are shared and initialized again.
It extends an existing test to catch the missing check.

This removes some debugging information from the previous commit
to not leak private information via the sharing sessions.

Fixes #979
2017-07-17 14:07:47 -03:00
akwizgran
6e931e9ba5 Bump version number and expiry date for beta release. 2017-07-17 10:32:46 +01:00
akwizgran
7e749124bf Merge branch '617-protocol-versioning' into 'master'
Protocol versioning for BTP

See merge request !557
2017-07-17 09:24:35 +00:00
akwizgran
5822eb7808 Remove 'this'. 2017-07-17 10:16:50 +01:00
Torsten Grote
7a7e086541 Merge branch '982-name-not-found-exception' into 'master'
Use fully-qualified class names in manifest

Closes #982

See merge request !565
2017-07-14 12:19:50 +00:00
akwizgran
abab3167c2 Use fully-qualified class names in manifest.
This prevents a crash on Android 4 when the package name in build.gradle differs from the name in the manifest.
2017-07-14 12:01:55 +01:00
Torsten Grote
8d08570568 Merge branch '977-crash-when-opening-rss-blog' into 'master'
Create correct shareable for RSS blogs

Closes #977

See merge request !564
2017-07-07 17:42:54 +00:00
akwizgran
2007078f13 Added test for sharing an RSS blog. 2017-07-07 18:02:15 +01:00
akwizgran
dfb71a7978 Merge branch '942-block-blog-notifications' into 'master'
Block blog notifications when viewing combined feed

See merge request !563
2017-07-07 16:32:07 +00:00
akwizgran
480b0e3a03 Create correct shareable for RSS blogs.
Also removed "personal blog" wording that doesn't apply to RSS blogs.
2017-07-07 17:30:44 +01:00
akwizgran
8f8751f4ac Block blog notifications when viewing combined feed. 2017-07-07 15:34:00 +01:00
akwizgran
de2ea112ee Merge branch '933-beta-warning' into 'master'
Show Beta Expiry Warning

Closes #933

See merge request !559
2017-07-07 12:19:04 +00:00
Torsten Grote
6f99a53fd9 Show beta expiry warning in main activity 2017-07-07 09:12:07 -03:00
akwizgran
a8a9b9032d Merge branch 'warn_on_extra_translation' into 'master'
Show a warning instead of throwing an error for unused translations

See merge request !561
2017-07-07 12:01:23 +00:00
goapunk
6b15fb89de Show a warning instead of throwing an error for unused translations
Signed-off-by: goapunk <noobie@goapunks.net>
2017-07-07 12:19:44 +02:00
Torsten Grote
a711d6b8a1 Merge branch '106-fix-package-name' into 'master'
Set applicationId to match app_package

See merge request !560
2017-07-05 13:46:30 +00:00
akwizgran
5678f8aaa4 Update Robolectric tests so they can find resources. 2017-07-05 14:40:03 +01:00
akwizgran
2fe37f6c26 Set applicationId to match app_package. 2017-07-05 14:17:35 +01:00
Torsten Grote
a879747968 Translation Update 2017-07-05 09:50:14 -03:00
akwizgran
95e8fd7ee0 Merge branch 'notify_more_agressively' into 'master'
Notify more aggressively

See merge request !555
2017-07-05 11:36:37 +00:00
goapunk
4416aaaa4c Notify more aggressively
* Add setting to show notification on the lockscreen
* Don't block notifications in the contact-/-group/-forum/-bloglist

Signed-off-by: goapunk <noobie@goapunks.net>
2017-07-05 13:05:21 +02:00
Torsten Grote
500d5f0efe Merge branch '822-group-creation-workflow' into 'master'
Revisit private group creation workflow

Closes #822

See merge request !553
2017-07-04 17:19:11 +00:00
akwizgran
fc8978fd90 Create forum when button is clicked. 2017-07-04 16:17:59 +01:00
akwizgran
73df126bd4 Create and share private groups separately, as with forums. 2017-07-04 16:17:58 +01:00
akwizgran
9146488c7d Use same layout and behaviour for creating groups and forums. 2017-07-04 16:17:58 +01:00
akwizgran
613a7fe376 Merge branch '962-removing-contacts' into 'master'
Add test where two contacts remove each other

Closes #962

See merge request !558
2017-07-04 15:14:27 +00:00
akwizgran
ecb62f00d4 Code cleanup. 2017-07-04 16:09:32 +01:00
akwizgran
c4540a03cd Protocol versioning for BTP. 2017-07-04 16:09:32 +01:00
akwizgran
3e31da99b5 Merge branch '106-beta-namespace' into 'master'
Change app name and package name for beta release

Closes #106

See merge request !545
2017-07-04 14:40:47 +00:00
Torsten Grote
098c1d0b1e Add test where two contacts remove each other 2017-07-04 11:30:17 -03:00
akwizgran
178e908c86 Use a different package name and app name for beta builds. 2017-07-03 18:20:05 +01:00
akwizgran
ecf7cf14ae Merge branch '957-rss-url-case-sensitivity' into 'master'
Handle RSS URLs case-insensitively

Closes #957

See merge request !544
2017-07-03 16:22:52 +00:00
akwizgran
09e2a15a73 Merge branch '951-remove-visibility-indicators' into 'master'
Remove visibility indicators from private group join messages

Closes #951

See merge request !546
2017-07-03 16:22:31 +00:00
akwizgran
ab387860a6 Removed visibility indicators from private group member list. 2017-07-03 16:37:29 +01:00
akwizgran
f63fc94f2b Removed visibility indicators from private group join messages. 2017-07-03 16:37:29 +01:00
Michael Rogers
41e5928cca Validate and normalise RSS URLs. 2017-07-03 16:36:50 +01:00
Torsten Grote
8303175494 Merge branch 'use-f-droid-base-docker-image' into 'master'
Use F-Droid's base Docker image

See merge request !556
2017-07-03 15:35:28 +00:00
akwizgran
151eb6935b Use F-Droid's base Docker image. 2017-07-03 16:17:03 +01:00
akwizgran
6a419c0c7b Merge branch '968-downgrade-h2' into 'master'
Downgrade H2 to 1.4.192

Closes #968

See merge request !550
2017-07-03 11:51:35 +00:00
akwizgran
1795b32121 Downgrade H2 to 1.4.192. 2017-07-03 12:36:45 +01:00
akwizgran
01971768ce Merge branch '970_settings_use_summaries' into 'master'
Split notification settings into title and summary.

Closes #970

See merge request !554
2017-07-03 11:19:15 +00:00
akwizgran
ef7483ab01 Merge branch '787-tapping-blog-author-opens-same-blog' into 'master'
Don't reopen the same blog when the author is tapped

Closes #787

See merge request !551
2017-07-03 10:43:15 +00:00
akwizgran
527d11473d Merge branch '805-introduction-message-layout' into 'master'
Use smaller layout for introduction message screen

Closes #805

See merge request !552
2017-07-03 10:40:10 +00:00
akwizgran
775dadc9a0 Merge branch '904-notify-tor-controller' into 'master'
Notify Tor controller if Tor has crashed

Closes #904

See merge request !543
2017-07-03 09:29:04 +00:00
akwizgran
800b10a988 Merge branch '956-tap-protection-ux' into 'master'
Don't show tap protection dialog until it's needed

Closes #956

See merge request !548
2017-07-03 09:22:31 +00:00
akwizgran
c977bf047d Removed overrides of showScreenFilterWarning. 2017-07-03 10:08:36 +01:00
goapunk
660a25f21d Split notification settings into title and summary.
Signed-off-by: goapunk <noobie@goapunks.net>
2017-07-03 09:27:07 +02:00
Torsten Grote
e7fd6d23af Merge branch '962-check-blog-subscription-when-removing-contact' into 'master'
Check personal blog subscription when removing contact

See merge request !549
2017-06-30 20:57:52 +00:00
Torsten Grote
46982897f0 Merge branch '963-load-thread-list-messages-on-start' into 'master'
Load messages each time activity starts

See merge request !547
2017-06-30 20:53:13 +00:00
Torsten Grote
d24de68d64 Merge branch '574-upgrade-tor' into 'master'
Upgrade Tor to 0.2.9

Closes #574

See merge request !542
2017-06-30 20:36:22 +00:00
akwizgran
7514c46a3f Use smaller layout for introduction message screen. 2017-06-30 16:23:16 +01:00
akwizgran
6632c0f8e3 Don't reopen the same blog when the author is tapped. 2017-06-30 14:24:32 +01:00
akwizgran
79aafcda69 Fixed a test, added a regression test. 2017-06-30 12:58:44 +01:00
akwizgran
05af21e8dc Check personal blog subscription when removing contact. 2017-06-30 12:04:34 +01:00
akwizgran
0dc62cbbdc Fixed a test. 2017-06-30 10:01:35 +01:00
akwizgran
f3a084cfd2 Removed option to remember shown overlay apps. 2017-06-29 18:47:36 +01:00
akwizgran
8b32f82566 Don't show tap protection dialog until it's needed. 2017-06-29 18:18:39 +01:00
akwizgran
d598b6ed44 Load messages each time activity starts. 2017-06-26 16:21:25 +01:00
akwizgran
f5dc6f24b9 Bumped expiry date to 1 September 2017. 2017-06-26 14:50:58 +01:00
akwizgran
37454392da Update Tor binaries to 0.2.9.11. 2017-06-23 22:06:00 +01:00
akwizgran
de7f9111d3 Update Tor patch to 0.2.9.11. 2017-06-23 15:23:26 +01:00
akwizgran
96d2889a6c Notify Tor controller if Tor has crashed. 2017-06-23 14:57:00 +01:00
Torsten Grote
f6412d1e9a Merge branch 'spongy-castle-1-56' into 'master'
Upgrade Spongy Castle and some other dependencies

See merge request !541
2017-06-15 17:37:22 +00:00
akwizgran
b377cd6b1c Upgrade Spongy Castle and some other dependencies. 2017-06-12 17:44:08 +01:00
Ernir Erlingsson
f6cdbda5bb Merge branch 'master' of https://code.briarproject.org/akwizgran/briar 2017-05-29 11:06:16 +02:00
Ernir Erlingsson
855c600a3e hotfix list restore NPE for user testing 2017-05-29 11:05:46 +02:00
akwizgran
ea6e8303b0 Merge branch '954_dont_show_on_startup_failure' into 'master'
Don't show screenfilter warning in StartupFailureActivity

See merge request !539
2017-05-29 09:05:18 +00:00
goapunk
d4934040d9 Don't show screenfilter warning in StartupFailureActivity
Signed-off-by: goapunk <noobie@goapunks.net>
2017-05-22 12:40:33 +02:00
akwizgran
3449677b24 Bumped version number and expiry date. 2017-05-19 12:07:29 +01:00
akwizgran
1ad3a6646e Merge branch '941-store-correct-parent-id' into 'master'
Store correct original parent ID when rewrapping blog posts

See merge request !534
2017-05-12 09:53:27 +00:00
akwizgran
2d10f6b2bd Merge branch '884-emoji-text-view-layout-bug' into 'master'
Remove ellipsizing support from EmojiTextView

Closes #884

See merge request !533
2017-05-12 09:35:33 +00:00
akwizgran
5b05424d83 Merge branch 'master' into '941-store-correct-parent-id'
# Conflicts:
#   briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
2017-05-12 09:34:24 +00:00
akwizgran
0826022d82 Merge branch 'bring_annotations_in_line' into 'master'
Bring nullable annotation imports in line

See merge request !536
2017-05-12 09:33:00 +00:00
akwizgran
a901bfb9cb Merge branch '948-vector-crash' into 'master'
Remove scientific notation from vector drawables to prevent crashes

Closes #948

See merge request !537
2017-05-12 09:28:59 +00:00
akwizgran
03cdce122a Merge branch '947-bluetooth-address-crash' into 'master'
Don't crash on empty bluetooth addresses

See merge request !538
2017-05-12 09:26:57 +00:00
goapunk
f2e0e16969 Bring nullable annotation imports in line
Signed-off-by: goapunk <noobie@goapunks.net>
2017-05-12 10:06:56 +02:00
Torsten Grote
0c441e2ff3 Don't crash on empty bluetooth addresses 2017-05-10 15:06:09 -03:00
Torsten Grote
21302304a5 Remove scientific notation from vector drawables to prevent crashes
Details: http://stackoverflow.com/a/40829348
2017-05-10 14:56:59 -03:00
Torsten Grote
6839d8b844 Merge branch 'wifi-manager-memory-leak' into 'master'
Use application context to get WifiManager

See merge request !535
2017-05-10 17:01:52 +00:00
Torsten Grote
aee65a716c Merge branch '798-remove-contact-blogs' into 'master'
Allow to remove pre-shared blogs of our contacts

Closes #798

See merge request !529
2017-05-10 16:58:38 +00:00
Torsten Grote
6a07d8f2c9 Allow to remove pre-shared blogs of our contacts 2017-05-10 13:50:07 -03:00
Ernir Erlingsson
3c1ea81cd0 Merge branch '853-disabled-menu-items' into 'master'
Remove theme default color override

Closes #853

See merge request !527
2017-05-06 20:26:15 +00:00
Ernir Erlingsson
025f417bc7 Merge branch '894-list-position-restore' into 'master'
save and restore list position for threaded lists

Closes #894 and #946

See merge request !528
2017-05-06 19:37:02 +00:00
Ernir Erlingsson
c9dcd906c9 final pre-merge fixes 2017-05-06 21:36:25 +02:00
Ernir Erlingsson
7024e04d15 fixed final akwizgran comments 2017-05-06 21:31:53 +02:00
akwizgran
0b8ac947db Use application context to get WifiManager. 2017-05-05 15:43:27 +01:00
Ernir Erlingsson
948410a064 fixed unread buttons for threaded lists and akwizgran's comments 2017-05-05 14:49:53 +02:00
akwizgran
2841339cac Merge branch '468-ci' into 'master'
Set up basic CI

Closes #468

See merge request !530
2017-05-05 09:11:06 +00:00
Torsten Grote
e8e82bd805 Update Translations 2017-05-04 10:26:49 -03:00
Ernir Erlingsson
6876f40a0e Merge branch 'fix_groupname_validation' into 'master'
Fix groupname validation

See merge request !531
2017-05-04 07:26:55 +00:00
Ernir Erlingsson
5f4e1ecdfd improvements after code review #1
fix
2017-05-02 11:42:55 +02:00
Ernir Erlingsson
044719432a list position save and restore now implemented for threaded lists 2017-05-02 11:42:55 +02:00
Ernir Erlingsson
d1a929da85 bumped expire date 2017-05-02 11:42:15 +02:00
goapunk
2a8978a60d fix group name validation
Signed-off-by: goapunk <noobie@goapunks.net>
2017-04-29 16:49:37 +02:00
Torsten Grote
c0afad7a26 Set up basic CI 2017-04-28 13:24:41 -03:00
akwizgran
37281c6c23 Remove ellipsizing support from EmojiTextView.
This is a workaround for a layout bug.
2017-04-28 15:39:24 +01:00
Ernir Erlingsson
6de539a62d Merge branch '791-permanent-input' into 'master'
Show text input permanently in threaded conversations

Closes #791

See merge request !526
2017-04-27 10:38:58 +00:00
Ernir Erlingsson
34704ec04d Merge branch '874-tree-indicator' into 'master'
Darken thread indicator

Closes #874

See merge request !525
2017-04-26 08:38:52 +00:00
akwizgran
9fd6d46583 Merge branch '871-increase-socket-timeout' into 'master'
Increase socket timeout for Tor sockets

See merge request !519
2017-04-19 16:53:59 +00:00
akwizgran
76a5e25656 Added tests for wrapping and rewrapping blog posts. 2017-04-19 12:16:18 +01:00
akwizgran
3575b74837 Store correct original parent ID when rewrapping blog posts. 2017-04-19 12:15:34 +01:00
Torsten Grote
f1c7996960 Remove theme default color override 2017-04-18 09:14:00 -03:00
Torsten Grote
920f3581fa Show text input permanently in threaded conversations 2017-04-17 16:22:24 -03:00
Torsten Grote
45e7af31fe Darken thread indicator 2017-04-17 16:14:26 -03:00
Torsten Grote
67d5d8cdf1 Merge branch '941-reblogged-rss-post-has-wrong-icon' into 'master'
Store RSS flag for wrapped blog posts

Closes #941

See merge request !524
2017-04-17 18:23:41 +00:00
Torsten Grote
9d8cadb7a9 Merge branch 'use-original-timestamp-for-rss-posts' into 'master'
Use original timestamp for RSS posts, if available

See merge request !523
2017-04-17 18:22:10 +00:00
Torsten Grote
6425c49d04 Merge branch 'remove-single-top-flag' into 'master'
Don't use single top and clear top flags together

See merge request !522
2017-04-17 18:20:46 +00:00
Torsten Grote
68d98b50f2 Merge branch '938-ignore-play-services-overlay-permission' into 'master'
When checking for overlay apps, ignore Play Services

Closes #938

See merge request !521
2017-04-17 18:19:46 +00:00
akwizgran
84986d393f Added a test for #941, fixed some broken tests. 2017-04-13 17:28:45 +01:00
akwizgran
115d488bc3 Clamp the imported timestamp within reasonable limits. 2017-04-13 16:21:00 +01:00
akwizgran
2eeb2213e3 Store RSS flag for wrapped blog posts. 2017-04-13 15:23:08 +01:00
akwizgran
1b48d661e8 Use original timestamp for RSS posts, if available. 2017-04-13 14:43:43 +01:00
akwizgran
49ba66dee9 Don't use single top and clear top flags together. 2017-04-13 13:56:20 +01:00
akwizgran
46920f3bce Merge branch '892-separate-rss-blog' into 'master'
Separate RSS posts from personal blog posts

Closes #892

See merge request !520
2017-04-13 10:15:00 +00:00
Torsten Grote
4b955809f7 Address review comments 2017-04-12 15:18:27 -03:00
akwizgran
57d4d6546a When checking for overlay apps, ignore Play Services. 2017-04-12 14:24:37 +01:00
Torsten Grote
9bfb58a764 Show blog posts from RSS feeds with a dedicated icon
This adds a field to the post headers and some more tests.
2017-04-12 08:43:24 -03:00
Torsten Grote
0256ec0b8c Show reblog icon only for reblogged posts 2017-04-12 08:43:23 -03:00
Torsten Grote
b0b4a85d15 Add integration test for FeedManager
Attention: This factors out a DnsModule to be able to make actual
non-Tor DNS lookups for testing.
2017-04-12 08:43:23 -03:00
Torsten Grote
d40a058ef5 Change blog descriptor format to include RSS feed flag
This now also handles the case where an RSS blog is deleted via the blog
deletion option and not the feed management.
2017-04-12 08:43:22 -03:00
Torsten Grote
58b9efb24c Open feed's blog when clicking it in 'manage activity' 2017-04-12 08:43:22 -03:00
Torsten Grote
17de785c12 Remove blog as well when removing RSS feed
This also adds a confirmation dialog to the removal process.
2017-04-12 08:43:21 -03:00
Torsten Grote
c7ff1ba974 Store RSS feeds in a separate dedicated blog
A fake LocalAuthor is created for this new blog and stored in the feed's metadata.
2017-04-12 08:43:21 -03:00
akwizgran
d17669f131 Increase socket timeout for Tor sockets. 2017-04-11 14:53:03 +01:00
akwizgran
9755cd9ab4 Merge branch '891-messages-not-acked' into 'master'
Fix MessageId calculation for deprecated MessageQueue

Closes #891

See merge request !514
2017-04-11 12:49:44 +00:00
akwizgran
6d2b18facc Merge branch '799-explain-content-visibility' into 'master'
Show explanation about visibility in member lists

Closes #799

See merge request !516
2017-04-07 14:54:41 +00:00
Torsten Grote
f8cf7034db Show explanation about visibility in member lists 2017-04-07 11:38:33 -03:00
akwizgran
a1e65c9fa7 Merge branch '893-double-introduction-accept' into 'master'
Prevent conversation actions from being executed twice

Closes #893

See merge request !512
2017-04-07 14:03:40 +00:00
Torsten Grote
499d2fe677 Prevent conversation actions from being executed twice 2017-04-07 10:00:55 -03:00
Torsten Grote
fe963edd9d Merge branch '829-new-launcher-icon' into 'master'
Use the new launcher icon

Closes #829

See merge request !515
2017-04-07 12:59:35 +00:00
akwizgran
96f006068f Use the new launcher icon. 2017-04-07 13:57:13 +01:00
akwizgran
74f1fa5690 Merge branch '932-panic-button-terminate-process' into 'master'
Terminate the process after handling a panic trigger

Closes #932

See merge request !513
2017-04-07 12:49:52 +00:00
Torsten Grote
85c17b4cb0 Fix MessageId calculation for deprecated MessageQueue
This was preventing introduction messages from getting ACKed.
The introduction tests were modified to check for this.
2017-04-07 09:45:35 -03:00
akwizgran
6b3a1fd6d4 Merge branch 'fix-test-configuration' into 'master'
Fix "all tests" configuration

See merge request !509
2017-04-07 10:19:01 +00:00
akwizgran
bcabcfce8c Merge branch '925_panic_app_market' into 'master'
Refine the panic app list tap behavior

Closes #925

See merge request !511
2017-04-07 10:17:48 +00:00
goapunk
db0a3bf380 Refine the panic app list behavior
* Only open if a market is installed

Signed-off-by: goapunk <noobie@goapunks.net>
2017-04-07 12:07:10 +02:00
akwizgran
d5d9436e28 Terminate the process after handling a panic trigger. 2017-04-07 10:54:51 +01:00
Torsten Grote
0827b067ec Harmonize position of boolean message variables 2017-04-06 15:42:12 -03:00
akwizgran
9d0dbe9210 Merge branch '885_store_only_four_lan_ip' into 'master'
Store only 4 ip addresses because 5 exceed the maximum length.

Closes #885

See merge request !510
2017-04-06 14:38:49 +00:00
akwizgran
1f7d1bf515 Merge branch '675-polite-executor' into 'master'
Use a polite executor for validation tasks

Closes #675

See merge request !507
2017-04-06 14:37:59 +00:00
akwizgran
fb85ecf07b Added note about number of available processors changing. 2017-04-06 15:34:39 +01:00
akwizgran
a931e6b316 Merge branch '906_tapjacking' into 'master'
Add tapjacking protection

Closes #906

See merge request !502
2017-04-06 14:31:10 +00:00
akwizgran
3aa4644339 If we have multiple cores, leave one free from crypto tasks. 2017-04-06 11:36:02 +01:00
goapunk
9a638c804a Store only 4 ip addresses because 5 exceed the maximum length.
Signed-off-by: goapunk <noobie@goapunks.net>
2017-04-06 12:35:44 +02:00
akwizgran
df3254c634 Fix "all tests" configuration.
The last (empty) stage of this configuration used to
complain about not finding any tests. I replace the last
stage with a copy of the briar-android configuration
and removed briar-android from the list of prerequisites,
so all stages now contain tests.
2017-04-06 10:18:42 +01:00
akwizgran
ba353b9f2b List of wifi configs can be null. 2017-04-06 10:11:59 +01:00
goapunk
04c4e70dd1 Add tapjacking protection
* Set filterTouchesWhenObscured for all views
* Warn the user if Apps using the SYSTEM_ALERT_WINDOW permission are installed
* Warn the user if an App using the permission is installed while Briar is running

Signed-off-by: goapunk <noobie@goapunks.net>
2017-04-05 23:25:57 +02:00
akwizgran
d381e25e86 Limit the number of validation tasks on the crypto executor. 2017-04-05 17:34:21 +01:00
akwizgran
0c085f139a Added "polite" delegating executor. 2017-04-05 17:34:20 +01:00
akwizgran
4123f4a5ce Log time spent queueing and executing crypto and DB tasks. 2017-04-05 17:34:15 +01:00
akwizgran
7bc269fda4 Merge branch '914-simpler-secure-random' into 'master'
Remove Fortuna generator, fix Android SecureRandom bug

Closes #914

See merge request !500
2017-04-05 10:55:25 +00:00
akwizgran
a22931bae6 Merge branch '928-move-html-sanitation-to-dbthread' into 'master'
Move HTML Sanitation to DbThread

Closes #928

See merge request !506
2017-04-04 16:54:21 +00:00
akwizgran
403f886110 Merge branch '910-fix-intent-hijacking' into 'master'
Fix possible intent hijacking for implicit pending intents

Closes #910

See merge request !499
2017-04-04 16:34:38 +00:00
Torsten Grote
b7866be38d Move HTML Sanitation to DbThread 2017-04-04 13:27:06 -03:00
akwizgran
a1b415330e Merge branch '926-class-cast-exception' into 'master'
Don't cast Context to BaseActivity

Closes #926

See merge request !505
2017-04-04 12:44:38 +00:00
Torsten Grote
58318bb79f Remove pending intents for clearning notification counters
These counters are already reset when the user clicks the notification
or vists the area of the app the notifications are for.

This also removes a potential intent hijacking vulnerability.
2017-04-04 09:02:38 -03:00
akwizgran
10bb30e190 Don't assume Context is a BaseActivity. 2017-04-03 12:22:52 +01:00
akwizgran
199a2ffc46 Merge branch '909-prevent-multiple-password-screens' into 'master'
Prevent multiple instances of PasswordActivity

Closes #909

See merge request !504
2017-03-31 13:42:04 +00:00
akwizgran
f6ad2992f2 Prevent multiple instances of PasswordActivity. 2017-03-31 12:55:38 +01:00
akwizgran
f039bd1239 Merge branch '909-restrict-access-to-panic-prefs' into 'master'
Don't allow other apps to open the panic prefs activity

See merge request !503
2017-03-31 08:25:21 +00:00
Torsten Grote
da22d91ef3 Update expiry date and translations 2017-03-30 15:35:02 -03:00
Torsten Grote
cd360ec877 Merge branch '909-restrict-access-to-settings-activity' into 'master'
Require a system permission to open the settings activity

See merge request !501
2017-03-30 12:58:07 +00:00
akwizgran
8e1ada4cdc Don't allow other apps to open the panic prefs activity. 2017-03-30 12:26:33 +01:00
akwizgran
ac063b4c79 Require a system permission to open the settings activity. 2017-03-30 12:00:35 +01:00
akwizgran
10e6163e94 Merge branch '915-fix-forumactivitytest' into 'master'
Fix ForumActivityTest

Closes #915

See merge request !496
2017-03-30 08:19:30 +00:00
Torsten Grote
ebc3402307 Merge branch '912-validate-stream-encrypter-args' into 'master'
Validate arguments to StreamEncrypter#writeFrame()

Closes #912

See merge request !497
2017-03-29 16:52:54 +00:00
akwizgran
d9c63bbcfe Remove Fortuna generator, fix Android SecureRandom bug. 2017-03-29 16:31:59 +01:00
akwizgran
9c89e83c20 Merge branch '913-simpler-password-strength-estimation' into 'master'
Simpler password strength estimation

Closes #913

See merge request !495
2017-03-29 15:01:44 +00:00
akwizgran
adc9bdeb68 Merge branch 'run-configurations' into 'master'
Run configurations for tests

See merge request !498
2017-03-29 08:18:05 +00:00
akwizgran
ff7f0bdc63 Added run configurations for tests to git. 2017-03-28 15:36:18 +01:00
Torsten Grote
c5f6980c69 Fix ForumActivityTest 2017-03-28 09:34:42 -03:00
akwizgran
2574354997 Merge branch '905_set_testing_constant_on_debug' into 'master'
Set TESTING from BuildConfig

Closes #905

See merge request !494
2017-03-28 12:30:00 +00:00
akwizgran
c4e42949cf Simpler password strength estimation. 2017-03-28 13:27:04 +01:00
goapunk
1c5897f1cc Set TESTING from BuildConfig
Signed-off-by: goapunk <noobie@goapunks.net>
2017-03-27 23:39:39 +02:00
akwizgran
510f99c7da Validate arguments to StreamEncrypter#writeFrame(). 2017-03-27 16:26:49 +01:00
akwizgran
1918346ae8 Merge branch '911-link-sanitation' into 'master'
Sanitize all HTML before displaying it

Closes #911

See merge request !493
2017-03-27 09:45:17 +00:00
akwizgran
2a59515c72 Merge branch '907-panic-signout' into 'master'
Require a panic app to be set before executing any panic actions

Closes #907

See merge request !492
2017-03-27 09:43:30 +00:00
akwizgran
7161152b41 Merge branch '903_replace_Runtime_with_ProcessBuilder' into 'master'
Use ProcessBuilder instead of Runtime to start tor

See merge request !487
2017-03-27 09:37:00 +00:00
akwizgran
b42660edab Merge branch 'emoji-soft-reference' into 'master'
Fix potential NPE when getting soft reference

See merge request !490
2017-03-27 09:28:30 +00:00
akwizgran
b405bbf98e Merge branch 'setting-to-disable-tor' into 'master'
Add a setting to disable Tor

See merge request !489
2017-03-27 09:27:56 +00:00
akwizgran
c167938b61 Use constants for Tor network setting values. 2017-03-27 10:26:10 +01:00
Torsten Grote
24b531e6b2 Sanitize all HTML before displaying it 2017-03-24 16:45:36 -03:00
Torsten Grote
9cffff715a Require a panic app to be set before executing any panic actions 2017-03-24 16:19:09 -03:00
Torsten Grote
804e912e19 Merge branch 'remove-placeholder-tests' into 'master'
Remove placeholder tests

See merge request !491
2017-03-24 18:12:13 +00:00
akwizgran
d67e3900e3 Removed placeholder tests.
Evidently this way of nagging myself to write tests doesn't work.
2017-03-24 15:18:37 +00:00
akwizgran
e682f31898 Added a setting to disable Tor.
Also fixed a bug with settings namespaces.
2017-03-24 14:56:30 +00:00
akwizgran
a9053808b4 Merge branch '908-rss-import-dns-leak' into 'master'
Don't make DNS lookups during RSS import

Closes #908

See merge request !488
2017-03-24 10:02:19 +00:00
akwizgran
d9a62a0431 Merge branch 'print_tor_errors' into 'master'
Make Tor boot more verbose

See merge request !486
2017-03-24 10:01:29 +00:00
akwizgran
15ba73276d Merge branch '900-remove-error-state' into 'master'
Remove error state and reset session on error instead

Closes #900

See merge request !484
2017-03-24 09:57:03 +00:00
Torsten Grote
720dda784e Remove error state and reset session on error instead 2017-03-23 14:14:23 -03:00
akwizgran
0ae55404f5 Merge branch '900-simplify-sharing-client-state-machine' into 'master'
Remove REMOTE_LEFT state from sharing client state machine

See merge request !483
2017-03-23 16:13:44 +00:00
akwizgran
9c41437870 Prevent OkHttp from making local DNS lookups. 2017-03-23 15:13:15 +00:00
akwizgran
da9cde083f Include description of SOCKS error in exception. 2017-03-23 15:13:15 +00:00
goapunk
ce3156c9fe Use ProcessBuilder instead of Runtime to start tor
* ProcessBuilder copies the ENV from the current proc
  and preserves ANDROID_ROOT and ANDROID_DATA

Signed-off-by: goapunk <noobie@goapunks.net>
2017-03-18 09:46:24 +01:00
goapunk
be3752bf2f Set Android env vars
Signed-off-by: goapunk <noobie@goapunks.net>

(cherry picked from commit e26f663)
2017-03-17 16:00:34 +00:00
noobie
ef74db65aa Make Tor boot more verbose
Signed-off-by: noobie <noobie@goapunks.net>
2017-03-13 12:19:14 +01:00
Torsten Grote
867a233b6f Update expiry 2017-03-06 18:46:15 +01:00
Torsten Grote
36f02b36d9 Update expiry and translations 2017-02-01 11:17:53 -02:00
Torsten Grote
59af25b2cd Remove REMOTE_LEFT state from sharing client state machine 2017-01-12 15:19:28 -02:00
akwizgran
2fb11fba2a Merge branch '877-save-invitation-outcome-to-invitation-message-and-make-available-to-ui' into 'master'
Store invitation outcome in metadata and make it available to the UI

This MR is based on !479 and should only be merged after that one has been merged as well.

It stores the invitation outcome in the message metadata  and includes it in the `canBeOpened()` calculation for private groups and sharables.

Closes #877

See merge request !480
2017-01-06 16:06:19 +00:00
akwizgran
1d11857e75 Merge branch '476-blog-sharing-protocol-modifies-state-external-to-session' into 'master'
Migrate blog sharing to new sharing client infrastructure

This MR contains a second small commit that fixes #816 and adds a test for it.

Closes #476, #701

See merge request !479
2017-01-06 16:04:17 +00:00
Torsten Grote
04508a7431 Store invitation outcome in metadata
and include in canBeOpened calculation for private groups and sharables.
2017-01-06 13:29:21 -02:00
Torsten Grote
5653c6d650 Address review comments 2017-01-06 13:25:13 -02:00
Torsten Grote
ab100ad19b Properly remove the blog when deleting a contact and inform all peers
Fixes #816
2017-01-06 13:01:37 -02:00
Torsten Grote
c13eafef14 Migrate blog sharing to new sharing client infrastructure 2017-01-06 13:01:34 -02:00
akwizgran
d5443e9651 Merge branch '889-select-navdrawer-item-when-coming-from-notification' into 'master'
Check the blog item in NavDrawer when opening a blog via notification

There are three scenarios where the selected item in the NavDrawer changes:
1. The user selects an item -> the item is checked automatically.
2. The user pressed back -> already handled in onBackPressed (needs to be extended with #606)
3. The user touched a notification -> handled by this commit.
   
Signed-off-by: goapunk <noobie@goapunks.net>

Closes #889

See merge request !481
2017-01-06 14:59:21 +00:00
akwizgran
d5f9a3280d Merge branch 'briar-recycler-view-log' into 'master'
Stop periodic list update only once

When testing the forum unread code, I noticed the recycler view is detaching twice. Once because the stop method is called and once because the view detaches from the window. Wouldn't it be safe to null the refresher when the updates are stopped?

See merge request !478
2017-01-06 14:15:48 +00:00
goapunk
09b2ecaecf Check the corresponding NavDrawer item when coming from a notification
Signed-off-by: goapunk <noobie@goapunks.net>
2017-01-06 15:12:40 +01:00
Torsten Grote
dc6a6f27ab Fix MessageTreeImplTest 2017-01-04 16:27:49 -02:00
Torsten Grote
8d9ddeeeee Stop periodic list update only once 2017-01-04 11:15:19 -02:00
Torsten Grote
baed2b8483 Merge branch '879-remove-thread-collapsing-unread-count' into 'master'
Remove code for collapsing threads and for reply count

Besides removing lots of code, this MR also improves the encapsulation between adapter and view holders.

Closes #478, #502, #526, #682,  #683,  #835,  #836

See merge request !477
2017-01-04 13:00:16 +00:00
Torsten Grote
b3d3230549 Remove code for collapsing threads and for reply count 2017-01-04 10:58:31 -02:00
akwizgran
deb8787668 Merge branch '879-threaded-unread-messages' into 'master'
Threaded Unread Handling

![unread](/uploads/457c3bc36c897d683ff8161b4f3a344c/unread.mp4)

This leaves in the collapsing code for now and just hides the UI element for collapsing. The code can be removed in a second pass to simplify the adapter.

Closes #879

See merge request !476
2017-01-04 11:12:24 +00:00
Torsten Grote
7034ea28f3 Merge branch '475-new-sharing-client' into 'master'
New Forum Sharing Client

This is very similar to how the private group invitations work and I am sure there's still some tiny bugs that I didn't catch.

All existing integration tests either pass or have been modified to pass.

Once this has been merged, the code should be usable for blog sharing as well.

Closes #475

See merge request !467
2017-01-03 19:30:48 +00:00
Torsten Grote
51b78cf9b1 Address review comments for new sharing client 2017-01-03 17:25:45 -02:00
Torsten Grote
b4c669243b Add UnreadMessageButton to threaded conversations 2017-01-03 13:25:31 -02:00
Torsten Grote
694e662028 New Forum Sharing Client 2017-01-03 11:23:02 -02:00
Torsten Grote
409e0fb5a5 ForumSharingValidator 2017-01-03 11:23:00 -02:00
Torsten Grote
279f4d668a Add new UnreadMessageButton class 2017-01-02 16:30:00 -02:00
akwizgran
d2608e28ac Merge branch '881-forumactivitytest-fails-due-to-custom-toolbar' into 'master'
Fix ForumActivityTest and get rid of redundant theme definition

Closes #881

See merge request !474
2017-01-02 14:22:27 +00:00
akwizgran
8cf02c5f0e Merge branch '851-refresher-memory-leak' into 'master'
Fix memory leaks caused by periodic view refreshing tasks

This branch implements @goapunk's suggested solution to #851. Credit goes to @ernir for finding the bug and the initial solution, and @goapunk for the improved solution - I just did a quick implementation so we can get this fixed as quickly as possible.

Closes #851

See merge request !473
2017-01-02 14:10:32 +00:00
Torsten Grote
c5df2100da Fix ForumActivityTest and get rid of redundant theme definition 2017-01-02 11:57:45 -02:00
akwizgran
a6999a8197 Merge branch '710-conversationactivity-uses-uninitialised-field-as-format-string-argument' into 'master'
Make sure contact name is initialized when needed

This uses a Listenable Future and unfortunately requires 4 basically identical methods to handle the incoming events. Any suggestions for improving that are welcome.

Closes #710

See merge request !472
2017-01-02 11:11:41 +00:00
akwizgran
da89f11419 Merge branch '882-feedmanagerimpl-logs-rss-feed-urls' into 'master'
Do not log information from RSS feeds

Closes #882

See merge request !475
2017-01-02 10:52:04 +00:00
Torsten Grote
a9663875f4 Update expiry date and translations 2016-12-30 12:13:43 -02:00
Torsten Grote
804966ede6 Do not log information from RSS feeds 2016-12-29 13:07:18 -02:00
Torsten Grote
f0f22b42e5 Make sure contact name is initialized when needed 2016-12-29 12:29:32 -02:00
akwizgran
59316ae3c4 Fix memory leaks caused by periodic view refreshing tasks. 2016-12-28 15:23:21 +00:00
akwizgran
79c78518fb Fix potential NPE when getting soft reference. 2016-12-28 13:47:33 +00:00
Torsten Grote
460b524e4b Merge branch 'record-reading-tests' into 'master'
Unit tests for record readers

I thought we should have some tests for the new logic that skips unrecognised record types.

See merge request !471
2016-12-21 17:14:16 +00:00
akwizgran
48e949c9f8 Merge branch '742-use-unique-request-ids-across-the-app' into 'master'
Use unique request codes across the app

Closes #742

See merge request !470
2016-12-21 15:33:03 +00:00
Torsten Grote
924398c829 Use unique request codes across the app 2016-12-21 12:52:11 -02:00
akwizgran
8619b044ce Merge branch '469-handle-background-errors' into 'master'
Add a handleDbException() method to BaseActivity

This adds a `handleDbException()` method to BaseActivity and a corresponding method for fragments that calls through to the activity.
For now, the method just finishes the activity
and NavDrawerActivity overrides it to do nothing,
and all the error places marked with TODO that finish the activity call the method instead.

That gives us zero functional improvement over the status quo,
but it allows us to change the default behaviour easily,
and then we can start thinking about which cases should have non-default behaviour.

First part of #469

See merge request !469
2016-12-21 14:46:53 +00:00
akwizgran
3c3731a562 Merge branch '876-group-invitation-not-marked-unavailable' into 'master'
Mark invitation unavailable to answer when creator dissolved the group after the invitation.

Closes #876

See merge request !468
2016-12-21 14:43:38 +00:00
akwizgran
b54984b542 Unit tests for RecordReaderImpl. 2016-12-21 14:39:56 +00:00
akwizgran
2390f767f5 Unit tests for KeyAgreementTransport. 2016-12-21 14:08:21 +00:00
Torsten Grote
0a9840997f This adds a handleDbException() method to BaseActivity
and a corresponding method for fragments that calls through to the activity.
For now, the method just finishes the activity
and NavDrawerActivity overrides it to do nothing,
and all the error places marked with TODO that finish the activity call the method instead.

That gives us zero functional improvement over the status quo,
but it allows us to change the default behaviour easily,
and then we can start thinking about which cases should have non-default behaviour.
2016-12-21 12:06:20 -02:00
Torsten Grote
6a94785d9a Mark invitation unavailable to answer when creator dissolved the group
after the invitation.

Closes #876
2016-12-21 11:24:08 -02:00
akwizgran
79fc41477c Merge branch '628-bring-protocols-into-line-with-spec' into 'master'
Bring protocols in line with spec

Closes #628

See merge request !465
2016-12-21 12:52:43 +00:00
Torsten Grote
efb89adf41 Merge branch '793-show-open-button-after-accepting-invitations' into 'master'
Show open button in private conversation after accepting invitations

To keep the implementation simple, the Open button does appear where the Accept button had been previously.

In order to make the Open button functional, I had to make the `GroupId` of the invitation target available to the UI. Most code in this MR is due to that.

![device-2016-12-13-105228](/uploads/d0f27fc02f1411596458d9203a0810d2/device-2016-12-13-105228.png)

Closes #793

See merge request !457
2016-12-20 14:07:13 +00:00
Torsten Grote
c04580e321 Don't open unsubscribed shareables 2016-12-20 12:00:01 -02:00
Torsten Grote
2ef9b8f4b6 Show open button in private conversation after accepting invitations 2016-12-20 08:47:27 -02:00
akwizgran
d63d15329c Merge branch '814-enable-QrScanner-after-QrCode-was-created' into 'master'
Ignore QR code results until local QR code is created

* Make scanning only possible after we are "ready" (= our QrCode was created and set).

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #814

See merge request !454
2016-12-19 19:28:14 +00:00
Torsten Grote
5345db0b6b Address review comments 2016-12-19 11:15:53 -02:00
Torsten Grote
501980d8fe Bring protocols in line with spec 2016-12-19 10:26:48 -02:00
akwizgran
cc5c000278 Merge branch '738-older-devices-show-overflow-icon-on-some-screens-but-not-others' into 'master'
Also show overflow icon on devices with menu key by using Toolbar

Closes #738

See merge request !463
2016-12-16 11:58:18 +00:00
akwizgran
3ce0131b8c Merge branch '828-update-briar-logo-in-app' into 'master'
Update all logos

The launcher icons are now in mipmap folders which is the recommended practice, because on a low-res device, the high res drawables are stripped from the app. This is bad when the user decides to show the app icons really big on the launcher and the high-res drawables are not available anymore.

The old launcher icon seemed to have some sort of 3D effect.
![device-2016-12-13-134037](/uploads/84db532df3821ad74ba57719f0763b7b/device-2016-12-13-134037.png)

Navigation Drawer Old:
![device-2016-12-13-124112](/uploads/465b817d2e0bbbd50b461ea32686c933/device-2016-12-13-124112.png)
Navigation Drawer New:
![device-2016-12-13-132428](/uploads/3c3530bfc515525dd8f66abfa52d1142/device-2016-12-13-132428.png)

Closes #828

See merge request !459
2016-12-15 23:25:40 +00:00
akwizgran
008e4f760a Merge branch '795-use-different-notification-icons-for-different-features' into 'master'
Use different notification icons for different features

![device-2016-12-13-151008](/uploads/2c9aa33c230738b5ea20a76ac5e3b214/device-2016-12-13-151008.png)
![device-2016-12-13-150954](/uploads/85acd46fc6afd3aebcc1fcd015b041d7/device-2016-12-13-150954.png)

Closes #795

See merge request !460
2016-12-15 23:16:36 +00:00
akwizgran
fc44268b22 Removed translations of unused strings. 2016-12-15 23:12:24 +00:00
akwizgran
de0a7c75ed Merge branch '697-include-commit-id-in-crash-reports-and-feedback' into 'master'
Include Commit ID in crash reports and feedback

Closes #697

See merge request !461
2016-12-15 23:06:24 +00:00
Torsten Grote
1c6be2fb78 Include Commit ID in crash reports and feedback 2016-12-15 15:40:52 -02:00
Torsten Grote
09b0a8b161 Use different notification icons for different features
and use the primary color for the notification.
2016-12-15 15:29:48 -02:00
Torsten Grote
a6d053a0ea Update all logos 2016-12-15 15:19:38 -02:00
akwizgran
e7a26c42a4 Merge branch '285-plugins-should-throw-exceptions-for-startup-errors' into 'master'
Plugins throw exceptions for startup errors

Please review carefully as I don't know much about the code I have touched here.

Closes #285

See merge request !462
2016-12-15 14:33:35 +00:00
akwizgran
bb5fc35e17 Removed translations of unused strings. 2016-12-15 10:56:04 +00:00
Torsten Grote
ea4e2f09c8 Revert dagger update 2016-12-14 16:52:38 -02:00
Torsten Grote
ffc9fdbb92 Plugins throw exceptions for startup errors 2016-12-14 16:35:23 -02:00
akwizgran
074f5c2faf Fix imports in HashTest. 2016-12-14 17:09:15 +00:00
goapunk
7666b210e4 Ignore results from the QrScanner if task is not ready
* Ignore results until the KeyAgreementTask is ready and returned the local payload

Signed-off-by: goapunk <noobie@goapunks.net>
2016-12-14 17:28:01 +01:00
akwizgran
ab3fcb6219 Merge branch 'add-crypto-hash-test' into 'master'
Add Unit tests for CryptoComponent#hash()

See merge request !464
2016-12-14 16:14:18 +00:00
akwizgran
b7e35ff780 Merge branch '778-move-unit-tests-into-their-respective-modules' into 'master'
Move all unit tests to their modules and remove briar-tests

There are now tests in these modules:
* bramble-api
* bramble-core
* bramble-j2se
* briar-core
* briar-android

In order to run all -core tests together, the following AS run configuration can be used:
![Screenshot_2016-12-12_16-37-53](/uploads/8c706406f015ecd9e2371ebc28e6b34c/Screenshot_2016-12-12_16-37-53.png)

Closes #778

See merge request !456
2016-12-14 15:57:45 +00:00
akwizgran
3c2428449d Moved test utility classes into test package. 2016-12-14 15:42:52 +00:00
Torsten Grote
25a4caec2a Add Unit tests for CryptoComponent#hash() 2016-12-14 13:15:44 -02:00
Torsten Grote
db71472501 Also show overflow icon on devices with menu key by using Toolbar 2016-12-14 11:17:04 -02:00
Torsten Grote
1081a08ea9 Move all unit tests to their modules and remove briar-tests 2016-12-13 17:22:24 -02:00
akwizgran
32be148c7a Merge branch '646-shared-with-subtitle-groups' into 'master'
Add sharing information to private group ActionBar subtitle

![device-2016-12-12-114533](/uploads/b31fc37643ef6e817a80a4ddd767fe98/device-2016-12-12-114533.png)

Closes #646

See merge request !455
2016-12-13 18:01:48 +00:00
Torsten Grote
78000375df Merge branch '155-notification-icon' into 'master'
Make notification icon less similar to superuser icon

Closes #155

See merge request !458
2016-12-13 17:24:05 +00:00
akwizgran
66f8978bb6 Make notification icon less similar to superuser icon. 2016-12-13 17:20:48 +00:00
Torsten Grote
45b5040254 Add sharing information to private group ActionBar subtitle 2016-12-12 13:55:35 -02:00
Torsten Grote
378a8f0a10 Merge branch '813-add-online-status-and-creator-information-to-group-memberlist' into 'master'
Add creator and online information to group member list

![device-2016-12-06-102258](/uploads/90e19a6ca31aaf91c6ebf3ea8e218b3f/device-2016-12-06-102258.png)
![device-2016-12-06-110113](/uploads/3fd62f7cdfe75419a07262356d27b952/device-2016-12-06-110113.png)

Closes #813

See merge request !448
2016-12-12 15:36:02 +00:00
Torsten Grote
562866494b Add creator and online information to group member list 2016-12-12 13:33:23 -02:00
akwizgran
c9cb085a0a Merge branch '777-move-integration-tests-into-their-respective-modules' into 'master'
Move integration tests to their proper packages

Closes #777

See merge request !453
2016-12-12 15:08:26 +00:00
Torsten Grote
97d4c68f43 Move integration tests to their proper packages 2016-12-12 10:27:41 -02:00
Torsten Grote
4226ba40c2 Merge branch '570-consistent-use-of-animations' into 'master'
Make animations more consistent

![animations6](/uploads/0ac694d3561515e04fbb9032d31f183c/animations6.mp4)

Closes #570, #621

See merge request !439
2016-12-09 16:49:26 +00:00
Torsten Grote
3df3d19a07 Address review comments 2016-12-09 14:40:20 -02:00
Torsten Grote
e3dcc62509 Use back transition when backing out of creating private group 2016-12-09 14:22:05 -02:00
Torsten Grote
db3c3eee44 Move OnBlogPostClickListener from activity to fragment 2016-12-09 14:22:03 -02:00
Torsten Grote
5a522d64df Don't show splash screen when signed in
This also removes the BriarFragmentActivity that was only really used by
the NavDrawerActivity.
2016-12-09 14:14:47 -02:00
Torsten Grote
68b216d580 Make animations more consistent 2016-12-09 14:13:18 -02:00
Torsten Grote
d5c6fcc85b Fix merge accident after renaming event 2016-12-09 14:12:27 -02:00
Torsten Grote
a099104d08 Merge branch '646-shared-with-subtitle-forums' into 'master'
Add sharing info to ForumActivity action bar subtitle

This indirectly does also most of the work for adding the same information to private groups. However, completing this is blocked by !448.

![device-2016-12-07-152915](/uploads/5bb42f2e78a87931b0307e7597ba72c5/device-2016-12-07-152915.png)

Second part of #646

See merge request !451
2016-12-09 16:06:21 +00:00
akwizgran
787b3399f7 Merge branch '646-shared-with-subtitle' into 'master'
Add blog sharing information to toolbar subtitle

This MR introduces a new `SharingController` which is supposed to be used in activities that show blogs, groups and forums. Feedback on this approach is welcome before this is used to add "Shared with" support to other parts of the UI.

The toolbar subtitle shows information about how many contacts the current shareable is shared with and how many of those are online.

So far this is implemented for blogs:

![device-2016-12-05-180207](/uploads/13afb4c7c5d10ad29c414865ee02670d/device-2016-12-05-180207.png)

One part of #646

See merge request !447
2016-12-09 16:04:04 +00:00
Torsten Grote
4e159bbb1f Add sharing info to ForumActivity action bar subtitle 2016-12-09 14:02:42 -02:00
Torsten Grote
7c6232db9d Address review comments (rename event, fix annotations, final field) 2016-12-09 13:54:39 -02:00
Torsten Grote
6cf1480d2d Merge branch '766-unit-tests-for-peer-protocol-engine' into 'master'
Add unit tests for PeerProtocolEngine

Although not all classes have unit tests, this

Closes #766

See merge request !450
2016-12-08 16:14:34 +00:00
Torsten Grote
2679e6932f Add unit tests for PeerProtocolEngine 2016-12-08 14:13:00 -02:00
akwizgran
17e149e517 Merge branch '766-unit-tests-for-invitee-protocol-engine' into 'master'
Add unit tests for InviteeProtocolEngine

Next part of #766

See merge request !444
2016-12-08 15:42:05 +00:00
Torsten Grote
d04dda1566 Add sharing information to toolbar subtitle of blogs
The toolbar subtitle shows information about how many contacts the
current blog is shared with and how many of those are online.
2016-12-07 15:16:44 -02:00
Torsten Grote
5588855667 Fix intent of some CreatorProtocolEngine unit tests 2016-12-07 15:07:01 -02:00
Torsten Grote
7df6abbcbe Merge branch '810-fix-sharing-status-screens' into 'master'
Fix Sharing Status screens

* Remove distinction between "shared with" and "shared by"
* Show all contacts a blog is shared with
* Show online status of contacts in sharing screen

![device-2016-12-05-142949](/uploads/703fbd2d52815374e57edd89f754bf6c/device-2016-12-05-142949.png)

Closes #810

See merge request !445
2016-12-07 16:52:29 +00:00
Torsten Grote
001f5faeaa Two small review details: comment and initializing boolean 2016-12-07 14:49:57 -02:00
Torsten Grote
ba1a19d236 Address review issues 2016-12-07 14:31:24 -02:00
Torsten Grote
b7ce7de42a Add unit tests for InviteeProtocolEngine 2016-12-07 14:31:23 -02:00
akwizgran
3f6a8f9341 Merge branch '808-introduction-client-logs-contact-names' into 'master'
Remove verbose logging from introduction client

Closes #808

See merge request !449
2016-12-07 15:49:14 +00:00
akwizgran
9495163016 Merge branch 'onboarding-dialog-style' into 'master'
Introduce Dialog Theme for Onboarding

Currently onboarding dialogs and confirmation dialogs look the same. This MR introduces a new dialog theme for onboarding dialogs that looks like the tap target onboarding, so that the user can immediately spot the purpose of the dialog.

![device-2016-12-06-085539](/uploads/6d75b17c0f20028bb7ffac65e6fba03a/device-2016-12-06-085539.png)

See merge request !446
2016-12-07 15:47:12 +00:00
Torsten Grote
7f5a5d40dc Remove verbose logging from introduction client 2016-12-06 15:36:54 -02:00
Torsten Grote
98dd8ec7f7 Fix Sharing Status screens
* Remove distinction between "shared with" and "shared by"
* Show all contacts a blog is shared with
* Show online status of contacts in sharing screen
2016-12-06 10:53:50 -02:00
akwizgran
27c2ee8d89 Merge branch '548-require-a-label-for-hashing' into 'master'
Require a label for hashing

* Add a string label argument to `CryptoComponent#hash()`
* Convert `DoubleDigest` from implementing `MessageDigest`
  to implementing `org.spongycastle.crypto.Digest`
  (we need to keep `DoubleDigest` for `FortunaGenerator`)
* Convert all other uses of `MessageDigest` to `CryptoComponent#hash()`
* Remove `CryptoComponent#getMessageDigest()`, `MessageDigest` and `DigestWrapper`

Closes #548

See merge request !442
2016-12-06 11:07:58 +00:00
Torsten Grote
b98ab93e77 Merge branch '283-die-bluetooth-die' into 'master'
Ensure key agreement tasks finish if they ignore interrupts

The problem here was that `BluetoothSocket#connect()` was throwing an IOException when the task was interrupted - the task treated this like any other connection failure and retried, so the task never finished.

The fix is to check whether the timeout has expired before retrying, so the task eventually finishes even if it ignores the original interrupt.

Closes #283

See merge request !443
2016-12-06 11:02:19 +00:00
Torsten Grote
81337fe7ad Introduce Dialog Theme for Onboarding 2016-12-05 14:54:39 -02:00
akwizgran
cdd234dfe3 Ensure key agreement tasks finish if they ignore interrupts. 2016-12-05 12:38:45 +00:00
Torsten Grote
062ed4ef4b Require a label for hashing
* Add a string label argument to CryptoComponent#hash()
* Convert DoubleDigest from implementing MessageDigest
  to implementing org.spongycastle.crypto.Digest
  (we need to keep DoubleDigest for FortunaGenerator)
* Convert all other uses of MessageDigest to CryptoComponent#hash()
* Remove CryptoComponent#getMessageDigest(), MessageDigest and DigestWrapper
2016-12-05 09:57:18 -02:00
akwizgran
9c22ea8434 Merge branch '766-unit-tests-for-creator-protocol-engine' into 'master'
Add unit tests for CreatorProtocolEngine

See merge request !441
2016-12-05 09:59:40 +00:00
Torsten Grote
9458b185f8 Add unit test for CreatorProtocolEngine 2016-12-02 10:57:00 -02:00
akwizgran
c2b06536ad Merge branch 'identity-manager-unit-tests' into 'master'
Add missing IdentityManager unit tests

See merge request !440
2016-12-02 10:35:15 +00:00
akwizgran
878b52ef2c Merge branch '771-create-bramble-modules' 2016-12-01 21:48:03 +00:00
Torsten Grote
a9ddb0019e Add missing IdentityManager unit tests 2016-12-01 13:21:09 -02:00
akwizgran
2d7cb7b279 Updated Transifex config. 2016-12-01 10:19:24 +00:00
akwizgran
f25d33b0c8 Move stray resources to the right place. 2016-12-01 10:18:42 +00:00
akwizgran
906dd1bd06 Added .gitignore files for new modules. 2016-12-01 10:08:46 +00:00
akwizgran
ad6016d428 Updated java.library.path. 2016-11-30 18:10:49 +00:00
akwizgran
f6d23b4d1a Merge branch '705-blog-pager-race-conditions' into 'master'
Remove blog pagers

I set out to fix potential race conditions in the blog pagers (the screens you reach by tapping the body of a blog post, that allow you to swipe left and right through the posts in the combined feed or a single blog). The race conditions here are similar to those addressed by !356, but the adapters don't inherit from BriarAdapter so they need to be fixed separately.

While I was looking into this I found a few minor problems with the pagers:
* The feed pager wasn't responding to events - this was fixed in !398
* The feed pager finishes NavDrawerActivity when any blog is removed
* The feed isn't updated when a blog is added (this applies to the list view as well as the pager)
* Posts aren't removed from the feed pager when a blog is removed

The last problem is quite serious - the feed pager's adapter contains posts that are no longer in the DB, so they'll fail to load. To fix that problem, the adapter needs to be cleared in onStop() and repopulated in onStart(). This is the same approach we use for other adapters where items can be removed from the underlying dataset. Unfortunately, FragmentStatePagerAdapter has some odd behaviour when you clear and repopulate it:

1. When reselecting the previously selected item after clearing and repopulating the adapter, the item slides into view instead of just appearing, which makes it look like you've accidentally swiped.
2. Items are sometimes duplicated when clearing and repopulating the adapter, so swiping left or right shows another copy of the same post.

These problems only seem to happen if the adapter is cleared - adding new posts works fine on master, although I think there might be some luck involved - FragmentStatePagerAdapter doesn't seem to be designed to support items changing positions.

I spent a lot of time trying to resolve these problems before concluding that maybe it wasn't worth it, and we should just remove the pagers. That's what's currently implemented in this branch. Tapping the body of a post will show the full-length post, but you won't be able to swipe left or right.

The swiping functionality was nice to have, so if you have ideas for fixing the bugs I'd love to hear them. But I'd rather remove this functionality than keep it in a buggy state with no plan for how to fix it.

Closes #705

See merge request !400
2016-11-30 11:21:03 +00:00
akwizgran
aa064e853a Merge branch '760-integration-tests-for-private-group-invitation-protocol' into 'master'
Add integration tests for GroupInvitationManager

This MR is based on !433. It adds some integration tests for the private group invitation protocol. One of those tests fails at the moment.

It does not yet cover all corner cases, so it does not fully address #760, but addresses a part of it. Suggestions for more scenarios to test are welcome.

[Wording changed to prevent #760 from being closed automatically based on the description.]

See merge request !434
2016-11-30 11:19:05 +00:00
akwizgran
8a139eaf5d Tightened up test expectations. 2016-11-30 11:17:57 +00:00
akwizgran
d51f73151f Fixed a bug in the group invitation protocol, added tests. 2016-11-30 11:12:04 +00:00
akwizgran
6c90204c6e Fixed a broken unit test. 2016-11-30 11:07:30 +00:00
akwizgran
f8266d8a02 Tightened up some tests. 2016-11-30 10:23:43 +00:00
akwizgran
f245b04726 Fixed a failing test. 2016-11-30 10:23:43 +00:00
Torsten Grote
67d9f3a7c2 Add integration tests for GroupInvitationManager 2016-11-30 10:23:35 +00:00
akwizgran
24d68c4f5b Merge branch '727-refactor-integration-tests' into 'master'
Refactor Integration Tests

This is quite a massive MR (currently 1763 additions and 3482 deletions). However, there's not so much happening. The only thing I did was moving redundant code from the various protocol integration tests to the `BriarIntegrationTest` class.

All integration tests are still passing.

Closes #727

See merge request !433
2016-11-29 18:28:11 +00:00
akwizgran
edbd7f4eeb Addressed review comments. 2016-11-29 18:27:19 +00:00
akwizgran
2f7830e73f Merge branch '766-unit-tests-for-group-validators' into 'master'
Add unit tests for group validators

Part of #766

See merge request !436
2016-11-29 18:13:43 +00:00
akwizgran
a82fdca3d4 Added more private group invitation validation tests. 2016-11-29 18:12:32 +00:00
akwizgran
050111a994 Added some more private group validation tests, found a bug. 2016-11-29 17:46:46 +00:00
akwizgran
a22d1d811f Merge branch '766-unit-tests-for-group-invitation-client' into 'master'
Add unit tests for group invitation client

Part of #766

See merge request !429
2016-11-29 11:51:17 +00:00
akwizgran
90124e00ca Addressed review comments. 2016-11-29 11:50:20 +00:00
akwizgran
04323856de Merge branch '782-wrong-item-selected-in-navdrawer-onBackPressed' into 'master'
Fix Contacts Item always beeing selected if Back is pressed in the NavMenu

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #782

See merge request !438
2016-11-28 17:07:24 +00:00
goapunk
cfcd36f21a Fix Contacts Item always beeing selected if Back is pressed in the NavMenu
Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-28 16:29:41 +01:00
Ernir Erlingsson
2b9ccb4c42 Merge branch '782-wrong-item-selected-in-navdrawer-onBackPressed' into 'master'
Select the correct MenuItem when Back is pressed in NawDrawer

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #782

See merge request !437
2016-11-28 08:37:53 +00:00
Ernir Erlingsson
6436e6688d Merge branch '477-private-messaging-text-bubble-and-header-overlap' into 'master'
Bring back the toolbar shadow

![device-2016-11-21-180111](/uploads/7cd5e6a1e7a4b79b6d7cf81377b148a0/device-2016-11-21-180111.png)

Closes #477

See merge request !431
2016-11-27 21:55:24 +00:00
Torsten Grote
8c7a532e2e Update translations before user testing 2016-11-27 13:38:26 -02:00
goapunk
47171f3e18 Select the correct MenuItem when Back is pressed in NawDrawer
Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-26 23:09:07 +01:00
Torsten Grote
6fc42f7296 Update also Malaysian translation (removes unused strings) 2016-11-23 21:08:51 -02:00
Torsten Grote
55af22ca04 Update translations and expiry date 2016-11-23 21:05:06 -02:00
Torsten Grote
b37a7531ca Add unit tests for group validators 2016-11-23 18:53:03 -02:00
akwizgran
6ab8219394 Merge branch '666-transport-icons-overlap-navigation-items' into 'master'
Make navigation drawer scrollable

![device-2016-11-22-095642](/uploads/bcd5f68d40816ed2e44c3194eb977695/device-2016-11-22-095642.png)![device-2016-11-22-095658](/uploads/da1807e981632936ba04db24dc7b8ae7/device-2016-11-22-095658.png)

Closes #666

See merge request !432
2016-11-23 15:11:43 +00:00
akwizgran
7d1ddb6d65 Merge branch '504-define-and-design-primary-and-secondary-actions' into 'master'
Make dialog actions consistent

Closes #504

See merge request !430
2016-11-23 15:08:58 +00:00
akwizgran
f1371f1db8 Merge branch '774-adding-contacts-via-bluetooth-only-fails' into 'master'
Use uuid created from the commitment/payload instead of the uuid returned from getUuid()

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #774

See merge request !435
2016-11-23 15:06:16 +00:00
goapunk
491e0adc9c Use uuid created from the commitment/payload instead of the uuid returned from getUuid()
Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-23 10:07:47 +01:00
Torsten Grote
2850763ec6 Refactor Integration Tests 2016-11-22 13:31:58 -02:00
Torsten Grote
f10ac13350 Make navigation drawer scrollable 2016-11-22 09:59:42 -02:00
Torsten Grote
e69139bc24 Bring back the toolbar shadow 2016-11-21 18:32:29 -02:00
Torsten Grote
38f46a9c60 Make dialog actions consistent 2016-11-21 17:42:23 -02:00
Torsten Grote
b0b932a01c Add unit tests for group invitation client 2016-11-21 16:57:28 -02:00
Torsten Grote
20de6f1aa5 Merge branch '747-remove-injected-field-from-unit-test' into 'master'
Remove injected field from unit test

Getting this off my todo list...

Closes #747

See merge request !428
2016-11-21 16:43:49 +00:00
akwizgran
cbdeb0ad32 Replace unused injected field with a mock. 2016-11-21 16:41:01 +00:00
akwizgran
a60414517c Merge branch '639-reblogger-and-author-look-similar-their-roles-are-unclear' into 'master'
Make original author look like commenter when reblogged

This wasn't as simple as changing the persona in the XML,
because the same layout is used for a post whether reblogged or not.
So the persona needs to be changed programmatically for reblogged posts.
For this, the `AuthorView#setPersona()` method has been made public and
was changed to always set all views into the desired state to support
usage in a RecyclerView.

![device-2016-11-21-094221](/uploads/e508937ad2d2d84f97f5be29bdeaac2e/device-2016-11-21-094221.png)

Closes #639

See merge request !426
2016-11-21 15:51:43 +00:00
akwizgran
988c3e4b58 Merge branch '768-keyagreementconnector-regression-unsupportedoperationexception' into 'master'
Fix KeyAgreement after regression

Closes #768

See merge request !427
2016-11-21 12:34:33 +00:00
Torsten Grote
b0098fb054 Fix KeyAgreement after regression 2016-11-21 10:32:06 -02:00
Torsten Grote
a7c28f04de Make original author look like commenter when reblogged
This wasn't as simple as changing the persona in the XML,
because the same layout is used for a post whether reblogged or not.
So the persona needs to be changed programmatically for reblogged posts.
For this, the `AuthorView#setPersona()` method has been made public and
was changed to always set all views into the desired state to support
usage in a RecyclerView.
2016-11-21 09:43:22 -02:00
akwizgran
4eec29a631 Merge branch '762-textinput_does_not_increase' into 'master'
make TextInputView resizable again

* TextInputView can resize up to 3 lines again

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #762

See merge request !425
2016-11-21 10:11:00 +00:00
goapunk
76504387ff make TextInputView resizable again
* TextInputView can resize up to 3 lines again

Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-18 18:05:31 +01:00
Torsten Grote
ea0ad08f57 Merge branch '763-remove-signature-api' into 'master'
Remove old signature class from API

I decided not to remove the SignatureImpl class, as it's not a trivial wrapper around the Bouncy Castle class, but I moved the interface into briar-core and made it  package-private.

Closes #763

See merge request !424
2016-11-18 16:23:01 +00:00
akwizgran
e4676517ef Merge branch '524-check-that-acra-is-catching-all-uncaught-exceptions' into 'master'
Introduce a @Scheduler annotation

and make sure work is offloaded to an executor, so exceptions can be caught.

Closes #524

See merge request !422
2016-11-18 16:00:22 +00:00
akwizgran
dbbeb37485 Merge branch '757-remove-deviceid-code' into 'master'
Remove Device ID

Closes #757

See merge request !423
2016-11-18 15:54:28 +00:00
akwizgran
89a7f41a07 Remove old signature class from API. 2016-11-18 15:30:18 +00:00
akwizgran
936ee5e95b Merge branch '549-require-a-label-for-signing' into 'master'
Require a label for signing

This adds a sign() and a verify() method to the CryptoComponent
that take a mandatory label argument to ensure that signatures can't be
repurposed.

Closes #549

See merge request !419
2016-11-18 15:16:41 +00:00
Torsten Grote
1697c2af04 Remove Device ID 2016-11-18 12:30:25 -02:00
Torsten Grote
cb8e0beea9 Fix Transport IDs 2016-11-18 12:29:57 -02:00
Torsten Grote
98cb077dd9 Migrate all custom signature code to new methods and add test 2016-11-18 12:19:03 -02:00
akwizgran
e6a8ad5d49 Merge branch '754-add-visibility-information-to-group-member-list' into 'master'
Add visibility information to group member list

![device-2016-11-17-120740](/uploads/f16dd42c3637e0030722559bace9c391/device-2016-11-17-120740.png)![device-2016-11-17-121008](/uploads/a83fe1f27cd3a505cf45a94fec76cdcf/device-2016-11-17-121008.png)

Closes #754

See merge request !418
2016-11-18 13:19:45 +00:00
akwizgran
5e4116efa0 Merge branch '761-keyboard_doesnt_close_on_userinteraction' into 'master'
use SHOW_IMPLICIT when showing the softkeyboard, otherwise it won't auto hide

* remove the forced hiding in ThreadListActivity as it should no longer be required

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #761

See merge request !421
2016-11-18 13:14:51 +00:00
akwizgran
a01eeafe4e Merge branch '752-refactor-android-dagger-module' into 'master'
Activity module refactor

Broke the Activity module into numerous modules to be able to make numerous controller's package visible

Closes #752

See merge request !417
2016-11-18 13:13:12 +00:00
Torsten Grote
c86d971166 Require a label for signing
This adds a sign() and a verify() method to the CryptoComponent
that take a mandatory label argument to ensure that signatures can't be
repurposed.
2016-11-18 11:05:19 -02:00
Torsten Grote
d5f8808597 Add visibility information to group member list 2016-11-18 11:02:54 -02:00
goapunk
e98f4901f5 use SHOW_IMPLICIT when showing the softkeyboard, otherwise it won't auto hide
* remove the forced hiding in ThreadListActivity as it should no longer be required

Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-18 13:50:04 +01:00
akwizgran
9b09b64ad3 Merge branch '558-use-namespaced-strings-for-transport-ids' into 'master'
Use namespaced strings for Transport IDs

Closes #558

See merge request !420
2016-11-18 12:49:57 +00:00
Torsten Grote
20708bc156 Introduce a @Scheduler annotation
and make sure work is offloaded to an executor, so exceptions can be
caught.
2016-11-18 10:48:20 -02:00
akwizgran
0814458cb9 Merge branch '759-introduction-responses-are-not-marked-as-read' into 'master'
Do not track incoming positive introduction responses

Positive introduction responses are not shown in the UI (for introducees) and are therefore not marked as read. If they would be tracked, the unread message count would be higher than it actually is and would never decrease.

This is a minimal fix that could be better, but I didn't bother to refactor anything, because we need to rewrite the introduction client eventually anyway once more.

Closes #759

See merge request !416
2016-11-18 12:20:40 +00:00
Torsten Grote
e32313c30b Use namespaced strings for Transport IDs 2016-11-17 17:06:26 -02:00
Torsten Grote
593152e7cd Do not track incoming positive introduction responses
because they are not shown in the UI and are therefore not marked as
read. This fixes the unread message count.
2016-11-17 10:59:20 -02:00
Ernir Erlingsson
ab91520813 refactored the activity module 2016-11-17 13:57:02 +01:00
Torsten Grote
37e61c97ea Merge branch 'remove-unmodifiable-wrappers' into 'master'
Remove unnecessary unmodifiable collection wrappers

Part of #379.

See merge request !414
2016-11-16 18:02:34 +00:00
Torsten Grote
303fcc9ece Merge branch 'validator-unit-tests' into 'master'
Unit tests for some validators

See merge request !413
2016-11-16 17:44:08 +00:00
akwizgran
e2bbe7429b Moved some boilerplate into a field. 2016-11-16 17:00:53 +00:00
akwizgran
eaf17c054f Moved common fields to superclass. 2016-11-16 16:39:30 +00:00
Torsten Grote
f97f30ce42 Merge branch '756-avoid-lost-messages' into 'master'
Use new group visibility state to avoid lost messages

Depends on !410. Closes #756.

See merge request !411
2016-11-16 16:22:30 +00:00
akwizgran
f4c26d9cc7 Remove unnecessary unmodifiable collection wrappers. 2016-11-16 16:19:47 +00:00
akwizgran
68abf8ba1a Merge branch '756-group-visibility' into 'master'
Add third group visibility state

This branch adds a third group visibility state: each group is either invisible, visible, or shared with respect to each contact.

Invisible means that the contact doesn't see any sign that we subscribe to the group. Visible means that the contact can send us messages in the group, but we won't send the contact messages in the group. Shared means that the contact can send us messages in the group and we'll send the contact any shared messages in the group.

This is a preparatory step for #756. I'll put up another MR with the changes that close that ticket.

See merge request !410
2016-11-16 15:56:37 +00:00
akwizgran
58f6af513d Use new group visibility state to avoid lost messages. #756 2016-11-16 15:50:07 +00:00
akwizgran
c9170fa5a0 Removed unnecessary use of unmodifiable collections. 2016-11-16 15:48:08 +00:00
akwizgran
ec1f4dccdb Added third group visibility state. 2016-11-16 15:40:51 +00:00
akwizgran
8c3b598ab2 Unit tests for ForumSharingValidator. 2016-11-16 15:35:27 +00:00
akwizgran
bd3bba6e8a Unit tests for ForumPostValidator. 2016-11-16 14:36:22 +00:00
akwizgran
11fcad89c6 Unit tests for BdfMessageValidator. 2016-11-16 14:32:22 +00:00
Torsten Grote
007df4288b Merge branch '709-track-private-group-invitation-messages' into 'master'
Use MessageTracker for private group invitation messages

Depends on !405.

See merge request !412
2016-11-16 14:14:48 +00:00
Torsten Grote
9798654c23 Merge branch 'message-tracker-refactoring' into 'master'
Factor MessageTracker out of BdfIncomingMessageHook

The branch moves the MessageTracker implementation from BdfIncomingMessageHook to a separate class. This will allow the private group invitation client to track messages from classes other than the one that implements the delivery hook.

I've also fixed a couple of bugs, removed some redundant code from the validation manager, and added null-safety annotations (which is how I noticed the bugs).

See merge request !405
2016-11-16 14:04:14 +00:00
akwizgran
7b58d003a1 Merge branch '732-reveal-contacts-ui-join-notices' into 'master'
Add visibility and OPTIONS button to private group join notices

![device-2016-11-11-180658](/uploads/e00d175a1e1f34307c5f0d80fa0d1cdf/device-2016-11-11-180658.png)
![device-2016-11-11-181325](/uploads/0f6010094d529a4f151db8ebce974885/device-2016-11-11-181325.png)

Closes #732

See merge request !408
2016-11-16 13:44:32 +00:00
akwizgran
b60f6b0789 Merge branch '755-group-message-timestamp' into 'master'
Made private group timestamp greater than that of latest message

I did not change `getPreviousMsgId()` to `getPreviousMsgHeader()` because there doesn't seem to be a need for it anymore.

Closes #755

See merge request !409
2016-11-16 13:29:59 +00:00
Torsten Grote
914b72505a Made private group timestamp greater than that of latest message 2016-11-16 11:20:25 -02:00
Torsten Grote
24dd4fda69 Address review issues 2016-11-16 11:08:00 -02:00
akwizgran
52eb261a11 Unit tests for PrivateMessageValidator. 2016-11-16 11:49:49 +00:00
Torsten Grote
980a6d18bb Add visibility and OPTIONS button to private group join notices 2016-11-16 09:25:22 -02:00
akwizgran
c4a152b543 Merge branch '732-reveal-contacts-ui-onboarding' into 'master'
Add onboarding dialog for revealing contacts screen

This MR is based on !406.

![device-2016-11-11-162417](/uploads/8df831905eebf41ecdbe368890cdd429/device-2016-11-11-162417.png)

See merge request !407
2016-11-14 12:44:41 +00:00
Torsten Grote
ed728e816e Add onboarding dialog for revealing contacts screen 2016-11-14 09:14:30 -02:00
akwizgran
efbce95399 Merge branch '732-reveal-contacts-ui' into 'master'
Add UI for revealing contacts within a private group

This addresses one part of #732. Join notices and onboarding will follow in separate MRs.

Although this MR is technically not based on !402, it does require it to be merged first to compile.

![device-2016-11-11-160454](/uploads/8cb6d8bdd0f3761657875024739e730a/device-2016-11-11-160454.png)

See merge request !406
2016-11-14 10:48:42 +00:00
akwizgran
98c81f71b4 Merge branch '709-reveal-relationships' into 'master'
Mark relationship visible when syncing group with peer

This branch updates the private group invitation protocol to use @grote's new method for marking a contact relationship visible to the group.

I've changed the method slightly because the protocol state machine allows us to leave and re-enter the BOTH_JOINED state (see diagram on #659), so the relationship may already be visible when the method is called. In that case the visibility isn't updated, so we stick with whichever of revealed-by-us and revealed-by-contact happened first.

See merge request !402
2016-11-14 10:32:56 +00:00
akwizgran
da543c1004 Added javadocs, removed redundant exception. 2016-11-14 10:30:38 +00:00
akwizgran
7ab4d12d83 Track private group invitation messages. 2016-11-14 10:10:14 +00:00
Torsten Grote
59964c5087 Add UI for revealing contacts within a private group 2016-11-11 15:40:02 -02:00
Torsten Grote
b885e49ba2 Don't indicate that we are sharing with ourselves in group memberlist 2016-11-11 15:40:01 -02:00
akwizgran
63da860681 Merge branch '732-reveal-contacts-ui-preparation' into 'master'
Prepare UI for revealing contacts

This changes the visibility of some methods (that need to be accessed from another package), removes unnecessary abstractions and fixes erroneous static import of GroupId constant.

See merge request !404
2016-11-11 17:33:54 +00:00
akwizgran
aa210fc555 Factor MessageTracker out of BdfIncomingMessageHook. 2016-11-11 16:59:10 +00:00
Torsten Grote
68f0e91f32 Prepare UI for revealing contacts
This changes the visibility of some methods, removes unnecessary
abstractions and fixes static import of GroupId constant.
2016-11-11 14:49:26 -02:00
akwizgran
3a2205123f Added a method for revealing a contact to a private group. 2016-11-11 13:49:49 +00:00
akwizgran
2837bde774 Removed blog post pagers 2016-11-11 13:38:04 +00:00
akwizgran
411549dc0a Code cleanup, use correct fragment class. 2016-11-11 13:37:32 +00:00
akwizgran
ab16ee7465 Merge branch 'exception-handler' into 'master'
Add new Exception handler

While working on #732 I again needed to use a `UiResultExceptionHandler`  when I actually don't need to return a result. We have some other places in the code like this. So I introduced a `UiExceptionHandler` without the result part and used it where appropriate. While I was touching some classes, I also added the new annotations.

This MR includes another small commit that notifies only on local group messages. Joining a group is a message as well and without this change, you are notified about a new message when you yourself joined your newly created group.

See merge request !403
2016-11-11 13:34:09 +00:00
Torsten Grote
eb66924e21 Do not show notification for local group messages 2016-11-11 10:03:03 -02:00
Torsten Grote
563d897651 Introduce Exception handler for when no result needs to be returned
Also add NotNull annotation to classes that were touched
2016-11-11 10:03:02 -02:00
akwizgran
98cf6b5bba Mark relationship visible when syncing group with peer. 2016-11-11 11:29:55 +00:00
akwizgran
ade7e50f65 Merge branch 'contact-selector-controller' into 'master'
Add a controller for contact selection lists

See merge request !401
2016-11-11 10:54:07 +00:00
Torsten Grote
ccc9d53ac7 Address review comments 2016-11-10 16:49:20 -02:00
Torsten Grote
d232529eb3 Add a controller for contact selection lists 2016-11-10 15:33:53 -02:00
akwizgran
a532f03784 Merge branch '732-reveal-backennd' into 'master'
Add support for revealing contacts to the PrivateGroupManager

This also adds three integration tests and improves some small details here and there in the private group client.

Prerequisite for #732.

See merge request !396
2016-11-10 17:00:31 +00:00
Torsten Grote
5e5bf7ec05 Add ContactRelationshipRevealedEvent and address review comments 2016-11-10 13:56:42 -02:00
akwizgran
7414abd1ce Merge branch '748-qr-code-payload-order' into 'master'
Preserve the order of descriptors in QR code payloads

This fixes a regression caused by my recent changes to the Payload class.

Closes #748

See merge request !399
2016-11-10 12:21:36 +00:00
Torsten Grote
dc76ce2be2 Merge branch '720-camera-surface-illegal-state-exception' into 'master'
Don't crash if camera is reopened or surface is recreated

This branch fixes the crash is described in #720, which can be reproduced easily by scanning a QR code and failing to connect (for example, scan a screenshot of a QR code from a device that's no longer listening). When the camera view becomes visible again after trying to connect, its surfaceCreated() callback is called again with the same surface. An IllegalStateException added in !340 causes the crash.

Closes #720

See merge request !397
2016-11-10 11:12:24 +00:00
Torsten Grote
3eed0bfe81 Add visibility of contact relationship to JoinMessageHeader 2016-11-09 16:35:27 -02:00
Torsten Grote
ec8982438a Add support for revealing contacts to the PrivateGroupManager
This also adds two integration tests and improves some small details
2016-11-09 16:34:58 -02:00
akwizgran
501c2dab31 Preserve the order of descriptors in QR code payloads. 2016-11-09 15:57:41 +00:00
akwizgran
2fe69af6d8 Don't try to get parameters after releasing camera. 2016-11-09 14:51:05 +00:00
Torsten Grote
b20c107010 Merge branch 'feed-pager-events' into 'master'
Make the feed pager respond to events, block notifications

This branch fixes a bug I found while working on #705: FeedPostPagerFragment doesn't start or stop the controller, so it doesn't load newly received posts or block notifications, unlike FeedFragment.

See merge request !398
2016-11-09 14:16:57 +00:00
akwizgran
f410e4eddd Make the feed pager respond to events, block notifications. 2016-11-09 13:24:44 +00:00
akwizgran
bb82bd70e2 Don't crash if camera is reopened or surface is recreated. 2016-11-09 12:43:33 +00:00
akwizgran
138a6e11a7 Merge branch '346-smaller-qr-codes' into 'master'
Encode transport properties more compactly in QR codes

The [original BQP spec](https://code.briarproject.org/akwizgran/briar/wikis/BQP) described a compact encoding for transport properties, with the goal of making the QR code as small as possible. At some point during the implementation, I asked @str4d to use TransportIds and TransportProperties instead, as described in the [current spec](https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md). That was a mistake.

Using the original format reduces the payload from 60 to 34 bytes (43% smaller) for Bluetooth only, and from 96 to 49 bytes (49% smaller) for Bluetooth and LAN. This makes it easier to scan codes from low-resolution screens using fixed-focus and/or low-resolution cameras. Using this branch I can exchange codes between the Sony Xperia Tipo (320x480 screen, fixed focus, 640x480 preview size) and the Huawei Ascend Y300 (480x800 screen, infinity focus, 1280x720 preview size).

This also removes an obstacle to implementing #558, as TransportIds are no longer included in QR codes.

Closes #346.

See merge request !394
2016-11-08 17:32:26 +00:00
akwizgran
178d72114b Merge branch '709-private-group-invitation-protocol' into 'master'
Private group invitation protocol

This branch implements the private group invitation protocol. The implementation is something of an experiment with a new way of writing client protocols.

We start with a role enum that lists the roles in the protocol, and a state enum for each role, which lists the states in the role's state machine. Then there's a session class, parameterised by the state class and therefore by the role, which represents the session information held by that role. Then there's an engine interface, parameterised by the session class and therefore by the role, which encapsulates the protocol logic for the role. Most of this stuff can be created pretty mechanically from the state machine diagrams.

The engine interface has a method for each type of message and each local action. I started out with one method for all messages and another for all local actions, but that turned out to be a bad design - the information about what kind of message was being handled was lost when the message was passed to the engine, and had to be recovered using an instanceof ladder.

Each engine method takes a message or an action and a session, and returns an updated session. A transaction is passed in so the engine can send messages, attach events, and do any other work it needs to do (such as changing the visibility of groups, in the case of this protocol). This removes the need to run tasks outside the engine, so the protocol logic is better encapsulated inside the engine.

Parsing and encoding of messages and sessions is separated from protocol logic. MessageParser, MessageEncoder and the validator are the only classes that know how messages and their metadata are formatted, and likewise SessionParser and SessionEncoder are the only classes that know how sessions are formatted. The metadata keys are declared in a package-private interface.

It's common knowledge that I never make mistakes, so to keep things interesting I've hidden 114 deliberate mistakes in this code. See how many you can spot!

Needs tests before #709 is closed.

See merge request !382
2016-11-08 17:22:00 +00:00
Torsten Grote
c1f1eb7dfa Merge branch '709-preliminaries' into 'master'
Preliminaries for private group invitation protocol

As promised, here's the preliminary stuff for #709 as a separate MR.

See merge request !395
2016-11-08 17:02:45 +00:00
akwizgran
d2a3804cfe Added null safety annotations to plugin interfaces. 2016-11-08 16:59:56 +00:00
akwizgran
fb095c1f4d Broadcast events for private group invitations. 2016-11-08 16:08:51 +00:00
akwizgran
f89d8cbe38 Updated peer state machine for automatic join response. 2016-11-08 16:08:50 +00:00
akwizgran
d2434123a9 Private group invitation protocol. 2016-11-08 16:08:50 +00:00
akwizgran
edbf5ff5b4 Preliminaries for private group invitation protocol. 2016-11-08 15:45:04 +00:00
akwizgran
32f0b53d15 Increase test timeouts to avoid spurious failures. 2016-11-08 15:17:08 +00:00
akwizgran
55ecdd9a13 Merge branch '557-use-namespaced-strings-for-client-ids' into 'master'
Use namespaced strings for client IDs

Closes #557

See merge request !393
2016-11-08 13:25:41 +00:00
akwizgran
e47e3242a6 Merge branch '196-mark-messages-read' into 'master'
Mark private messages read properly

Depends on !386.

This branch uses the same approach as forums to mark messages read, i.e. each message is marked read when it becomes visible, rather than marking all messages read in a batch when the activity finishes. This fixes two problems: messages not being marked read when isFinishing() is false, for example when leaving the activity via the home button, and a race condition between updating and loading the group count when leaving the activity, resulting in a stale unread message count in the contact list.

Closes #196.

See merge request !388
2016-11-08 13:25:00 +00:00
Torsten Grote
4387bfc5bd Merge branch '733-incoming-messages-aren-t-added-to-private-group-conversation' into 'master'
Broadcast GroupMessageAddedEvent for the UI to update when received

Closes #733

See merge request !390
2016-11-08 13:24:20 +00:00
Torsten Grote
d11ee5e43b Broadcast GroupMessageAddedEvent for the UI to update when received 2016-11-08 11:23:52 -02:00
akwizgran
ce53589c33 Merge branch '736-private-group-list-is-not-updated-when-group-is-dissolved' into 'master'
Create GroupDissolvedEvent and react to it

This MR also makes the private group list react to incoming group invitations (once they are implemented).

![device-2016-11-07-155240](/uploads/84ed51cf72bf2c7c597a0fd68b5d868c/device-2016-11-07-155240.png)
![device-2016-11-07-155302](/uploads/446c98d70d674d0bcd79bfb7682dfed5/device-2016-11-07-155302.png)

Closes #736, #737

See merge request !392
2016-11-08 13:20:28 +00:00
Torsten Grote
e96b3a8c68 Use namespaced strings for client IDs 2016-11-08 11:17:52 -02:00
Torsten Grote
62040d45b8 Create GroupDissolvedEvent and react to it
Also react to incoming group invitations
2016-11-08 10:28:54 -02:00
akwizgran
1809943f1d Merge branch '734-notifications-for-private-group-messages' into 'master'
Show Notifications for Group Messages

Closes #734

See merge request !391
2016-11-08 12:06:15 +00:00
akwizgran
d204757395 Merge branch '735-back-button-in-invite-members-screen-returns-to-group-list' into 'master'
Return to group after not inviting new members

This MR also closes the keyboard when returning from the message fragment.

Closes #735

See merge request !389
2016-11-08 11:55:36 +00:00
akwizgran
c640ee8e51 Merge branch '714-asynchronous-context-leaks' into 'master'
Fixed asynchronous Activity leaks in Fragments

If a Fragment has been detached its `getActivity()` method will return null, providing numerous crash possibilities within the app.

My approach to fixing this is to make Fragments use their own `runOnUiThreadUnlessDestroyed` method, which also checks if the Fragment has been detached before running the Runnable

Closes #714

See merge request !387
2016-11-08 11:49:45 +00:00
akwizgran
04d4ecad05 Encode transport properties more compactly in QR codes. 2016-11-08 11:28:44 +00:00
Ernir Erlingsson
c36bb3e60e created runOnUiThreadUnlessDestroyed fragment wrapper 2016-11-07 17:11:57 +01:00
akwizgran
7327029fca Log the QR code payload length. 2016-11-07 16:04:07 +00:00
Torsten Grote
81d341374d Show Notifications for Group Messages 2016-11-07 13:52:59 -02:00
Torsten Grote
7b884d2425 Return to group after not inviting new members
Also close keyboard when returning from message fragment
2016-11-07 10:44:22 -02:00
Torsten Grote
fbcf334941 Merge branch 'use-contact-id-as-conversation-id' into 'master'
Use contact ID rather than messaging group ID to identify conversation

We originally used the private messaging group ID to identify the private conversation, but now that the conversation includes messages from multiple clients it's more appropriate to use the contact ID.

This refactoring isn't urgent - I've had the branch lying around for a while, but I'm putting it up for review because #734 will touch some of the same code.

See merge request !386
2016-11-07 11:24:11 +00:00
akwizgran
238100bcac Mark messages read properly in private conversation. 2016-11-07 10:43:24 +00:00
akwizgran
7c3805260d Merge branch '643-allow-messages-to-be-deleted-in-the-delivery-hook' into 'master'
Allow messages to be deleted in delivery hook

Closes #643

See merge request !385
2016-11-04 16:14:44 +00:00
akwizgran
51bcf7b1b8 Don't use messaging group ID as proxy for contact ID. 2016-11-04 15:50:44 +00:00
Torsten Grote
719a53dc94 Address review comments 2016-11-04 12:58:12 -02:00
Torsten Grote
3f9a254a0b Allow messages to be deleted in delivery hook 2016-11-04 12:52:33 -02:00
akwizgran
e810a1265a Merge branch '205-unit-tests-for-keymanagerimpl-and-transportkeymanager' into 'master'
Add unit tests for KeyManagerImpl

This also creates a `TransportKeyManager` interface and a factory for that to be able to test things separately.

Closes #205

See merge request !380
2016-11-04 14:29:21 +00:00
Torsten Grote
c36f5c795b Address review comments for TransportKeyManagerImplTest 2016-11-04 11:04:44 -02:00
Torsten Grote
f52186ac8c Add unit tests for KeyManagerImpl and create TransportKeyManager
interface and a factory for that.
2016-11-04 10:54:56 -02:00
akwizgran
e0f4be931d Merge branch '708-private-group-fixup' into 'master'
Let only the creator invite new members to private groups

A little bug I noticed when reviewing the implementation of the invitation protocol.

See merge request !383
2016-11-04 09:33:50 +00:00
akwizgran
7536c00a34 Merge branch '708-private-group-remove-new-member-announcement' into 'master'
Remove new member announcement and add signature to join message



See merge request !384
2016-11-04 09:32:40 +00:00
akwizgran
847b6e4179 Added comments to integration test. 2016-11-04 09:32:21 +00:00
Torsten Grote
58793068c3 Address review comments 2016-11-03 17:26:37 -02:00
Torsten Grote
7125248677 Remove new member announcement and add signature to invitation 2016-11-03 17:24:31 -02:00
Torsten Grote
4bad7076e7 Merge branch '674-ending-a-transaction-can-throw-an-exception-in-a-finally-block' into 'master'
Replace transaction.setComplete() by database.commitTransaction()

Closes #674

See merge request !374
2016-11-03 19:23:16 +00:00
akwizgran
2bb16bb75f Merge branch '348-testers-did-not-understand-qr-code-workflow' into 'master'
Improve QR code workflow slightly

* Improve wording so contacts know they need meet up to scan
  and scan each other's codes
* Use consistent progress bar styles

Closes #348

See merge request !381
2016-11-03 15:56:19 +00:00
Torsten Grote
b5a427f876 Let only the creator invite new members to private groups 2016-11-02 17:40:33 -02:00
Torsten Grote
b34b4623ed Replace transaction.setComplete() by database.commitTransaction() 2016-11-02 13:04:31 -02:00
Torsten Grote
f3b9214702 Improve QR code workflow slightly
* Improve wording so contacts know they need meet up to scan
  and scan each other's codes
* Use consistent progress bar styles
2016-11-02 12:43:41 -02:00
akwizgran
36f087c512 Merge branch '724-unit-tests-for-clienthelperimpl' into 'master'
Add Unit Tests for ClientHelper

Closes #724

See merge request !379
2016-11-02 11:04:07 +00:00
akwizgran
0c30f16d7e Merge branch '731-bdf-reader-open-lists-and-dictionaries' into 'master'
Don't throw IllegalStateException if BDF input is incomplete

Closes #731

See merge request !378
2016-11-01 17:40:13 +00:00
akwizgran
4d8a84a48d Don't throw IllegalStateException if BDF input is incomplete. 2016-11-01 17:38:23 +00:00
akwizgran
2650f3114e Merge branch '518-limit-the-depth-of-nested-bdf-structures' into 'master'
Limit the depth of nested BDF structures

Closes #518

See merge request !375
2016-11-01 17:30:50 +00:00
Torsten Grote
dfdde9799f Add Unit Tests for ClientHelper 2016-11-01 15:28:28 -02:00
akwizgran
114a2dc8f2 Merge branch '427-local-author-caching' into 'master'
Cache the local author and load before the db latch is released

Closes #427, #588 

See merge request !354
2016-11-01 17:21:14 +00:00
akwizgran
642fa7df18 Removed unused field, renamed nickname methods. 2016-11-01 17:17:40 +00:00
akwizgran
c85767d2a0 Nickname is all one word. 2016-11-01 17:12:30 +00:00
Torsten Grote
55af1b954e Limit the depth of nested BDF structures 2016-11-01 14:52:00 -02:00
Ernir Erlingsson
88272c5d61 improvements after dev comments 2016-11-01 13:33:12 +01:00
Ernir Erlingsson
eaa393a7ed added a cache to the IdentityManager, changed its signature, modified when and where the author is stored
made the author creation single-threaded again in the LifecycleManager, removed redundant code
2016-11-01 12:51:49 +01:00
akwizgran
19080ad957 Merge branch '723-unit-tests-for-contactmanagerimpl' into 'master'
Add Unit tests for ContactManager

Closes #723

See merge request !376
2016-11-01 11:50:47 +00:00
Torsten Grote
7eeeb5f1ed Add Unit tests for ContactManager 2016-11-01 09:40:05 -02:00
akwizgran
d55503ee92 Merge branch '722-implement-ux-design-for-inviting-new-members-to-a-group' into 'master'
Implement UX design for inviting new members to a group

Closes #722

See merge request !373
2016-11-01 11:38:29 +00:00
Torsten Grote
8448d27d20 Implement UX design for inviting new members to a group 2016-11-01 09:27:23 -02:00
akwizgran
47d6fc526f Merge branch '678-implement-ux-for-viewing-the-membership-of-a-private-group' into 'master'
Implement UX for viewing the membership of a private group

This MR is the second and last MR to address #678. The first part is in !377.

![device-2016-10-26-112000](/uploads/8cbdee65c123a6d5329e208d9983d0b0/device-2016-10-26-112000.png)

Closes #678

See merge request !364
2016-11-01 11:12:21 +00:00
Torsten Grote
3da879cfd9 Address review comments for group member list 2016-11-01 09:09:22 -02:00
Torsten Grote
8fdce5ba51 Group Member List UI 2016-11-01 09:09:20 -02:00
akwizgran
f759a7506f Merge branch '600-remove-content-type-from-private-messages' into 'master'
Remove content-type and parentId from private messages

and turn them into a regular string.

Closes #600

See merge request !372
2016-11-01 11:05:30 +00:00
akwizgran
0b11aea7a2 Merge branch '672-implement-ux-for-dissolving-a-group' into 'master'
Implement UX for when a group has been dissolved

This MR is based on !367.

Closes #672

See merge request !369
2016-11-01 11:02:27 +00:00
akwizgran
aa954cee63 Merge branch '671-implement-ux-for-leaving-a-group' into 'master'
Implement UX for leaving a group

This MR also includes the creator's part of the UX for dissolving a group since it is almost the same.

![device-2016-10-26-185615](/uploads/8689a1ee103fcee23105a469b37c59de/device-2016-10-26-185615.png)

Closes #671

See merge request !367
2016-11-01 10:57:33 +00:00
akwizgran
68024c264e Merge branch '700-update-blog-backend-to-match-current-usage' into 'master'
Update blog backend to match current usage

Closes #700

See merge request !371
2016-11-01 10:56:02 +00:00
Torsten Grote
78740a6942 Remove content-type and parentId from private messages
and turn them into a regular string.
2016-11-01 08:39:15 -02:00
Torsten Grote
9e553ef9c8 Update blog backend to match current usage 2016-11-01 08:34:29 -02:00
Torsten Grote
1147b8ffaf Disable group before loading messages 2016-11-01 08:26:40 -02:00
Torsten Grote
67866dbe66 Implement UX for when a group has been dissolved 2016-11-01 07:41:55 -02:00
Torsten Grote
8dac2d1ca6 Implement UI for dissolving and leaving group 2016-11-01 07:40:56 -02:00
Torsten Grote
b0a5a69b81 Remove group from database in PrivateGroupManager 2016-11-01 07:39:35 -02:00
akwizgran
a18317e912 Merge branch '681-convert-forum-post-bodies-to-strings-remove-content-type' into 'master'
Remove forum content type and change bodies to string

Also removes support for anonymous forum posts.

This MR depends on !360.

Closes #698, #681

See merge request !370
2016-10-31 21:34:24 +00:00
akwizgran
ad7d0d8e74 Merge branch '678-private-group-hooks-and-membership' into 'master'
Add methods and hooks to PrivateGroupManager related to members and removal

This MR is the first of two MRs related to #678.

See merge request !377
2016-10-31 16:27:15 +00:00
akwizgran
fe79131f4a Merge branch '678-contact-list-refactoring' into 'master'
Refactor contact lists, their adapters and items

This was supposed to be a preparation for #678 to make the contacts lists cleaner and easier to re-use for different use-cases. Turns out #678 can't use this work, but it is probably nice to have anyway.

During this work, support for multiple identities has been removed from the various contact lists.

See merge request !363
2016-10-31 15:39:48 +00:00
Torsten Grote
cb61d91074 Add methods and hooks to PrivateGroupManager related to members and removal 2016-10-31 13:23:03 -02:00
akwizgran
399a4890de Merge branch '708-implement-protocol-for-private-group-messaging' into 'master'
Implement protocol for private group messaging

Closes #708

See merge request !360
2016-10-31 15:17:51 +00:00
Torsten Grote
656a947f5a Last minor review comments addressed 2016-10-31 13:13:59 -02:00
Torsten Grote
7191967092 Refactor contact lists, their adapters and items 2016-10-31 10:29:53 -02:00
Torsten Grote
5ce8b1978d Remove forum content type and move bodies to string
Also removes support for anonymous forum posts.
Closes #698
2016-10-31 10:25:12 -02:00
Torsten Grote
c0aa255bb6 Address review comments 2016-10-31 10:16:48 -02:00
Torsten Grote
c79ce61f6d Add PrivateGroupManager integration tests 2016-10-31 10:13:21 -02:00
Torsten Grote
0caabda303 Do additional validation on incoming private group messages 2016-10-31 10:13:21 -02:00
Torsten Grote
679b54b2b4 Show join messages properly in the threaded conversation 2016-10-31 10:13:20 -02:00
Torsten Grote
349a34ffd8 Return actual private group message headers and bodies to the UI 2016-10-31 10:12:26 -02:00
Torsten Grote
2c8aaa215c Posting group messages takes previous message into account 2016-10-31 10:11:35 -02:00
Torsten Grote
4f4f1956eb Creator automatically joins the group after creating it 2016-10-31 10:11:33 -02:00
Torsten Grote
e06726b2f9 Implement New Member and Join Announcements in GroupMessageFactory 2016-10-31 10:10:14 -02:00
Torsten Grote
a6e3827127 Implement first prototype of GroupMessageValidator 2016-10-31 10:09:17 -02:00
Torsten Grote
8dc529cc3f Move validator's signature verification into ClientHelper 2016-10-31 10:08:26 -02:00
akwizgran
1e36f21cc8 Merge branch '707-implement-ux-for-showing-and-answering-private-group-invitations' into 'master'
Implement UX for showing and answering private group invitations

As usual, this MR contains several logically separate commits that could be split out into smaller MRs if desired. It consists of two main parts:
* Showing open invitations in the list of private groups with a snackbar
* Showing invitations and responses in the private conversation

For both parts, the existing code was refactored to allow for a smooth implementation and to leave maintainable code behind.

![device-2016-10-18-101549](/uploads/66582dbe97736fdcd2498e87e1c7dfd1/device-2016-10-18-101549.png)
![device-2016-10-18-101612](/uploads/8c25eff8171f330796a55cb27cdb2552/device-2016-10-18-101612.png)
![device-2016-10-18-101534](/uploads/ebba4c0a2c0f727dcadac8c2ec57b48f/device-2016-10-18-101534.png)

Closes #707

See merge request !357
2016-10-31 12:02:22 +00:00
Torsten Grote
2cc650d85f Address review comments 2016-10-28 15:29:47 -02:00
akwizgran
3407d0c0a8 Merge branch 'protocol-state-exception' into 'master'
ProtocolStateException for client protocols

Methods that implement local actions in a client protocol (for example, accepting an invitation) can throw this exception to indicate that the action wasn't taken because the action isn't applicable to the current state. This can happen if the protocol state machine is updated by an incoming message and the user takes an action before the UI has been updated.

See merge request !368
2016-10-27 15:46:03 +00:00
akwizgran
ca8d3babaa Added ProtocolStateException for client protocols. 2016-10-27 11:57:36 +01:00
Torsten Grote
7b627bb427 Remove PartialItem interface and the need for casting ConversationItems 2016-10-27 08:22:52 -02:00
Torsten Grote
f027b832d4 Address review issues 2016-10-27 08:14:33 -02:00
Torsten Grote
42175dca7a Show group invitations and responses in private conversation 2016-10-27 08:14:33 -02:00
Torsten Grote
5ffcdc4e46 Refactor ConversationAdapter and its ConversationItems 2016-10-27 08:14:32 -02:00
Torsten Grote
e00219c15f Allow responding to sharing invitations based on SessionId 2016-10-27 08:14:32 -02:00
Torsten Grote
96666273d3 Show group invitations in group list 2016-10-27 08:14:32 -02:00
Torsten Grote
a92f7e1c9f Controllerize invitation activities 2016-10-27 08:14:31 -02:00
Torsten Grote
02a39f5694 Refactor events based on InvitationRequestReceivedEvent 2016-10-27 08:14:31 -02:00
Torsten Grote
a33d7d1663 Add a stub for a GroupInvitationManager 2016-10-27 08:14:30 -02:00
Ernir Erlingsson
8eeaf4e347 Merge branch '688-proguard-warns-about-missing-descriptor-classes' into 'master'
Fix proguard notes about unkept descriptor classes

Closes #688

See merge request !366
2016-10-26 20:32:43 +00:00
Torsten Grote
835bd86346 Fix proguard notes about unkept descriptor classes 2016-10-26 15:57:52 -02:00
akwizgran
84b2a171ab Merge branch '718-creating-a-group-without-having-contacts-can-cause-crash' into 'master'
Fix crash when navigating back in contact selector

Closes #718

See merge request !365
2016-10-26 17:08:07 +00:00
Torsten Grote
1df00f5702 Fix crash when navigating back in contact selector 2016-10-26 14:49:45 -02:00
akwizgran
292e1c3e8e Merge branch '715-long-posts-aren-t-rendered' into 'master'
Disable EmojiTextView software layer rendering when cache is too small

This needs to be tested if it works as intended on several devices.

See merge request !362
2016-10-26 15:09:56 +00:00
akwizgran
c8c0281efc Merge branch '686-crash-when-transitioning-out-of-reblogactivity' into 'master'
Limit scene transition animations to API 23 and above

to work-around [android bug #224270](https://code.google.com/p/android/issues/detail?id=224270).
This is only necessary if the transitioning view might not be available anymore when the exit transition is made.

Closes #686

See merge request !361
2016-10-26 10:11:32 +00:00
akwizgran
e8c48ccf8d Merge branch '661-implement-ux-for-creating-a-private-group' into 'master'
Implement UX for creating a private group

This MR allows the user to create a new private group and select contacts to be invited into the group.

There are currently 6 commits starting with some small refactoring for code reuse and making more functionality available in the backend. Each commit could be split up into a dedicated MR if desired.

![create-groups](/uploads/5229f102ee2611c05d5e9d1e2aac510d/create-groups.gif)

Closes #661

See merge request !353
2016-10-26 09:32:34 +00:00
Torsten Grote
09baa2ebe1 Add own constant for maximum group invitation message length 2016-10-26 07:28:51 -02:00
Torsten Grote
1176741ea4 Address actual review issues 2016-10-25 15:22:11 -02:00
Torsten Grote
e6def70030 Pre-address potential review issues 2016-10-25 14:58:50 -02:00
Torsten Grote
1a812f1327 UI for creating private groups 2016-10-25 14:58:47 -02:00
Torsten Grote
8dc3bd2c4c Implement private group creation and fetching in PrivateGroupManager 2016-10-25 14:57:43 -02:00
Torsten Grote
c934ec30aa Move Up button handling into BaseFragment 2016-10-25 14:57:43 -02:00
Torsten Grote
d5f6e71cba Create a reusable ContactSelectorActivity 2016-10-25 14:57:41 -02:00
Torsten Grote
feed2581c9 Factor out a reuseable MessageFragment 2016-10-25 14:56:25 -02:00
Torsten Grote
bd1f3fc2bd Make ContactSelectorFragment reusable 2016-10-25 14:52:27 -02:00
akwizgran
d25f4d1fbe Merge branch 'string-truncation' into 'master'
Truncate all messages to valid length before sending



See merge request !358
2016-10-25 15:52:35 +00:00
Torsten Grote
e84d1c5996 Update translations and expiry date 2016-10-25 08:19:15 -02:00
Torsten Grote
06831bafc3 Disable EmojiTextView software layer rendering when cache is too small 2016-10-24 17:20:57 -02:00
Torsten Grote
9284167a2e Limit scene transition animations to API 23 and above
to work-around android bug #224270.
This is only necessary if the transitioning view might not be available
anymore when the exit transition is made.
2016-10-24 15:34:24 -02:00
akwizgran
df44015ccb Merge branch '705-adapter-revisions' into 'master'
Fix race conditions when updating UI from events (again)

This is my second attempt at fixing race conditions caused by updating the UI from events while background tasks are loading data from the DB. Unlike my first attempt, this one is pretty simple and doesn't require too much reasoning about possible races.

The first commit fixes a few list loading bugs I found while working on this problem, and moves the lifecycle callbacks from resume/pause to start/stop, closing #609. The second commit contains the fix for #705, which works as follows:

* Each BriarAdapter has a revision counter
* Before making a change to the adapter that could be overwritten by a background task, increment the revision
* Before starting a background task that could overwrite other changes, get the current revision
* Before applying changes from a background task that could overwrite other changes, check whether the revision has changed
* If the revision has changed, restart the background task
* Otherwise apply the changes

Closes #609. #705 remains open because the PagerAdapters for blogs need to be updated.

See merge request !356
2016-10-21 10:28:02 +00:00
akwizgran
c4716ca457 BlogFragment doesn't need to use adapter revisions.
All changes to the adapter are cumulative.
2016-10-20 14:21:10 +01:00
akwizgran
9bb16b424f Moved revision counter methods into their own interface. 2016-10-20 12:44:09 +01:00
akwizgran
e8ebdc2884 Don't finish nav drawer fragments on error. 2016-10-20 11:55:39 +01:00
akwizgran
2140a290e4 Avoid race conditions when updating the UI from events. 2016-10-20 11:28:03 +01:00
akwizgran
50a70f7649 Use start/stop lifecycle callbacks rather than pause/resume.
Also fixed a couple of bugs.
2016-10-20 10:40:10 +01:00
akwizgran
b3e5d1ff85 Finished renaming entry to item, reduced some visibility. 2016-10-19 20:49:45 +01:00
Torsten Grote
690142ce07 Merge branch '712-bdf-list-out-of-bounds' into 'master'
Throw FormatException if BdfList index is out of bounds

Closes #712

See merge request !359
2016-10-19 17:49:14 +00:00
akwizgran
82eea6bb77 Throw FormatException if BdfList index is out of bounds. 2016-10-19 18:11:31 +01:00
Torsten Grote
3ad3332649 Merge branch '663-implement-ux-for-displaying-message-threads-in-private-groups' into 'master'
Private Group Threaded Conversation

This MR refactors the forum activity, its controller, its adapter and view holder so *most* of the code can be re-used for private groups by making heavy use of generics.

The refactoring has 1383 additions and 1087 deletions, so just grows the code-base slightly and adding the private group conversation just takes an additional 400 lines.

The MR also includes one commit that moves post/message creation more into clients, so the UI doesn't need to keep track of timestamps. This commit can of course be split out into a separate MR if desired.

Closes #662, #663 

See merge request !350
2016-10-19 16:42:24 +00:00
Torsten Grote
5a0fa5dcc7 Last round of addressing review issues 2016-10-19 14:38:11 -02:00
akwizgran
97223cce97 Fixed a typo in a constant. 2016-10-19 15:14:07 +01:00
akwizgran
08b191d72e Fixed a typo in a comment in a test. URGENT STUFF! 2016-10-19 15:04:24 +01:00
akwizgran
06335c2c30 Truncate all messages to valid length before sending. 2016-10-19 14:49:09 +01:00
Torsten Grote
8f882dc910 Addressing second round of review issues 2016-10-19 10:43:02 -02:00
Torsten Grote
0523c4e718 Address issues found in code review 2016-10-19 10:43:01 -02:00
Torsten Grote
7bf4aebdaf Move post/message creation into clients
This way the forum and private group client do not need to keep track of
message timestamps themselves and do not need to interact with
post/message factories.
2016-10-19 10:43:01 -02:00
Torsten Grote
6db59ffce5 Parsing and retrieval of private groups in PrivateGroupManager 2016-10-19 10:43:01 -02:00
Torsten Grote
e0835ad460 Add "Created by" to ActionBar 2016-10-19 10:43:00 -02:00
Torsten Grote
c83d4bbb39 Implement first prototype of private group message threads 2016-10-19 10:43:00 -02:00
Torsten Grote
65b47bb5d2 Refactor Forum Controller, so it can be used by private groups 2016-10-19 10:42:59 -02:00
Torsten Grote
9ce95d6de7 Refactor Forum Activity and adapters to be re-used for private groups 2016-10-19 10:42:59 -02:00
akwizgran
9d2c56e75f Upgraded Gradle plugin to 2.2.1. 2016-10-19 12:24:22 +01:00
akwizgran
32c4f61e68 Merge branch '670-uncaught-exceptions-do-not-print-a-stack-trace-in-introductionintegrationtest' into 'master'
Print stack trace for uncaught exceptions during tests for easier debugging

Closes #670

See merge request !355
2016-10-14 12:14:05 +00:00
Torsten Grote
6e04664915 Print stack trace for uncaught exceptions during tests for easier debugging 2016-10-14 08:44:47 -03:00
akwizgran
5674ee2d88 Converted group list controller to constructor injection. 2016-10-12 17:28:44 +01:00
akwizgran
8637faf858 Merge branch '704-constructor-injection' into 'master'
Use constructor injection for controllers

Also made some listeners volatile.

This is part of #704 - if I don't find any other classes that need constructor injection I'll close the ticket.

See merge request !351
2016-10-12 16:02:53 +00:00
akwizgran
970cbbf557 Merge branch 'not-null-by-default' into 'master'
Null safety annotations

The @NotNullByDefault annotation marks all fields, methods and parameters in a class or package @NotNull, so Android Studio will warn if values that may be null are used. Please use this annotation for new classes, and specify @Nullable for any fields, methods and parameters that may be null.

Injected fields are initialised to null, so injected classes should use @MethodsNotNullByDefault and @ParametersNotNullByDefault, or specify @Nullable for injected fields.

See merge request !349
2016-10-12 16:00:54 +00:00
akwizgran
57ac4a5374 Removed Maven Central repo. 2016-10-12 17:00:03 +01:00
akwizgran
2b91631ba5 Use constructor injection for controllers.
Also made some listeners volatile.
2016-10-11 12:31:21 +01:00
akwizgran
b327122255 Merge branch '660-implement-ux-for-the-list-of-private-groups' into 'master'
Private Group List UI

This MR implements the UI for the list of private groups.

It reacts to three types of events to refresh the displayed data:
* new group message received
* private group added
* private group removed

Missing from final implementation:
* entering groups
* adding new groups
* reacting to a future group dissolved event
* actually removing a dissolved group

![device-2016-09-29-180741](/uploads/666f04e8c9e2c81bdfe7f5648c14e71d/device-2016-09-29-180741.png)
![device-2016-10-03-141200](/uploads/5d0a54ea5a31d64404591c03ccf1e3b6/device-2016-10-03-141200.png)
![groups](/uploads/3eba757e21837739a129aab15100c06a/groups.gif)

Closes #660

See merge request !335
2016-10-11 10:22:26 +00:00
akwizgran
0b3ec9aa4c Merge branch '676-keyboard-isn-t-shown-when-forum-text-entry-field-gets-focus' into 'master'
Always show the keyboard when asked for it

The main fix is maintaining the internal keyboard state when the entire view gets hidden, because `onMeasure()` isn't called anymore in that case and can't update it itself.

Closes #676

See merge request !348
2016-10-11 09:47:27 +00:00
Torsten Grote
154e02723f Always show the keyboard when asked for it
and maintain keyboard state when hiding view.
2016-10-10 13:53:53 -03:00
Torsten Grote
b09e30a95f Private Group List 2016-10-10 13:48:34 -03:00
akwizgran
3ea36bbd40 Merge branch '551-destroyable-context' into 'master'
Always check whether the context has been destroyed

#551 has the same root cause as #610, which is that when a background operation completes, we need to check whether the activity or fragment that started the operation has been destroyed before doing anything with the UI. 

DestroyableActivity has been renamed to DestroyableContext because it's now implemented by some fragments as well. Various existing listener interfaces now extend DestroyableContext.

I also modified the ActivityLifecycleController interface so the activity is passed into the onActivityCreate() method rather than being injected - @ernir please check I haven't broken anything!

Closes #551

See merge request !341
2016-10-10 15:00:15 +00:00
akwizgran
cb983f02c2 Always check whether context has been destroyed. 2016-10-10 15:54:08 +01:00
akwizgran
f1730aa7d9 Merge branch '696-npe-key-agreement-task' into 'master'
Fix NPE when stopping KeyAgreementTask, improve thread safety

This branch fixes #696 and improves the thread safety of the camera code, mostly by adding @UiThread annotations and occasionally by moving stuff onto the UI thread that might have happened on other threads before.

Closes #696

See merge request !345
2016-10-10 14:46:25 +00:00
akwizgran
857665db79 Merge branch '373-slow-contact-list' into 'master'
Use new group metadata for showing lists

What was supposed to be a minimal change turned into a rather large MR. I did my best to keep things in separate commits, so I can still split this into smaller MRs if desired.

While making use of the new group metadata in the contact and forum list, I noticed some other things in need of improvement to get rid of needing to load all messages:
* Refactor `SharingManager` so its events provide message headers that can be used to update list items
* Add `GroupId` to conversation items, so the metadata of the respective group can be updated as well when marking the items read
* Create a very basic `ConversationManager` so the GroupCount for the various clients can be queried in one go without needing to know all their groups per contact
* Fix a nasty bug that caused forum and blog invitation to not update their read state
* Fix some bugs related to displaying the forum list with proper unread count

Some casual measurements with just a few contacts and messages showed a reduction of the contact list load time by one third.

See merge request !343
2016-10-10 14:00:36 +00:00
Torsten Grote
7f2db71160 Address review comments 2016-10-10 10:46:30 -03:00
akwizgran
60dee5c4cb Added null safety annotations. 2016-10-10 14:32:26 +01:00
Torsten Grote
784561144a Use new GroupCount to display Forum List
Fixes #531, #532
2016-10-10 08:00:17 -03:00
Torsten Grote
70d39d03bc Use group metadata from ConversationManager for showing contact lists
Fixes #373
2016-10-10 08:00:17 -03:00
Torsten Grote
48a3db46bc Properly pass message read state for sharing invitations and responses
Fixes #350
2016-10-10 08:00:16 -03:00
Torsten Grote
f52819f4ca Create a basic ConversationManager for querying GroupCount
This is also lays the groundwork for #384
2016-10-10 08:00:16 -03:00
Torsten Grote
457c30f3f2 Add GroupId to conversation items 2016-10-10 08:00:15 -03:00
Torsten Grote
1731369d7a Refactor SharingManager so its events provide message header 2016-10-10 08:00:12 -03:00
akwizgran
064b920626 Merge branch '687-refactor-adapters' into 'master'
Refactor existing adapters into a generic superclass

This MR also moves various blog classes into their own packages and makes the required visibility changes.

Closes #687

See merge request !346
2016-10-10 10:15:13 +00:00
Torsten Grote
b2fa039474 Refactor existing adapters into a generic superclass
This commit also moves various blog classes into their own packages and
makes the required visibility changes.
2016-10-06 11:30:10 -03:00
akwizgran
9112d17a4b Merge branch '611-body-cache-thread-safety' into 'master'
Make body cache thread-safe, reduce visibility of classes

Closes #611

See merge request !347
2016-10-06 13:43:09 +00:00
akwizgran
86fbb89637 Make body cache thread-safe, reduce visibility of classes. 2016-10-06 14:41:55 +01:00
akwizgran
b3bea1f945 Merge branch 'fix-introduction-unit-tests' into 'master'
Fix IntroductionManager unit tests

I forgot to run the unit tests after changing the `GroupCount` serialization in response to a review comment. This MR fixes the tests.

See merge request !344
2016-10-06 10:59:27 +00:00
akwizgran
543304973e Fixed an NPE, improved thread safety of camera code. 2016-10-06 11:53:07 +01:00
akwizgran
fc38738428 Merge branch '598-remove-unused-code' into 'master'
Remove unused UI code and layouts

If we ever need this code, it will be in the git history.

Closes #598

See merge request !342
2016-10-06 08:55:33 +00:00
Torsten Grote
d661fa0661 Fix IntroductionManager unit tests 2016-10-05 18:51:03 -03:00
akwizgran
e2eda8fef0 Merge branch '584-store-latest-timestamp-and-unread-count-in-group-metadata-for-private-messaging' into 'master'
Store message count, unread count and timestamp of latest message in group metadata

This is to eventually address #373 and slowness of other lists. The group metadata is not yet used, but if this MR isn't merged fast, another commit that actually uses it and thus takes care of the slowness will be added.

Closes #584, #585, #586

See merge request !336
2016-10-05 16:20:32 +00:00
akwizgran
604542c19b Remove unused UI code and layouts. 2016-10-05 17:09:16 +01:00
Torsten Grote
a727a0817e Store message count, unread count and timestamp of latest message
in group metadata to be able to speed up group listings.

Closes #584, #586, #585
2016-10-05 12:34:37 -03:00
Torsten Grote
3fa84ec7a8 Merge branch '680-release-camera-surface' into 'master'
Release camera surface to work around Android bug #54285

Closes #680

See merge request !340
2016-10-05 14:41:19 +00:00
Torsten Grote
e5f5511112 Merge branch 'identicon-cleanup' into 'master'
Clean up identicon code, remove unused classes

I noticed some debug-level logging coming from the identicon code, went in there to remove it, and realised half the code was unused, so I removed that too.

No functional changes except that the logging is gone and the opacity is now OPAQUE rather than UNKNOWN, which wasn't valid in this context.

See merge request !339
2016-10-05 14:38:17 +00:00
akwizgran
16ecb2ce8d Release surface to work around Android bug #54285. 2016-10-05 14:47:23 +01:00
akwizgran
c49c888f9f Merge branch '644-missing-header' into 'master'
Remove loading callbacks from fragment listener

Now fragments are responsible for their own Progress bars.

Closes #642

See merge request !316
2016-10-05 13:34:09 +00:00
Ernir Erlingsson
6b3db67ef5 removed fragment progress callback and fixed missing header 2016-10-05 14:21:14 +02:00
akwizgran
293c06fd61 Merge branch '92-emoticons' into 'master'
Emoji Support for all user input

All text that can be generated by users will show emoji from the shipped sprites by using the `EmojiTextView` instead of the normal `TextView`.

For all messages and posts, the custom emoji keyboard is now available as well. For this, a new `LargeTextInputView` has been introduced that is a sub-class of `TextInputView`. In order for the emoticon keyboard to work properly the existing views had to be modified heavily, sometimes resulting in new behavior such as scroll views now being above the fixed input field. Actual testing on a device (preferably with a tiny screen) is recommended to make sure this still works as expected. Screenshots will be included at the end of this post.

This MR also disables menu actions rather than hiding them and it includes a fix for a regression that was not showing the keyboard automatically in forums.

![device-2016-09-28-104914](/uploads/8ce9c8f61b32dc5a46b89a3a2cf1e6a4/device-2016-09-28-104914.png)
![device-2016-09-28-105026](/uploads/96ef9c40547c7a44fbc4517c87637a7e/device-2016-09-28-105026.png)
![device-2016-09-28-105041](/uploads/a0d1ed23ccb66e8bf9541737407142e3/device-2016-09-28-105041.png)
![device-2016-09-28-105440](/uploads/fb76ed2adc87600cfb0fc33c3962d4a6/device-2016-09-28-105440.png)
![device-2016-09-28-105515](/uploads/51f845d697cee3df38d1b9eef3c0ddfc/device-2016-09-28-105515.png)

Closes #92

See merge request !329
2016-10-05 11:01:12 +00:00
akwizgran
1c55fae704 Merge branch '695-introduction-failure' into 'master'
Fix regression in IntroduceeManager

This was happening when the remote response arrives before the local
response is made and thus the local response needs to be send with the
ACK following. The problem was that we ACK was sent before the response
which is not allowed and resulted in the session being aborted by the
introducee. This was happening, because recursion is hard ;)

The fix is only restarting another protocol engine to send the ACK
after the first run has been completed.

An integration test was added to prevent such regression in the future
and to test this code path.

Closes #695

See merge request !338
2016-10-04 21:38:48 +00:00
Torsten Grote
95670937c3 Fix regression in IntroduceeManager
This was happening when the remote response arrives before the local
response is made and thus the local response needs to be send with the
ACK following. The problem was that we ACK was sent before the response
which is not allowed and resulted in the session being aborted by the
introducee. This was happening, because recursion is hard ;)

The fix is only restarting another protocol engine to send the ACK
after the first run has been completed.

An integration test was added to prevent such regression in the future
and to test this code path.
2016-10-04 17:44:47 -03:00
Ernir Erlingsson
165deebb40 Merge branch '690-introduction-onboarding-is-shown-again-if-it-s-dismissed' into 'master'
Don't show introduction onboarding again no matter how dismissed

Closes #690

See merge request !337
2016-10-04 20:30:08 +00:00
Torsten Grote
0b0cae06ae Don't show introduction onboarding again no matter how dismissed 2016-10-04 14:51:37 -03:00
Torsten Grote
f8e0441de8 Emoji Support for all user input
All text that can be generated by users will show emoji from the
shipped sprites.

For all messages and posts, the custom emoji keyboard is now available.

This also disables menu actions rather than hiding them and thus
closes #677

Included is a fix for a regression that was not showing the keyboard
automatically in forums and thus
closes #676
2016-10-04 14:12:17 -03:00
akwizgran
a422c626b3 Merge branch '673-privategroupmanager-facade' into 'master'
Create PrivateGroupManager Facade and stub implementation

Some classes were renamed and new base classes introduced in the process. I suggest to expand the "Changed files" before reviewing to get an overview over the changes.

Closes #673

See merge request !332
2016-10-03 19:46:55 +00:00
Torsten Grote
6ece398a21 Create PrivateGroupManager Facade and stub implementation 2016-09-30 12:05:35 -03:00
akwizgran
8b50cb1461 Merge branch 'fix-integration-tests' into 'master'
Fix integration tests

First problem was a race condition with message delivery and the second
one due to the fact that we no longer plan to allow adding of additional
blogs, so the test for that has simply been removed.

See merge request !333
2016-09-29 16:43:56 +00:00
Torsten Grote
f28bc691a5 Merge branch '685-teaser-length' into 'master'
Check length of text after spanning

Closes #685

See merge request !334
2016-09-29 14:12:10 +00:00
akwizgran
42056720fa Check length of text after spanning. #685 2016-09-29 15:06:50 +01:00
Torsten Grote
0861ee1f10 Fix integration tests
First problem was a race condition with message delivery and the second
one due to the fact that we no longer plan to allow adding of additional
blogs, so the test for that has simply been removed.
2016-09-29 11:02:44 -03:00
akwizgran
a30de6309d Removed translated strings that were causing lint errors.
The app _name string is marked as non-translatable and the new_identity_item string no longer exists.
2016-09-29 12:47:29 +01:00
akwizgran
d112b42d20 Fixed obsolete ID in layout. 2016-09-29 12:45:56 +01:00
akwizgran
fd6719301a Merge branch '556-thread-safety-blocking-issues' into 'master'
Forum controller thread safety and tree safety

This branch solves the concurrent forum issues by code restructure and refactoring.

Closes #556 
Closes #552 

See merge request !262
2016-09-29 09:30:51 +00:00
Ernir Erlingsson
92f2e7b0fc merge with master and fixes after comments 2016-09-29 01:30:13 +02:00
akwizgran
ee98900613 Merge branch '644-missing-header-only' into 'master'
Remove toolbar animation to fix the missing toolbar on first start

Closes #644

See merge request !331
2016-09-28 17:03:55 +00:00
akwizgran
747553f577 Cleaned up identicon code, removed unused classes. 2016-09-28 17:34:12 +01:00
Torsten Grote
8a4c162bba Remove toolbar animation to fix the missing toolbar on first start 2016-09-28 13:33:09 -03:00
akwizgran
7e806c8cf2 Merge branch '679-own-personal-blogs-can-be-removed' into 'master'
Prevent personal blogs from being removed

This also adds unit tests to prevent regressions like this in the future.

Closes #679

See merge request !330
2016-09-28 16:22:46 +00:00
akwizgran
e466ed580c Merge branch '589-when-a-message-is-shared-share-its-transitive-dependencies' into 'master'
When a message is shared, share its transitive dependencies

Like other recursive operations on the dependency graph, this is
not done in a single transaction to prevent an attacker from creating
arbitrary large transactions.

So at startup, the `ValidationManager` finds and resumes any
unfinished operations, by looking for unshared messages with shared
dependents.

Closes #589

See merge request !325
2016-09-28 16:19:43 +00:00
Torsten Grote
d058172429 When a message is shared, share its transitive dependencies
Like other recursive operations on the dependency graph, this is
not done in a single transaction to prevent an attacker from creating
arbitrary large transactions.

So at startup, the `ValidationManager` finds and resumes any
unfinished operations, by looking for shared messages with unshared
dependencies.
2016-09-28 13:17:11 -03:00
Torsten Grote
1f0b305139 Prevent personal blogs from being removed
This also adds unit tests to prevent regressions like this in the
future.
2016-09-28 13:12:20 -03:00
Torsten Grote
7a0db798d1 bump expiry date and update translations 2016-09-28 11:56:55 -03:00
Torsten Grote
7e6a522eee Merge branch '346-camera-parameters' into 'master'
Try harder to find suitable camera parameters

This branch fixes QR code scanning on the Galaxy Nexus running Cyanogen Mod 12.1 (Android 5.1.1), without breaking QR code scanning on any of the other test devices.

The problem on the Galaxy Nexus was that the selected scene mode was overriding the selected focus mode, so we asked for continuous picture mode but got macro mode. Macro mode requires startAutoFocus() to be called, but we weren't calling it because we'd asked for continuous picture mode.

The fix for that problem is to query the focus mode after applying the parameters and call startAutoFocus() based on the actual mode rather than the requested mode.

But then I discovered another problem: barcode scene mode was setting the flash to auto, so in low light the flash was turning on and off while trying to scan QR codes. That might work well for printed QR codes, but it's terrible when scanning from a screen.

The fix for the new problem is to select barcode scene mode, then try to disable the flash, and if that fails, reset the scene mode. Then we pick the best available video stabilisation, focus mode and preview size.

On the Galaxy Nexus with CM 12.1, that means we use continuous picture mode instead of barcode scene mode, which works fine. All the other test devices pick the same settings as before.

See merge request !321
2016-09-28 14:40:56 +00:00
akwizgran
33795e7046 Use compareAndSet() instead of locking. 2016-09-27 23:02:54 +02:00
Ernir Erlingsson
2d59b9095c Fixing concurrency issues and refactoring code 2016-09-27 23:02:44 +02:00
Torsten Grote
8fb820c967 Merge branch 'check-if-listfiles-returns-null' into 'master'
Check whether File#listFiles() returns null

The docs say this can happen if there's an I/O error. Also fixed a throw-in-finally-block warning and renamed an IoUtils method to make its contract clearer.

See merge request !328
2016-09-27 16:17:09 +00:00
akwizgran
53d0b8b21e Check whether File#listFiles() returns null.
The docs say this can happen for a directory if there's an I/O error.
2016-09-27 15:52:57 +01:00
akwizgran
d389f79a48 Merge branch '346-remove-base32-todos' into 'master'
Remove base32 TODOs, fix a potential NPE

I thought we'd be able to get higher data density in QR codes by using base32 instead of base64, allowing the QR code to use alphanumeric mode instead of byte mode. But I tried it, and although the QR code does use alphanumeric mode, it comes out at exactly the same size (see the 346-use-base32-for-qr-codes branch). So this MR removes the TODOs and fixes a potential NPE I spotted while working on the other branch.

See merge request !327
2016-09-27 14:19:45 +00:00
akwizgran
b278c7d9cb Remove base32 TODOs - base64 is just as good. 2016-09-27 13:31:07 +01:00
Torsten Grote
a85043efb5 Merge branch 'recreate-cache-dir' into 'master'
Recreate cache directory after deleting app data

This fixes a warning on the Moto G:
```
E/libEGL: error creating cache file /data/data/org.briarproject/cache/com.android.opengl.shaders_cache: No such file or directory (2)
```

@grote might possibly be related to hardware rendering issues.

See merge request !326
2016-09-27 12:07:43 +00:00
akwizgran
133722dd2c Code cleanup. 2016-09-27 11:51:24 +01:00
akwizgran
9e3db12ea2 Recreate the cache dir after deleting app data. 2016-09-27 11:44:14 +01:00
akwizgran
f461ec4ab0 Merge branch '627-tests-for-introduction-security-properties' into 'master'
Add more introduction tests for fake MAC and modified timestamp

Closes #627, #669

See merge request !315
2016-09-26 17:09:56 +00:00
Torsten Grote
e87c301e3a Add more introduction tests for fake MAC and modified timestamp 2016-09-26 13:31:00 -03:00
akwizgran
17bacc1116 Merge branch '357-introduction-feature-is-not-very-visible' into 'master'
Add first onboarding screen

When the user enters a private conversation after adding her second
contact, an onboarding screen will be shown highlighting the possibility
of introducing the contacts to each other.

![intro2](/uploads/b2cd4377f39974ca1fbd95649558e487/intro2.gif)

Closes #357

See merge request !324
2016-09-26 14:30:45 +00:00
Torsten Grote
401abf2c0c Add first onboarding screen
When the user enters a private conversation after adding her second
contact, an onboarding screen will be shown highlighting the possibility
of introducing the contacts to each other.
2016-09-26 10:42:20 -03:00
akwizgran
a4d08f4cf1 Try harder to find suitable camera parameters. #346 2016-09-26 12:14:23 +01:00
akwizgran
eb6189150f Merge branch '92-emoticons' into 'master'
Emoji

This MR introduces a custom Emoji implementation to Briar for devices that do not support Emoji sufficiently. It is heavily based on Signal's implementation. Hence, the license for the Android part has been changed to GPLv3.

So far, emoji input is only supported for forums and private conversations that both rely on the same `TextInputView`.

![emoji2](/uploads/f69af031e72efb0bd6f0f67a9574d11f/emoji2.gif)

See merge request !317
2016-09-23 16:31:38 +00:00
akwizgran
c917110e6a Emoji: minor bug fixes, code cleanup, logging, visibility, 2016-09-23 17:18:21 +01:00
Torsten Grote
d5beca5351 Port Signal's emoji implementation to Briar
Add functionality to save and restore recently used Emojis

Update emoji and add new categories based on AOSP's XML file
2016-09-23 17:18:18 +01:00
akwizgran
1fdbe65dde Fixed a broken test. 2016-09-23 11:34:02 +01:00
Torsten Grote
1583163f88 Merge branch '538-recipient-offers-message-to-sender' into 'master'
Don't offer messages back to the sender

Closes #538

See merge request !323
2016-09-22 15:02:06 +00:00
akwizgran
ee35110167 Merge branch '625-avoid-repeated-author-status-lookups' into 'master'
Avoid repeated author status lookups

Closes #625

See merge request !322
2016-09-22 13:18:45 +00:00
akwizgran
72bf701345 Mark a received message as seen by the sender. 2016-09-22 11:31:32 +01:00
Torsten Grote
fd4dbdc081 Avoid repeated author status lookups 2016-09-21 17:26:24 -03:00
akwizgran
97937428bb Merge branch '329-btp-header' into 'master'
Include stream number in stream header nonce

See the corresponding change in the BTP spec for an explanation:
388e1d23c0

Closes #329

See merge request !320
2016-09-21 08:58:36 +00:00
akwizgran
4be1c1bb7d Include stream number in stream header nonce. 2016-09-20 15:27:01 +01:00
1799 changed files with 80356 additions and 47726 deletions

7
.gitignore vendored
View File

@@ -9,15 +9,18 @@ Thumbs.db
.DS_Store .DS_Store
# Eclipse project files # Eclipse project files
#.classpath .classpath
#.project .project
.settings
# Local configuration file (sdk path, etc) # Local configuration file (sdk path, etc)
local.properties local.properties
# Android Studio # Android Studio
.idea/* .idea/*
!.idea/runConfigurations/
!.idea/codeStyleSettings.xml !.idea/codeStyleSettings.xml
.gradle .gradle
build/ build/
*.iml *.iml
projectFilesBackup/

29
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,29 @@
image: registry.gitlab.com/fdroid/ci-images-base:latest
cache:
paths:
- .gradle/wrapper
- .gradle/caches
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
# Accept the license for the Android build tools
- echo y | /opt/android-sdk/tools/bin/sdkmanager "build-tools;26.0.2"
# Download OpenJDK 6 so we can compile against its standard library
- JDK_FILE=openjdk-6-jre-headless_6b38-1.13.10-1~deb7u1_amd64.deb
- if [ ! -d openjdk ]
- then
- wget -q http://ftp.uk.debian.org/debian/pool/main/o/openjdk-6/$JDK_FILE
- dpkg-deb -x $JDK_FILE openjdk
- fi
- export JAVA_6_HOME=$PWD/openjdk/usr/lib/jvm/java-6-openjdk-amd64
test:
script:
- ./gradlew test
after_script:
# this file changes 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/

View File

@@ -31,6 +31,8 @@
</value> </value>
</option> </option>
<option name="RIGHT_MARGIN" value="100" /> <option name="RIGHT_MARGIN" value="100" />
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
<AndroidXmlCodeStyleSettings> <AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" /> <option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings> </AndroidXmlCodeStyleSettings>

28
.idea/runConfigurations/All_tests.xml generated Normal file
View File

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

View File

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

View File

@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="briar-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<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

@@ -13,23 +13,6 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------
All files under the directories briar-android/src, briar-api/src,
briar-core/src, briar-desktop/src and briar-test/src are licensed
under the Apache License, version 2.0 (the "License"); you may not
use these files except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
------------------------------------------------------------------------- -------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE

View File

@@ -1,5 +1,5 @@
bin bin
gen gen
build build
local.properties
.settings .settings
src/main/res/raw/*.zip

View File

@@ -0,0 +1,95 @@
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
apply plugin: 'com.android.library'
apply plugin: 'witness'
apply plugin: 'de.undercouch.download'
android {
compileSdkVersion 27
buildToolsVersion '26.0.2'
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 1616
versionName "0.16.16"
consumerProguardFiles 'proguard-rules.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification {
verify = [
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128-runtime.jar:e357a0f1d573c2f702a273992b1b6cb661734f66311854efb3778a888515c5b5',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128.jar:47b4bec6df11a1118da3953da8b9fa1e7079d6fec857faa1a3cf912e53a6fd4e',
'org.jacoco:org.jacoco.ant:0.7.4.201502262128:org.jacoco.ant-0.7.4.201502262128.jar:013ce2a68ba57a3c59215ae0dec4df3498c078062a38c3b94c841fc14450f283',
'org.jacoco:org.jacoco.core:0.7.4.201502262128:org.jacoco.core-0.7.4.201502262128.jar:ec4c74554312fac5116350164786f91b35c9e082fa4ea598bfa42b5db05d7abb',
'org.jacoco:org.jacoco.report:0.7.4.201502262128:org.jacoco.report-0.7.4.201502262128.jar:7a3554c605e088e7e323b1084656243f0444fa353e2f2dee1f1a4204eb64ff09',
'org.ow2.asm:asm-debug-all:5.0.1:asm-debug-all-5.0.1.jar:4734de5b515a454b0096db6971fb068e5f70e6f10bbee2b3bd2fdfe5d978ed57',
]
}
ext.torBinaryDir = 'src/main/res/raw'
ext.torVersion = '0.2.9.14'
ext.geoipVersion = '2017-11-06'
ext.torDownloadUrl = 'https://briarproject.org/build/'
def torBinaries = [
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
]
def downloadBinary(name) {
return tasks.create("downloadBinary${name}", Download) {
src "${torDownloadUrl}${name}.zip"
.replace('tor_', "tor-${torVersion}-")
.replace('geoip', "geoip-${geoipVersion}")
.replaceAll('_', '-')
dest "${torBinaryDir}/${name}.zip"
onlyIfNewer true
}
}
def verifyBinary(name, chksum) {
return tasks.create([
name : "verifyBinary${name}",
type : Verify,
dependsOn: downloadBinary(name)]) {
src "${torBinaryDir}/${name}.zip"
algorithm 'SHA-256'
checksum chksum
}
}
project.afterEvaluate {
torBinaries.every { key, value ->
preBuild.dependsOn.add(verifyBinary(key, value))
}
}

Binary file not shown.

View File

@@ -0,0 +1,15 @@
-keep,includedescriptorclasses class org.briarproject.** { *; }
-keep class org.h2.** { *; }
-dontwarn org.h2.**
-dontnote org.h2.**
-keep class dagger.** { *; }
-dontwarn dagger.**
-dontnote dagger.**
-dontwarn sun.misc.Unsafe
-dontnote com.google.common.**
# UPnP library isn't used
-dontwarn org.bitlet.weupnp.**

View File

@@ -0,0 +1,22 @@
<manifest
package="org.briarproject.bramble"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.bluetooth"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="false"
android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

View File

@@ -0,0 +1,13 @@
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,4 +1,4 @@
package org.briarproject.android.api; package org.briarproject.bramble.api.system;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;

View File

@@ -1,20 +1,21 @@
package org.briarproject.plugins; package org.briarproject.bramble.plugin;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import org.briarproject.android.api.AndroidExecutor; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.api.plugins.PluginConfig; import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.api.reporting.DevReporter; import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.api.system.LocationUtils; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.plugins.droidtooth.DroidtoothPluginFactory; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.plugins.tcp.AndroidLanTcpPluginFactory; import org.briarproject.bramble.plugin.droidtooth.DroidtoothPluginFactory;
import org.briarproject.plugins.tor.TorPluginFactory; import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
@@ -28,25 +29,26 @@ import dagger.Module;
import dagger.Provides; import dagger.Provides;
@Module @Module
public class AndroidPluginsModule { public class AndroidPluginModule {
@Provides @Provides
public PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor, PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
AndroidExecutor androidExecutor, SecureRandom random, AndroidExecutor androidExecutor, SecureRandom random,
SocketFactory torSocketFactory, BackoffFactory backoffFactory, SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Application app, LocationUtils locationUtils, DevReporter reporter, Application app, LocationUtils locationUtils, DevReporter reporter,
EventBus eventBus) { EventBus eventBus) {
Context appContext = app.getApplicationContext(); Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor, DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
androidExecutor, appContext, random, backoffFactory); androidExecutor, appContext, random, eventBus, backoffFactory);
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext, DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
locationUtils, reporter, eventBus, torSocketFactory, locationUtils, reporter, eventBus, torSocketFactory,
backoffFactory); backoffFactory);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
backoffFactory, appContext); backoffFactory, appContext);
final Collection<DuplexPluginFactory> duplex = Collection<DuplexPluginFactory> duplex =
Arrays.asList(bluetooth, tor, lan); Arrays.asList(bluetooth, tor, lan);
return new PluginConfig() { @NotNullByDefault
PluginConfig pluginConfig = new PluginConfig() {
@Override @Override
public Collection<DuplexPluginFactory> getDuplexFactories() { public Collection<DuplexPluginFactory> getDuplexFactories() {
@@ -58,5 +60,6 @@ public class AndroidPluginsModule {
return Collections.emptyList(); return Collections.emptyList();
} }
}; };
return pluginConfig;
} }
} }

View File

@@ -0,0 +1,490 @@
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.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
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.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
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.security.SecureRandom;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
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 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, EventListener {
private static final Logger LOG =
Logger.getLogger(DroidtoothPlugin.class.getName());
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(
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)) {
enableAdapter();
} else {
LOG.info("Not enabling Bluetooth");
}
}
}
private void bind() {
ioExecutor.execute(() -> {
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);
}
private void enableAdapter() {
if (adapter != null && !adapter.isEnabled()) {
if (adapter.enable()) {
LOG.info("Enabling Bluetooth");
wasEnabledByUs = true;
} else {
LOG.info("Could not enable Bluetooth");
}
}
}
@Override
public void stop() {
running = false;
if (receiver != null) appContext.unregisterReceiver(receiver);
tryToClose(socket);
disableAdapter();
}
private void disableAdapter() {
if (adapter != null && adapter.isEnabled() && wasEnabledByUs) {
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()) {
ContactId c = e.getKey();
if (connected.contains(c)) continue;
String address = e.getValue().get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(() -> {
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(c);
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 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 key agreement 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);
}
@Override
public void eventOccurred(Event e) {
if (e instanceof EnableBluetoothEvent) {
enableAdapterAsync();
} else if (e instanceof DisableBluetoothEvent) {
disableAdapterAsync();
}
}
private void enableAdapterAsync() {
ioExecutor.execute(this::enableAdapter);
}
private void disableAdapterAsync() {
ioExecutor.execute(this::disableAdapter);
}
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 BluetoothKeyAgreementListener extends KeyAgreementListener {
private final BluetoothServerSocket ss;
private BluetoothKeyAgreementListener(BdfList descriptor,
BluetoothServerSocket ss) {
super(descriptor);
this.ss = ss;
}
@Override
public Callable<KeyAgreementConnection> listen() {
return () -> {
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

@@ -1,18 +1,26 @@
package org.briarproject.plugins.droidtooth; package org.briarproject.bramble.plugin.droidtooth;
import android.content.Context; import android.content.Context;
import org.briarproject.android.api.AndroidExecutor; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.api.plugins.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
@Immutable
@NotNullByDefault
public class DroidtoothPluginFactory implements DuplexPluginFactory { public class DroidtoothPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
@@ -24,21 +32,24 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
private final AndroidExecutor androidExecutor; private final AndroidExecutor androidExecutor;
private final Context appContext; private final Context appContext;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final EventBus eventBus;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
public DroidtoothPluginFactory(Executor ioExecutor, public DroidtoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, Context appContext, AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, BackoffFactory backoffFactory) { SecureRandom secureRandom, EventBus eventBus,
BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.appContext = appContext; this.appContext = appContext;
this.secureRandom = secureRandom; this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
} }
@Override @Override
public TransportId getId() { public TransportId getId() {
return DroidtoothPlugin.ID; return ID;
} }
@Override @Override
@@ -50,7 +61,10 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) { public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext, DroidtoothPlugin plugin = new DroidtoothPlugin(ioExecutor,
secureRandom, backoff, callback, MAX_LATENCY); androidExecutor, appContext, secureRandom, backoff, callback,
MAX_LATENCY);
eventBus.addListener(plugin);
return plugin;
} }
} }

View File

@@ -1,14 +1,16 @@
package org.briarproject.plugins.droidtooth; package org.briarproject.bramble.plugin.droidtooth;
import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothSocket;
import org.briarproject.api.plugins.Plugin; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection; import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@NotNullByDefault
class DroidtoothTransportConnection extends AbstractDuplexTransportConnection { class DroidtoothTransportConnection extends AbstractDuplexTransportConnection {
private final BluetoothSocket socket; private final BluetoothSocket socket;

View File

@@ -1,4 +1,4 @@
package org.briarproject.plugins.tcp; package org.briarproject.bramble.plugin.tcp;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -7,16 +7,20 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import org.briarproject.api.plugins.Backoff; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
@NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin { class AndroidLanTcpPlugin extends LanTcpPlugin {
private static final Logger LOG = private static final Logger LOG =
@@ -24,6 +28,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
private final Context appContext; private final Context appContext;
@Nullable
private volatile BroadcastReceiver networkStateReceiver = null; private volatile BroadcastReceiver networkStateReceiver = null;
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff, AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff,
@@ -34,14 +39,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
} }
@Override @Override
public boolean start() { public void start() {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
// Register to receive network status events // Register to receive network status events
networkStateReceiver = new NetworkStateReceiver(); networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION); IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
appContext.registerReceiver(networkStateReceiver, filter); appContext.registerReceiver(networkStateReceiver, filter);
return true;
} }
@Override @Override

View File

@@ -1,16 +1,23 @@
package org.briarproject.plugins.tcp; package org.briarproject.bramble.plugin.tcp;
import android.content.Context; import android.content.Context;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.api.plugins.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginFactory; 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.Executor;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
@Immutable
@NotNullByDefault
public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
@@ -32,7 +39,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
@Override @Override
public TransportId getId() { public TransportId getId() {
return LanTcpPlugin.ID; return ID;
} }
@Override @Override

View File

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

View File

@@ -1,4 +1,4 @@
package org.briarproject.plugins.tor; package org.briarproject.bramble.plugin.tor;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -7,6 +7,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.FileObserver; import android.os.FileObserver;
@@ -15,26 +16,28 @@ import android.os.PowerManager;
import net.freehaven.tor.control.EventHandler; import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection; import net.freehaven.tor.control.TorControlConnection;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.api.contact.ContactId; import org.briarproject.bramble.api.event.Event;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.api.event.Event; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.api.event.EventListener; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.api.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.api.keyagreement.TransportDescriptor; import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.api.plugins.Backoff; import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.api.plugins.TorConstants; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.api.reporting.DevReporter; import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.api.system.LocationUtils; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.util.IoUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.util.StringUtils; import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable; import java.io.Closeable;
import java.io.EOFException; import java.io.EOFException;
@@ -52,6 +55,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -60,6 +64,7 @@ import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.CONNECTIVITY_SERVICE;
@@ -73,12 +78,20 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS; import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY; import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.api.plugins.TorConstants.CONTROL_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.util.PrivacyUtils.scrubOnion; import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class TorPlugin implements DuplexPlugin, EventHandler, EventListener { class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final String PROP_ONION = "onion";
private static final String[] EVENTS = { private static final String[] EVENTS = {
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR" "CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
}; };
@@ -136,7 +149,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
Object o = appContext.getSystemService(POWER_SERVICE); Object o = appContext.getSystemService(POWER_SERVICE);
PowerManager pm = (PowerManager) o; PowerManager pm = (PowerManager) o;
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "TorPlugin"); // This tag will prevent Huawei's powermanager from killing us.
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService");
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
} }
@@ -156,14 +170,18 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
@Override @Override
public boolean start() throws IOException { public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
// Install or update the assets if necessary // Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets(); if (!assetsAreUpToDate()) installAssets();
LOG.info("Starting Tor"); LOG.info("Starting Tor");
// Watch for the auth cookie file being updated // Watch for the auth cookie file being updated
try {
cookieFile.getParentFile().mkdirs(); cookieFile.getParentFile().mkdirs();
cookieFile.createNewFile(); cookieFile.createNewFile();
} catch (IOException e) {
throw new PluginException(e);
}
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
FileObserver obs = new WriteObserver(cookieFile, latch); FileObserver obs = new WriteObserver(cookieFile, latch);
obs.startWatching(); obs.startWatching();
@@ -171,19 +189,31 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
String torPath = torFile.getAbsolutePath(); String torPath = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath(); String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid()); String pid = String.valueOf(android.os.Process.myPid());
String[] cmd = {torPath, "-f", configPath, OWNER, pid};
String[] env = {"HOME=" + torDirectory.getAbsolutePath()};
Process torProcess; Process torProcess;
ProcessBuilder pb =
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
Map<String, String> env = pb.environment();
env.put("HOME", torDirectory.getAbsolutePath());
pb.directory(torDirectory);
try { try {
torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory); torProcess = pb.start();
} catch (SecurityException e) { } catch (SecurityException | IOException e) {
throw new IOException(e); throw new PluginException(e);
} }
// Log the process's standard output until it detaches // Log the process's standard output until it detaches
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
Scanner stdout = new Scanner(torProcess.getInputStream()); Scanner stdout = new Scanner(torProcess.getInputStream());
while (stdout.hasNextLine()) LOG.info(stdout.nextLine()); Scanner stderr = new Scanner(torProcess.getErrorStream());
while (stdout.hasNextLine() || stderr.hasNextLine()){
if(stdout.hasNextLine()) {
LOG.info(stdout.nextLine());
}
if(stderr.hasNextLine()){
LOG.info(stderr.nextLine());
}
}
stdout.close(); stdout.close();
stderr.close();
} }
try { try {
// Wait for the process to detach or exit // Wait for the process to detach or exit
@@ -191,19 +221,20 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (exit != 0) { if (exit != 0) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING))
LOG.warning("Tor exited with value " + exit); LOG.warning("Tor exited with value " + exit);
return false; throw new PluginException();
} }
// Wait for the auth cookie file to be created/updated // Wait for the auth cookie file to be created/updated
if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) { if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
LOG.warning("Auth cookie not created"); LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory); if (LOG.isLoggable(INFO)) listFiles(torDirectory);
return false; throw new PluginException();
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.warning("Interrupted while starting Tor"); LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return false; throw new PluginException();
} }
try {
// Open a control connection and authenticate using the cookie file // Open a control connection and authenticate using the cookie file
controlSocket = new Socket("127.0.0.1", CONTROL_PORT); controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
controlConnection = new TorControlConnection(controlSocket); controlConnection = new TorControlConnection(controlSocket);
@@ -221,13 +252,15 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Tor has already bootstrapped"); LOG.info("Tor has already bootstrapped");
connectionStatus.setBootstrapped(); connectionStatus.setBootstrapped();
} }
} catch (IOException e) {
throw new PluginException(e);
}
// Register to receive network status events // Register to receive network status events
networkStateReceiver = new NetworkStateReceiver(); networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION); IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
appContext.registerReceiver(networkStateReceiver, filter); appContext.registerReceiver(networkStateReceiver, filter);
// Bind a server socket to receive incoming hidden service connections // Bind a server socket to receive incoming hidden service connections
bind(); bind();
return true;
} }
private boolean assetsAreUpToDate() { private boolean assetsAreUpToDate() {
@@ -240,7 +273,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
private void installAssets() throws IOException { private void installAssets() throws PluginException {
InputStream in = null; InputStream in = null;
OutputStream out = null; OutputStream out = null;
try { try {
@@ -248,48 +281,54 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// Unzip the Tor binary to the filesystem // Unzip the Tor binary to the filesystem
in = getTorInputStream(); in = getTorInputStream();
out = new FileOutputStream(torFile); out = new FileOutputStream(torFile);
IoUtils.copy(in, out); IoUtils.copyAndClose(in, out);
// Make the Tor binary executable // Make the Tor binary executable
if (!torFile.setExecutable(true, true)) throw new IOException(); if (!torFile.setExecutable(true, true)) throw new IOException();
// Unzip the GeoIP database to the filesystem // Unzip the GeoIP database to the filesystem
in = getGeoIpInputStream(); in = getGeoIpInputStream();
out = new FileOutputStream(geoIpFile); out = new FileOutputStream(geoIpFile);
IoUtils.copy(in, out); IoUtils.copyAndClose(in, out);
// Copy the config file to the filesystem // Copy the config file to the filesystem
in = getConfigInputStream(); in = getConfigInputStream();
out = new FileOutputStream(configFile); out = new FileOutputStream(configFile);
IoUtils.copy(in, out); IoUtils.copyAndClose(in, out);
doneFile.createNewFile(); doneFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
tryToClose(in); tryToClose(in);
tryToClose(out); tryToClose(out);
throw e; throw new PluginException(e);
} }
} }
private InputStream getTorInputStream() throws IOException { private InputStream getTorInputStream() throws IOException {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Installing Tor binary for " + architecture); LOG.info("Installing Tor binary for " + architecture);
String filename = "tor-" + architecture + ".zip"; int resId = getResourceId("tor_" + architecture);
InputStream in = appContext.getResources().getAssets().open(filename); InputStream in = appContext.getResources().openRawResource(resId);
ZipInputStream zin = new ZipInputStream(in); ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException(); if (zin.getNextEntry() == null) throw new IOException();
return zin; return zin;
} }
private InputStream getGeoIpInputStream() throws IOException { private InputStream getGeoIpInputStream() throws IOException {
String filename = "geoip.zip"; int resId = getResourceId("geoip");
InputStream in = appContext.getResources().getAssets().open(filename); InputStream in = appContext.getResources().openRawResource(resId);
ZipInputStream zin = new ZipInputStream(in); ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException(); if (zin.getNextEntry() == null) throw new IOException();
return zin; return zin;
} }
private InputStream getConfigInputStream() throws IOException { private InputStream getConfigInputStream() throws IOException {
return appContext.getResources().getAssets().open("torrc"); int resId = getResourceId("torrc");
return appContext.getResources().openRawResource(resId);
} }
private void tryToClose(Closeable c) { private int getResourceId(String filename) {
Resources res = appContext.getResources();
return res.getIdentifier(filename, "raw", appContext.getPackageName());
}
private void tryToClose(@Nullable Closeable c) {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
@@ -297,7 +336,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
private void tryToClose(Socket s) { private void tryToClose(@Nullable Socket s) {
try { try {
if (s != null) s.close(); if (s != null) s.close();
} catch (IOException e) { } catch (IOException e) {
@@ -306,8 +345,12 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
private void listFiles(File f) { private void listFiles(File f) {
if (f.isDirectory()) for (File child : f.listFiles()) listFiles(child); if (f.isDirectory()) {
else LOG.info(f.getAbsolutePath()); File[] children = f.listFiles();
if (children != null) for (File child : children) listFiles(child);
} else {
LOG.info(f.getAbsolutePath());
}
} }
private byte[] read(File f) throws IOException { private byte[] read(File f) throws IOException {
@@ -322,27 +365,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
return b; return b;
} finally { } finally {
in.close(); tryToClose(in);
} }
} }
private void sendDevReports() { private void sendDevReports() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(() -> {
@Override
public void run() {
// TODO: Trigger this with a TransportEnabledEvent // TODO: Trigger this with a TransportEnabledEvent
File reportDir = AndroidUtils.getReportDir(appContext); File reportDir = AndroidUtils.getReportDir(appContext);
reporter.sendReports(reportDir); reporter.sendReports(reportDir);
}
}); });
} }
private void bind() { private void bind() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(() -> {
@Override
public void run() {
// If there's already a port number stored in config, reuse it // If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get("port"); String portString = callback.getSettings().get(PREF_TOR_PORT);
int port; int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0; if (StringUtils.isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString); else port = Integer.parseInt(portString);
@@ -352,8 +390,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
ss = new ServerSocket(); ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port)); ss.bind(new InetSocketAddress("127.0.0.1", port));
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
LOG.log(WARNING, e.toString(), e);
tryToClose(ss); tryToClose(ss);
return; return;
} }
@@ -363,25 +400,19 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
socket = ss; socket = ss;
// Store the port number // Store the port number
final String localPort = String.valueOf(ss.getLocalPort()); String localPort = String.valueOf(ss.getLocalPort());
Settings s = new Settings(); Settings s = new Settings();
s.put("port", localPort); s.put(PREF_TOR_PORT, localPort);
callback.mergeSettings(s); callback.mergeSettings(s);
// Create a hidden service if necessary // Create a hidden service if necessary
ioExecutor.execute(new Runnable() { ioExecutor.execute(() -> publishHiddenService(localPort));
@Override
public void run() {
publishHiddenService(localPort);
}
});
backoff.reset(); backoff.reset();
// Accept incoming hidden service connections from Tor // Accept incoming hidden service connections from Tor
acceptContactConnections(ss); acceptContactConnections(ss);
}
}); });
} }
private void tryToClose(ServerSocket ss) { private void tryToClose(@Nullable ServerSocket ss) {
try { try {
if (ss != null) ss.close(); if (ss != null) ss.close();
} catch (IOException e) { } catch (IOException e) {
@@ -460,7 +491,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
@Override @Override
public void stop() throws IOException { public void stop() throws PluginException {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
if (networkStateReceiver != null) if (networkStateReceiver != null)
@@ -497,29 +528,33 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
// TODO: Pass properties to connectAndCallBack() Map<ContactId, TransportProperties> remote =
for (ContactId c : callback.getRemoteProperties().keySet()) callback.getRemoteProperties();
if (!connected.contains(c)) connectAndCallBack(c); for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
ContactId c = e.getKey();
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
}
} }
private void connectAndCallBack(final ContactId c) { private void connectAndCallBack(ContactId c, TransportProperties p) {
ioExecutor.execute(new Runnable() { ioExecutor.execute(() -> {
@Override if (!isRunning()) return;
public void run() { DuplexTransportConnection d = createConnection(p);
DuplexTransportConnection d = createConnection(c);
if (d != null) { if (d != null) {
backoff.reset(); backoff.reset();
callback.outgoingConnectionCreated(c, d); callback.outgoingConnectionCreated(c, d);
} }
}
}); });
} }
@Override @Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null; if (!isRunning()) return null;
TransportProperties p = callback.getRemoteProperties().get(c); return createConnection(callback.getRemoteProperties(c));
if (p == null) return null; }
@Nullable
private DuplexTransportConnection createConnection(TransportProperties p) {
String onion = p.get(PROP_ONION); String onion = p.get(PROP_ONION);
if (StringUtils.isNullOrEmpty(onion)) return null; if (StringUtils.isNullOrEmpty(onion)) return null;
if (!ONION.matcher(onion).matches()) { if (!ONION.matcher(onion).matches()) {
@@ -547,17 +582,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 @Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return false; return false;
@@ -570,7 +594,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, TransportDescriptor d, long timeout) { byte[] commitment, BdfList descriptor, long timeout) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -642,7 +666,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) { if (e instanceof SettingsUpdatedEvent) {
if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) { SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) {
LOG.info("Tor settings updated"); LOG.info("Tor settings updated");
updateConnectionStatus(); updateConnectionStatus();
} }
@@ -650,9 +675,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
private void updateConnectionStatus() { private void updateConnectionStatus() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(() -> {
@Override
public void run() {
if (!running) return; if (!running) return;
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE); Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
@@ -664,7 +687,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked( boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country); country);
Settings s = callback.getSettings(); Settings s = callback.getSettings();
boolean useMobileData = s.getBoolean("torOverMobile", true); int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi); LOG.info("Online: " + online + ", wifi: " + wifi);
@@ -679,7 +702,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} else if (blocked) { } else if (blocked) {
LOG.info("Disabling network, country is blocked"); LOG.info("Disabling network, country is blocked");
enableNetwork(false); enableNetwork(false);
} else if (!wifi && !useMobileData) { } else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting"); LOG.info("Disabling network due to data setting");
enableNetwork(false); enableNetwork(false);
} else { } else {
@@ -687,9 +711,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
enableNetwork(true); enableNetwork(true);
} }
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
LOG.log(WARNING, e.toString(), e);
}
} }
}); });
} }

View File

@@ -1,25 +1,29 @@
package org.briarproject.plugins.tor; package org.briarproject.bramble.plugin.tor;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.event.EventBus; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.api.plugins.Backoff; import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.api.plugins.BackoffFactory; import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.api.plugins.TorConstants; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.api.reporting.DevReporter; import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.util.AndroidUtils;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import javax.net.SocketFactory; import javax.net.SocketFactory;
@Immutable
@NotNullByDefault
public class TorPluginFactory implements DuplexPluginFactory { public class TorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG = private static final Logger LOG =
@@ -81,7 +85,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
return null; return null;
} }
// Use position-independent executable for SDK >= 16 // Use position-independent executable for SDK >= 16
if (Build.VERSION.SDK_INT >= 16) architecture += "-pie"; if (Build.VERSION.SDK_INT >= 16) architecture += "_pie";
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);

View File

@@ -1,13 +1,16 @@
package org.briarproject.plugins.tor; package org.briarproject.bramble.plugin.tor;
import org.briarproject.api.plugins.Plugin; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
@NotNullByDefault
class TorTransportConnection extends AbstractDuplexTransportConnection { class TorTransportConnection extends AbstractDuplexTransportConnection {
private final Socket socket; private final Socket socket;
@@ -19,12 +22,12 @@ class TorTransportConnection extends AbstractDuplexTransportConnection {
@Override @Override
protected InputStream getInputStream() throws IOException { protected InputStream getInputStream() throws IOException {
return socket.getInputStream(); return IoUtils.getInputStream(socket);
} }
@Override @Override
protected OutputStream getOutputStream() throws IOException { protected OutputStream getOutputStream() throws IOException {
return socket.getOutputStream(); return IoUtils.getOutputStream(socket);
} }
@Override @Override

View File

@@ -1,10 +1,10 @@
package org.briarproject.system; package org.briarproject.bramble.system;
import android.app.Application; import android.app.Application;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import org.briarproject.android.api.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@@ -27,14 +27,11 @@ class AndroidExecutorImpl implements AndroidExecutor {
@Inject @Inject
AndroidExecutorImpl(Application app) { AndroidExecutorImpl(Application app) {
uiHandler = new Handler(app.getApplicationContext().getMainLooper()); uiHandler = new Handler(app.getApplicationContext().getMainLooper());
loop = new Runnable() { loop = () -> {
@Override
public void run() {
Looper.prepare(); Looper.prepare();
backgroundHandler = new Handler(); backgroundHandler = new Handler();
startLatch.countDown(); startLatch.countDown();
Looper.loop(); Looper.loop();
}
}; };
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.system; package org.briarproject.bramble.system;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
@@ -6,7 +6,8 @@ import android.content.Context;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import org.briarproject.api.system.LocationUtils; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.LocationUtils;
import java.util.Locale; import java.util.Locale;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -15,6 +16,7 @@ import javax.inject.Inject;
import static android.content.Context.TELEPHONY_SERVICE; import static android.content.Context.TELEPHONY_SERVICE;
@NotNullByDefault
class AndroidLocationUtils implements LocationUtils { class AndroidLocationUtils implements LocationUtils {
private static final Logger LOG = private static final Logger LOG =
@@ -23,7 +25,7 @@ class AndroidLocationUtils implements LocationUtils {
private final Context appContext; private final Context appContext;
@Inject @Inject
public AndroidLocationUtils(Application app) { AndroidLocationUtils(Application app) {
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
@@ -44,6 +46,7 @@ class AndroidLocationUtils implements LocationUtils {
* some reason - both that class and {@code Context.COUNTRY_CODE} are * some reason - both that class and {@code Context.COUNTRY_CODE} are
* annotated {@code @hide}. * annotated {@code @hide}.
*/ */
@Override
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public String getCurrentCountry() { public String getCurrentCountry() {
String countryCode = getCountryFromPhoneNetwork(); String countryCode = getCountryFromPhoneNetwork();

View File

@@ -0,0 +1,93 @@
package org.briarproject.bramble.system;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ContentResolver;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Parcel;
import android.provider.Settings;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static android.content.Context.WIFI_SERVICE;
import static android.provider.Settings.Secure.ANDROID_ID;
@Immutable
@NotNullByDefault
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
private static final int SEED_LENGTH = 32;
private final Context appContext;
@Inject
AndroidSecureRandomProvider(Application app) {
appContext = app.getApplicationContext();
}
@Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out);
out.writeInt(android.os.Process.myPid());
out.writeInt(android.os.Process.myTid());
out.writeInt(android.os.Process.myUid());
if (Build.FINGERPRINT != null) out.writeUTF(Build.FINGERPRINT);
if (Build.SERIAL != null) out.writeUTF(Build.SERIAL);
ContentResolver contentResolver = appContext.getContentResolver();
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain();
WifiManager wm =
(WifiManager) appContext.getSystemService(WIFI_SERVICE);
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) {
for (BluetoothDevice device : bt.getBondedDevices())
parcel.writeParcelable(device, 0);
}
out.write(parcel.marshall());
parcel.recycle();
}
@Override
protected void writeSeed() {
super.writeSeed();
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
applyOpenSslFix();
}
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private void applyOpenSslFix() {
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
SEED_LENGTH);
try {
// Seed the OpenSSL PRNG
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class)
.invoke(null, seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_load_file", String.class, long.class)
.invoke(null, "/dev/urandom", 1024);
if (bytesRead != 1024) throw new IOException();
} catch (Exception e) {
throw new SecurityException(e);
}
}
}

View File

@@ -0,0 +1,33 @@
package org.briarproject.bramble.system;
import android.app.Application;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidSystemModule {
@Provides
@Singleton
SecureRandomProvider provideSecureRandomProvider(Application app) {
return new AndroidSecureRandomProvider(app);
}
@Provides
LocationUtils provideLocationUtils(Application app) {
return new AndroidLocationUtils(app);
}
@Provides
@Singleton
AndroidExecutor provideAndroidExecutor(Application app) {
return new AndroidExecutorImpl(app);
}
}

View File

@@ -0,0 +1,70 @@
package org.briarproject.bramble.util;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static android.content.Context.MODE_PRIVATE;
public class AndroidUtils {
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
private static final String STORED_REPORTS = "dev-reports";
@SuppressWarnings("deprecation")
public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>();
if (Build.VERSION.SDK_INT >= 21) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
} else {
abis.add(Build.CPU_ABI);
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
}
return abis;
}
public static String getBluetoothAddress(Context ctx,
BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake
String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake
address = Settings.Secure.getString(ctx.getContentResolver(),
"bluetooth_address");
if (isValidBluetoothAddress(address)) return address;
// Let the caller know we can't find the address
return "";
}
private static boolean isValidBluetoothAddress(String address) {
return !StringUtils.isNullOrEmpty(address)
&& BluetoothAdapter.checkBluetoothAddress(address)
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
public static void deleteAppData(Context ctx) {
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children != null) {
for (File child : children) {
if (!child.getName().equals("lib"))
IoUtils.deleteFileOrDir(child);
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
new File(dataDir, "cache").mkdir();
}
public static File getReportDir(Context ctx) {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
}
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Bramble</string>
</resources>

55
bramble-api/build.gradle Normal file
View File

@@ -0,0 +1,55 @@
apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'witness'
dependencies {
implementation "com.google.dagger:dagger:2.0.2"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
}
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
]
}
// needed to make test output available to bramble-core and briar-core
configurations {
testOutput.extendsFrom(testCompile)
}
task jarTest(type: Jar, dependsOn: testClasses) {
from sourceSets.test.output
classifier = 'test'
}
artifacts {
testOutput jarTest
}
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
tasks.withType(JavaCompile) {
useJava6StandardLibrary(it)
}

View File

@@ -1,11 +1,18 @@
package org.briarproject.api; package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* A wrapper around a byte array, to allow it to be stored in maps etc. * A wrapper around a byte array, to allow it to be stored in maps etc.
*/ */
@ThreadSafe
@NotNullByDefault
public class Bytes implements Comparable<Bytes> { public class Bytes implements Comparable<Bytes> {
public static final BytesComparator COMPARATOR = new BytesComparator(); public static final BytesComparator COMPARATOR = new BytesComparator();
@@ -47,6 +54,12 @@ public class Bytes implements Comparable<Bytes> {
return aBytes.length - bBytes.length; return aBytes.length - bBytes.length;
} }
@Override
public String toString() {
return getClass().getSimpleName() +
"(" + StringUtils.toHexString(getBytes()) + ")";
}
public static class BytesComparator implements Comparator<Bytes> { public static class BytesComparator implements Comparator<Bytes> {
@Override @Override

View File

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

View File

@@ -1,12 +1,10 @@
package org.briarproject.api; package org.briarproject.bramble.api;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
public abstract class StringMap extends Hashtable<String, String> { public abstract class StringMap extends Hashtable<String, String> {
private static final long serialVersionUID = 2497176435908100448L;
protected StringMap(Map<String, String> m) { protected StringMap(Map<String, String> m) {
super(m); super(m);
} }

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
@NotNullByDefault
public abstract class UniqueId extends Bytes {
/**
* The length of a unique identifier in bytes.
*/
public static final int LENGTH = 32;
protected UniqueId(byte[] id) {
super(id);
if (id.length != LENGTH) throw new IllegalArgumentException();
}
}

View File

@@ -0,0 +1,36 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class BdfMessageContext {
private final BdfDictionary dictionary;
private final Collection<MessageId> dependencies;
public BdfMessageContext(BdfDictionary dictionary,
Collection<MessageId> dependencies) {
this.dictionary = dictionary;
this.dependencies = dependencies;
}
public BdfMessageContext(BdfDictionary dictionary) {
this(dictionary, Collections.emptyList());
}
public BdfDictionary getDictionary() {
return dictionary;
}
public Collection<MessageId> getDependencies() {
return dependencies;
}
}

View File

@@ -0,0 +1,66 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.system.Clock;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable
@NotNullByDefault
public abstract class BdfMessageValidator implements MessageValidator {
protected static final Logger LOG =
Logger.getLogger(BdfMessageValidator.class.getName());
protected final ClientHelper clientHelper;
protected final MetadataEncoder metadataEncoder;
protected final Clock clock;
protected BdfMessageValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) {
this.clientHelper = clientHelper;
this.metadataEncoder = metadataEncoder;
this.clock = clock;
}
protected abstract BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws InvalidMessageException, FormatException;
@Override
public MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException {
// Reject the message if it's too far in the future
long now = clock.currentTimeMillis();
if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) {
throw new InvalidMessageException(
"Timestamp is too far in the future");
}
byte[] raw = m.getRaw();
if (raw.length <= MESSAGE_HEADER_LENGTH) {
throw new InvalidMessageException("Message is too short");
}
try {
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
BdfMessageContext result = validateMessage(m, g, body);
Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies());
} catch (FormatException e) {
throw new InvalidMessageException(e);
}
}
}

View File

@@ -1,17 +1,21 @@
package org.briarproject.api.clients; package org.briarproject.bramble.api.client;
import org.briarproject.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.api.sync.GroupId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Message; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;
@NotNullByDefault
public interface ClientHelper { public interface ClientHelper {
void addLocalMessage(Message m, BdfDictionary metadata, boolean shared) void addLocalMessage(Message m, BdfDictionary metadata, boolean shared)
@@ -20,14 +24,21 @@ public interface ClientHelper {
void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata, void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException; boolean shared) throws DbException, FormatException;
Message createMessage(GroupId g, long timestamp, BdfDictionary body)
throws FormatException;
Message createMessage(GroupId g, long timestamp, BdfList body) Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException; throws FormatException;
Message createMessageForStoringMetadata(GroupId g);
@Nullable
Message getMessage(MessageId m) throws DbException;
@Nullable
Message getMessage(Transaction txn, MessageId m) throws DbException;
@Nullable
BdfList getMessageAsList(MessageId m) throws DbException, FormatException; BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
@Nullable
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException, BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException; FormatException;
@@ -37,7 +48,8 @@ public interface ClientHelper {
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g) BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException; throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m) throws DbException, BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException,
FormatException; FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m) BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
@@ -68,12 +80,6 @@ public interface ClientHelper {
void mergeMessageMetadata(Transaction txn, MessageId m, void mergeMessageMetadata(Transaction txn, MessageId m,
BdfDictionary metadata) throws DbException, FormatException; BdfDictionary metadata) throws DbException, FormatException;
/**
* Marks the given message as shared or unshared with other contacts.
*/
void setMessageShared(Transaction txn, MessageId m, boolean shared)
throws DbException;
byte[] toByteArray(BdfDictionary dictionary) throws FormatException; byte[] toByteArray(BdfDictionary dictionary) throws FormatException;
byte[] toByteArray(BdfList list) throws FormatException; byte[] toByteArray(BdfList list) throws FormatException;
@@ -85,6 +91,12 @@ public interface ClientHelper {
BdfList toList(byte[] b) throws FormatException; BdfList toList(byte[] b) throws FormatException;
byte[] sign(BdfList toSign, byte[] privateKey) BdfList toList(Message m) throws FormatException;
byte[] sign(String label, BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
void verifySignature(String label, byte[] sig, byte[] publicKey,
BdfList signed) throws FormatException, GeneralSecurityException;
} }

View File

@@ -0,0 +1,29 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group;
@NotNullByDefault
public interface ContactGroupFactory {
/**
* Creates a group that is not shared with any contacts.
*/
Group createLocalGroup(ClientId clientId);
/**
* Creates a group for the given client to share with the given contact.
*/
Group createContactGroup(ClientId clientId, 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);
}

View File

@@ -1,8 +1,13 @@
package org.briarproject.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Contact { public class Contact {
private final ContactId id; private final ContactId id;

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface ContactExchangeListener {
void contactExchangeSucceeded(Author remoteAuthor);
/**
* The exchange failed because the contact already exists.
*/
void duplicateContact(Author remoteAuthor);
/**
* A general failure.
*/
void contactExchangeFailed();
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
/**
* A task for conducting a contact information exchange with a remote peer.
*/
@NotNullByDefault
public interface ContactExchangeTask {
/**
* Exchanges contact information with a remote peer.
*/
void startExchange(ContactExchangeListener listener,
LocalAuthor localAuthor, SecretKey masterSecret,
DuplexTransportConnection conn, TransportId transportId,
boolean alice);
}

View File

@@ -1,9 +1,15 @@
package org.briarproject.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/** /**
* Type-safe wrapper for an integer that uniquely identifies a contact within * Type-safe wrapper for an integer that uniquely identifies a contact within
* the scope of a single node. * the scope of a single node.
*/ */
@Immutable
@NotNullByDefault
public class ContactId { public class ContactId {
private final int id; private final int id;

View File

@@ -0,0 +1,104 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
@NotNullByDefault
public interface ContactManager {
/**
* Registers a hook to be called whenever a contact is added.
*/
void registerAddContactHook(AddContactHook 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.
*/
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,
* 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;
/**
* Returns the contact with the given ID.
*/
Contact getContact(ContactId c) throws DbException;
/**
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
*
* @throws org.briarproject.bramble.api.db.NoSuchContactException
*/
Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
/**
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
*
* @throws org.briarproject.bramble.api.db.NoSuchContactException
*/
Contact getContact(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException;
/**
* Returns all active contacts.
*/
Collection<Contact> getActiveContacts() throws DbException;
/**
* Removes a contact and all associated state.
*/
void removeContact(ContactId c) throws DbException;
/**
* Removes a contact and all associated state.
*/
void removeContact(Transaction txn, ContactId c) throws DbException;
/**
* Marks a contact as active or inactive.
*/
void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException;
/**
* Return true if a contact with this name and public key already exists
*/
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException;
/**
* Return true if a contact with this name and public key already exists
*/
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
interface AddContactHook {
void addingContact(Transaction txn, Contact c) throws DbException;
}
interface RemoveContactHook {
void removingContact(Transaction txn, Contact c) throws DbException;
}
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a contact is added.
*/
@Immutable
@NotNullByDefault
public class ContactAddedEvent extends Event {
private final ContactId contactId;
private final boolean active;
public ContactAddedEvent(ContactId contactId, boolean active) {
this.contactId = contactId;
this.active = active;
}
public ContactId getContactId() {
return contactId;
}
public boolean isActive() {
return active;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a contact is removed.
*/
@Immutable
@NotNullByDefault
public class ContactRemovedEvent extends Event {
private final ContactId contactId;
public ContactRemovedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a contact is marked active or inactive.
*/
@Immutable
@NotNullByDefault
public class ContactStatusChangedEvent extends Event {
private final ContactId contactId;
private final boolean active;
public ContactStatusChangedEvent(ContactId contactId, boolean active) {
this.contactId = contactId;
this.active = active;
}
public ContactId getContactId() {
return contactId;
}
public boolean isActive() {
return active;
}
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a contact is verified.
*/
@Immutable
@NotNullByDefault
public class ContactVerifiedEvent extends Event {
private final ContactId contactId;
public ContactVerifiedEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -1,7 +1,7 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.SecureRandom; import java.security.SecureRandom;
@@ -10,14 +10,8 @@ public interface CryptoComponent {
SecretKey generateSecretKey(); SecretKey generateSecretKey();
MessageDigest getMessageDigest();
PseudoRandom getPseudoRandom(int seed1, int seed2);
SecureRandom getSecureRandom(); SecureRandom getSecureRandom();
Signature getSignature();
KeyPair generateAgreementKeyPair(); KeyPair generateAgreementKeyPair();
KeyParser getAgreementKeyParser(); KeyParser getAgreementKeyParser();
@@ -28,15 +22,6 @@ public interface CryptoComponent {
KeyParser getMessageKeyParser(); 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. * Derives a stream header key from the given master secret.
* @param alice whether the key is for use by Alice or Bob. * @param alice whether the key is for use by Alice or Bob.
@@ -141,13 +126,43 @@ public interface CryptoComponent {
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod); TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
/** Encodes the pseudo-random tag that is used to recognise a stream. */ /** Encodes the pseudo-random tag that is used to recognise a stream. */
void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber); 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
*/
byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signedData
* and the given publicKey.
*
* @param label A label that was specific to this signature
* to ensure that the signature cannot be repurposed
* @return true if the signature was valid, false otherwise.
*/
boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException;
/** /**
* Returns the hash of the given inputs. The inputs are unambiguously * Returns the hash of the given inputs. The inputs are unambiguously
* combined by prefixing each input with its length. * 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.
*/ */
byte[] hash(byte[]... inputs); 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 * Returns a message authentication code with the given key over the

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.crypto;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for long-running crypto tasks. Also
* used for annotating methods that should run on the crypto executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks must not run indefinitely. Tasks
* submitted during shutdown are discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface CryptoExecutor {
}

View File

@@ -1,6 +1,14 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
/** A key pair consisting of a {@link PublicKey} and a {@link PrivateKey). */ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey).
*/
@Immutable
@NotNullByDefault
public class KeyPair { public class KeyPair {
private final PublicKey publicKey; private final PublicKey publicKey;

View File

@@ -1,7 +1,10 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
@NotNullByDefault
public interface KeyParser { public interface KeyParser {
PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException; PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException;

View File

@@ -1,11 +1,14 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface PasswordStrengthEstimator { public interface PasswordStrengthEstimator {
float NONE = 0; float NONE = 0;
float WEAK = 0.4f; float WEAK = 0.25f;
float QUITE_WEAK = 0.6f; float QUITE_WEAK = 0.5f;
float QUITE_STRONG = 0.8f; float QUITE_STRONG = 0.75f;
float STRONG = 1; float STRONG = 1;
/** /**

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* The private half of a public/private {@link KeyPair}.
*/
@NotNullByDefault
public interface PrivateKey {
/**
* Returns the encoded representation of this key.
*/
byte[] getEncoded();
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* The public half of a public/private {@link KeyPair}.
*/
@NotNullByDefault
public interface PublicKey {
/**
* Returns the encoded representation of this key.
*/
byte[] getEncoded();
}

View File

@@ -1,9 +1,14 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
/** A secret key used for encryption and/or authentication. */ /**
* A secret key used for encryption and/or authentication.
*/
public class SecretKey { public class SecretKey {
public static final int LENGTH = 32; // Bytes /**
* The length of a secret key in bytes.
*/
public static final int LENGTH = 32;
private final byte[] key; private final byte[] key;

View File

@@ -1,13 +1,17 @@
package org.briarproject.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
@NotNullByDefault
public interface StreamDecrypter { public interface StreamDecrypter {
/** /**
* Reads a frame, decrypts its payload into the given buffer and returns * Reads a frame, decrypts its payload into the given buffer and returns
* the payload length, or -1 if no more frames can be read from the stream. * the payload length, or -1 if no more frames can be read from the stream.
* @throws java.io.IOException if an error occurs while reading the frame, *
* @throws IOException if an error occurs while reading the frame,
* or if authenticated decryption fails. * or if authenticated decryption fails.
*/ */
int readFrame(byte[] payload) throws IOException; int readFrame(byte[] payload) throws IOException;

View File

@@ -0,0 +1,22 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamContext;
import java.io.InputStream;
@NotNullByDefault
public interface StreamDecrypterFactory {
/**
* Creates a {@link StreamDecrypter} for decrypting a transport stream.
*/
StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx);
/**
* Creates a {@link StreamDecrypter} for decrypting a contact exchange
* stream.
*/
StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
SecretKey headerKey);
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException;
@NotNullByDefault
public interface StreamEncrypter {
/**
* Encrypts the given frame and writes it to the stream.
*/
void writeFrame(byte[] payload, int payloadLength, int paddingLength,
boolean finalFrame) throws IOException;
/**
* Flushes the stream.
*/
void flush() throws IOException;
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamContext;
import java.io.OutputStream;
@NotNullByDefault
public interface StreamEncrypterFactory {
/**
* Creates a {@link StreamEncrypter} for encrypting a transport stream.
*/
StreamEncrypter createStreamEncrypter(OutputStream out, StreamContext ctx);
/**
* Creates a {@link StreamEncrypter} for encrypting a contact exchange
* stream.
*/
StreamEncrypter createContactExchangeStreamDecrypter(OutputStream out,
SecretKey headerKey);
}

View File

@@ -1,12 +1,17 @@
package org.briarproject.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.api.FormatException; import org.briarproject.bramble.api.FormatException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap; import java.util.Map.Entry;
import java.util.TreeMap;
public class BdfDictionary extends ConcurrentSkipListMap<String, Object> { import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
public class BdfDictionary extends TreeMap<String, Object> {
public static final Object NULL_VALUE = new Object(); public static final Object NULL_VALUE = new Object();
@@ -39,6 +44,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Boolean getOptionalBoolean(String key) throws FormatException { public Boolean getOptionalBoolean(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -61,6 +67,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Long getOptionalLong(String key) throws FormatException { public Long getOptionalLong(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -87,6 +94,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Double getOptionalDouble(String key) throws FormatException { public Double getOptionalDouble(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -108,6 +116,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public String getOptionalString(String key) throws FormatException { public String getOptionalString(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -128,6 +137,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public byte[] getOptionalRaw(String key) throws FormatException { public byte[] getOptionalRaw(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -149,6 +159,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfList getOptionalList(String key) throws FormatException { public BdfList getOptionalList(String key) throws FormatException {
Object o = get(key); Object o = get(key);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
@@ -168,6 +179,7 @@ public class BdfDictionary extends ConcurrentSkipListMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfDictionary getOptionalDictionary(String key) public BdfDictionary getOptionalDictionary(String key)
throws FormatException { throws FormatException {
Object o = get(key); Object o = get(key);

View File

@@ -1,7 +1,13 @@
package org.briarproject.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class BdfEntry implements Entry<String, Object>, Comparable<BdfEntry> { public class BdfEntry implements Entry<String, Object>, Comparable<BdfEntry> {
private final String key; private final String key;

View File

@@ -1,15 +1,19 @@
package org.briarproject.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.api.FormatException; import org.briarproject.bramble.api.FormatException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Vector;
import static org.briarproject.api.data.BdfDictionary.NULL_VALUE; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
public class BdfList extends Vector<Object> { import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
@NotThreadSafe
public class BdfList extends ArrayList<Object> {
/** /**
* Factory method for constructing lists inline. * Factory method for constructing lists inline.
@@ -29,13 +33,20 @@ public class BdfList extends Vector<Object> {
super(items); super(items);
} }
private boolean isInRange(int index) {
return index >= 0 && index < size();
}
public Boolean getBoolean(int index) throws FormatException { public Boolean getBoolean(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof Boolean) return (Boolean) o; if (o instanceof Boolean) return (Boolean) o;
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Boolean getOptionalBoolean(int index) throws FormatException { public Boolean getOptionalBoolean(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof Boolean) return (Boolean) o; if (o instanceof Boolean) return (Boolean) o;
@@ -43,12 +54,14 @@ public class BdfList extends Vector<Object> {
} }
public Boolean getBoolean(int index, Boolean defaultValue) { public Boolean getBoolean(int index, Boolean defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof Boolean) return (Boolean) o; if (o instanceof Boolean) return (Boolean) o;
return defaultValue; return defaultValue;
} }
public Long getLong(int index) throws FormatException { public Long getLong(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof Long) return (Long) o; if (o instanceof Long) return (Long) o;
if (o instanceof Integer) return ((Integer) o).longValue(); if (o instanceof Integer) return ((Integer) o).longValue();
@@ -57,7 +70,9 @@ public class BdfList extends Vector<Object> {
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Long getOptionalLong(int index) throws FormatException { public Long getOptionalLong(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof Long) return (Long) o; if (o instanceof Long) return (Long) o;
@@ -68,6 +83,7 @@ public class BdfList extends Vector<Object> {
} }
public Long getLong(int index, Long defaultValue) { public Long getLong(int index, Long defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof Long) return (Long) o; if (o instanceof Long) return (Long) o;
if (o instanceof Integer) return ((Integer) o).longValue(); if (o instanceof Integer) return ((Integer) o).longValue();
@@ -77,13 +93,16 @@ public class BdfList extends Vector<Object> {
} }
public Double getDouble(int index) throws FormatException { public Double getDouble(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof Double) return (Double) o; if (o instanceof Double) return (Double) o;
if (o instanceof Float) return ((Float) o).doubleValue(); if (o instanceof Float) return ((Float) o).doubleValue();
throw new FormatException(); throw new FormatException();
} }
@Nullable
public Double getOptionalDouble(int index) throws FormatException { public Double getOptionalDouble(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof Double) return (Double) o; if (o instanceof Double) return (Double) o;
@@ -92,6 +111,7 @@ public class BdfList extends Vector<Object> {
} }
public Double getDouble(int index, Double defaultValue) { public Double getDouble(int index, Double defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof Double) return (Double) o; if (o instanceof Double) return (Double) o;
if (o instanceof Float) return ((Float) o).doubleValue(); if (o instanceof Float) return ((Float) o).doubleValue();
@@ -99,12 +119,15 @@ public class BdfList extends Vector<Object> {
} }
public String getString(int index) throws FormatException { public String getString(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof String) return (String) o; if (o instanceof String) return (String) o;
throw new FormatException(); throw new FormatException();
} }
@Nullable
public String getOptionalString(int index) throws FormatException { public String getOptionalString(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof String) return (String) o; if (o instanceof String) return (String) o;
@@ -112,19 +135,23 @@ public class BdfList extends Vector<Object> {
} }
public String getString(int index, String defaultValue) { public String getString(int index, String defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof String) return (String) o; if (o instanceof String) return (String) o;
return defaultValue; return defaultValue;
} }
public byte[] getRaw(int index) throws FormatException { public byte[] getRaw(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof byte[]) return (byte[]) o; if (o instanceof byte[]) return (byte[]) o;
if (o instanceof Bytes) return ((Bytes) o).getBytes(); if (o instanceof Bytes) return ((Bytes) o).getBytes();
throw new FormatException(); throw new FormatException();
} }
@Nullable
public byte[] getOptionalRaw(int index) throws FormatException { public byte[] getOptionalRaw(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof byte[]) return (byte[]) o; if (o instanceof byte[]) return (byte[]) o;
@@ -133,6 +160,7 @@ public class BdfList extends Vector<Object> {
} }
public byte[] getRaw(int index, byte[] defaultValue) { public byte[] getRaw(int index, byte[] defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof byte[]) return (byte[]) o; if (o instanceof byte[]) return (byte[]) o;
if (o instanceof Bytes) return ((Bytes) o).getBytes(); if (o instanceof Bytes) return ((Bytes) o).getBytes();
@@ -140,12 +168,15 @@ public class BdfList extends Vector<Object> {
} }
public BdfList getList(int index) throws FormatException { public BdfList getList(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof BdfList) return (BdfList) o; if (o instanceof BdfList) return (BdfList) o;
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfList getOptionalList(int index) throws FormatException { public BdfList getOptionalList(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof BdfList) return (BdfList) o; if (o instanceof BdfList) return (BdfList) o;
@@ -153,19 +184,23 @@ public class BdfList extends Vector<Object> {
} }
public BdfList getList(int index, BdfList defaultValue) { public BdfList getList(int index, BdfList defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof BdfList) return (BdfList) o; if (o instanceof BdfList) return (BdfList) o;
return defaultValue; return defaultValue;
} }
public BdfDictionary getDictionary(int index) throws FormatException { public BdfDictionary getDictionary(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o instanceof BdfDictionary) return (BdfDictionary) o; if (o instanceof BdfDictionary) return (BdfDictionary) o;
throw new FormatException(); throw new FormatException();
} }
@Nullable
public BdfDictionary getOptionalDictionary(int index) public BdfDictionary getOptionalDictionary(int index)
throws FormatException { throws FormatException {
if (!isInRange(index)) throw new FormatException();
Object o = get(index); Object o = get(index);
if (o == null || o == NULL_VALUE) return null; if (o == null || o == NULL_VALUE) return null;
if (o instanceof BdfDictionary) return (BdfDictionary) o; if (o instanceof BdfDictionary) return (BdfDictionary) o;
@@ -173,6 +208,7 @@ public class BdfList extends Vector<Object> {
} }
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) { public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) {
if (!isInRange(index)) return defaultValue;
Object o = get(index); Object o = get(index);
if (o instanceof BdfDictionary) return (BdfDictionary) o; if (o instanceof BdfDictionary) return (BdfDictionary) o;
return defaultValue; return defaultValue;

View File

@@ -1,47 +1,75 @@
package org.briarproject.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
@NotNullByDefault
public interface BdfReader { public interface BdfReader {
int DEFAULT_NESTED_LIMIT = 5;
boolean eof() throws IOException; boolean eof() throws IOException;
void close() throws IOException; void close() throws IOException;
boolean hasNull() throws IOException; boolean hasNull() throws IOException;
void readNull() throws IOException; void readNull() throws IOException;
void skipNull() throws IOException; void skipNull() throws IOException;
boolean hasBoolean() throws IOException; boolean hasBoolean() throws IOException;
boolean readBoolean() throws IOException; boolean readBoolean() throws IOException;
void skipBoolean() throws IOException; void skipBoolean() throws IOException;
boolean hasLong() throws IOException; boolean hasLong() throws IOException;
long readLong() throws IOException; long readLong() throws IOException;
void skipLong() throws IOException; void skipLong() throws IOException;
boolean hasDouble() throws IOException; boolean hasDouble() throws IOException;
double readDouble() throws IOException; double readDouble() throws IOException;
void skipDouble() throws IOException; void skipDouble() throws IOException;
boolean hasString() throws IOException; boolean hasString() throws IOException;
String readString(int maxLength) throws IOException; String readString(int maxLength) throws IOException;
void skipString() throws IOException; void skipString() throws IOException;
boolean hasRaw() throws IOException; boolean hasRaw() throws IOException;
byte[] readRaw(int maxLength) throws IOException; byte[] readRaw(int maxLength) throws IOException;
void skipRaw() throws IOException; void skipRaw() throws IOException;
boolean hasList() throws IOException; boolean hasList() throws IOException;
BdfList readList() throws IOException; BdfList readList() throws IOException;
void readListStart() throws IOException; void readListStart() throws IOException;
boolean hasListEnd() throws IOException; boolean hasListEnd() throws IOException;
void readListEnd() throws IOException; void readListEnd() throws IOException;
void skipList() throws IOException; void skipList() throws IOException;
boolean hasDictionary() throws IOException; boolean hasDictionary() throws IOException;
BdfDictionary readDictionary() throws IOException; BdfDictionary readDictionary() throws IOException;
void readDictionaryStart() throws IOException; void readDictionaryStart() throws IOException;
boolean hasDictionaryEnd() throws IOException; boolean hasDictionaryEnd() throws IOException;
void readDictionaryEnd() throws IOException; void readDictionaryEnd() throws IOException;
void skipDictionary() throws IOException; void skipDictionary() throws IOException;
} }

View File

@@ -0,0 +1,13 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.InputStream;
@NotNullByDefault
public interface BdfReaderFactory {
BdfReader createReader(InputStream in);
BdfReader createReader(InputStream in, int nestedLimit);
}

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.data; package org.briarproject.bramble.api.data;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -7,20 +7,30 @@ import java.util.Map;
public interface BdfWriter { public interface BdfWriter {
void flush() throws IOException; void flush() throws IOException;
void close() throws IOException; void close() throws IOException;
void writeNull() throws IOException; void writeNull() throws IOException;
void writeBoolean(boolean b) throws IOException; void writeBoolean(boolean b) throws IOException;
void writeLong(long l) throws IOException; void writeLong(long l) throws IOException;
void writeDouble(double d) throws IOException; void writeDouble(double d) throws IOException;
void writeString(String s) throws IOException; void writeString(String s) throws IOException;
void writeRaw(byte[] b) throws IOException; void writeRaw(byte[] b) throws IOException;
void writeList(Collection<?> c) throws IOException; void writeList(Collection<?> c) throws IOException;
void writeListStart() throws IOException; void writeListStart() throws IOException;
void writeListEnd() throws IOException; void writeListEnd() throws IOException;
void writeDictionary(Map<?, ?> m) throws IOException; void writeDictionary(Map<?, ?> m) throws IOException;
void writeDictionaryStart() throws IOException; void writeDictionaryStart() throws IOException;
void writeDictionaryEnd() throws IOException; void writeDictionaryEnd() throws IOException;
} }

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.OutputStream;
@NotNullByDefault
public interface BdfWriterFactory {
BdfWriter createWriter(OutputStream out);
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface MetadataEncoder {
Metadata encode(BdfDictionary d) throws FormatException;
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface MetadataParser {
BdfDictionary parse(Metadata m) throws FormatException;
}

View File

@@ -0,0 +1,11 @@
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

@@ -1,10 +1,8 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a duplicate contact is added to the database. This exception may * Thrown when a duplicate contact is added to the database. This exception may
* occur due to concurrent updates and does not indicate a database error. * occur due to concurrent updates and does not indicate a database error.
*/ */
public class ContactExistsException extends DbException { public class ContactExistsException extends DbException {
private static final long serialVersionUID = -6658762011691502411L;
} }

View File

@@ -1,34 +1,38 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.api.DeviceId; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.api.contact.Contact; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.api.contact.ContactId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.api.identity.Author; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.api.identity.AuthorId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.api.sync.ClientId; import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.bramble.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.api.sync.Message; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.api.sync.Offer; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.api.sync.Request; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.bramble.api.sync.Request;
import org.jetbrains.annotations.Nullable; import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import static org.briarproject.api.sync.ValidationManager.State; import javax.annotation.Nullable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/** /**
* Encapsulates the database implementation and exposes high-level operations * Encapsulates the database implementation and exposes high-level operations
* to other components. * to other components.
*/ */
@NotNullByDefault
public interface DatabaseComponent { public interface DatabaseComponent {
/** /**
@@ -52,11 +56,17 @@ public interface DatabaseComponent {
Transaction startTransaction(boolean readOnly) throws DbException; Transaction startTransaction(boolean readOnly) throws DbException;
/** /**
* Ends a transaction. If the transaction is marked as complete, the * Commits a transaction to the database.
* transaction is committed and any events attached to the transaction are
* broadcast; otherwise the transaction is aborted.
*/ */
void endTransaction(Transaction txn) throws DbException; void commitTransaction(Transaction txn) throws DbException;
/**
* Ends a transaction. If the transaction has not been committed,
* it will be aborted. If the transaction has been committed,
* any events attached to the transaction are broadcast.
* The database lock will be released in either case.
*/
void endTransaction(Transaction txn);
/** /**
* Stores a contact associated with the given local and remote pseudonyms, * Stores a contact associated with the given local and remote pseudonyms,
@@ -112,8 +122,9 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Deletes the message with the given ID. The message ID and any other * Deletes the message with the given ID. Unlike
* associated data are not deleted. * {@link #removeMessage(Transaction, MessageId)}, the message ID and any
* other associated data are not deleted.
*/ */
void deleteMessage(Transaction txn, MessageId m) throws DbException; void deleteMessage(Transaction txn, MessageId m) throws DbException;
@@ -198,13 +209,6 @@ public interface DatabaseComponent {
Collection<ContactId> getContacts(Transaction txn, AuthorId a) Collection<ContactId> getContacts(Transaction txn, AuthorId a)
throws DbException; throws DbException;
/**
* Returns the unique ID for this device.
* <p/>
* Read-only.
*/
DeviceId getDeviceId(Transaction txn) throws DbException;
/** /**
* Returns the group with the given ID. * Returns the group with the given ID.
* <p/> * <p/>
@@ -226,6 +230,15 @@ public interface DatabaseComponent {
*/ */
Collection<Group> getGroups(Transaction txn, ClientId c) throws DbException; Collection<Group> getGroups(Transaction txn, ClientId c) throws DbException;
/**
* Returns the given group's visibility to the given contact, or
* {@link Visibility INVISIBLE} if the group is not in the database.
* <p/>
* Read-only.
*/
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
throws DbException;
/** /**
* Returns the local pseudonym with the given ID. * Returns the local pseudonym with the given ID.
* <p/> * <p/>
@@ -258,6 +271,15 @@ public interface DatabaseComponent {
Collection<MessageId> getPendingMessages(Transaction txn, ClientId c) Collection<MessageId> getPendingMessages(Transaction txn, ClientId c)
throws DbException; throws DbException;
/**
* Returns the IDs of any messages from the given client
* that have a shared dependent, but are still not shared themselves.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToShare(Transaction txn,
ClientId c) throws DbException;
/** /**
* Returns the message with the given ID, in serialised form, or null if * Returns the message with the given ID, in serialised form, or null if
* the message has been deleted. * the message has been deleted.
@@ -313,10 +335,10 @@ public interface DatabaseComponent {
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* Missing dependencies have the state {@link * Missing dependencies have the state
* org.briarproject.api.sync.ValidationManager.State UNKNOWN}. * {@link ValidationManager.State UNKNOWN}.
* Dependencies in other groups have the state {@link * Dependencies in other groups have the state
* org.briarproject.api.sync.ValidationManager.State INVALID}. * {@link ValidationManager.State INVALID}.
* Note that these states are not set on the dependencies themselves; the * 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. * returned states should only be taken in the context of the given message.
* <p/> * <p/>
@@ -373,14 +395,6 @@ public interface DatabaseComponent {
void incrementStreamCounter(Transaction txn, ContactId c, TransportId t, void incrementStreamCounter(Transaction txn, ContactId c, TransportId t,
long rotationPeriod) throws DbException; long rotationPeriod) throws DbException;
/**
* Returns true if the given group is visible to the given contact.
* <p/>
* Read-only.
*/
boolean isVisibleToContact(Transaction txn, ContactId c, GroupId g)
throws DbException;
/** /**
* Merges the given metadata with the existing metadata for the given * Merges the given metadata with the existing metadata for the given
* group. * group.
@@ -439,6 +453,11 @@ public interface DatabaseComponent {
*/ */
void removeLocalAuthor(Transaction txn, AuthorId a) throws DbException; 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. * Removes a transport (and all associated state) from the database.
*/ */
@@ -456,10 +475,15 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Marks the given message as shared or unshared. * Sets the given group's visibility to the given contact.
*/ */
void setMessageShared(Transaction txn, MessageId m, boolean shared) void setGroupVisibility(Transaction txn, ContactId c, GroupId g,
throws DbException; Visibility v) throws DbException;
/**
* Marks the given message as shared.
*/
void setMessageShared(Transaction txn, MessageId m) throws DbException;
/** /**
* Sets the validation and delivery state of the given message. * Sets the validation and delivery state of the given message.
@@ -480,12 +504,6 @@ public interface DatabaseComponent {
void setReorderingWindow(Transaction txn, ContactId c, TransportId t, void setReorderingWindow(Transaction txn, ContactId c, TransportId t,
long rotationPeriod, long base, byte[] bitmap) throws DbException; long rotationPeriod, long base, byte[] bitmap) throws DbException;
/**
* Makes a group visible or invisible to a contact.
*/
void setVisibleToContact(Transaction txn, ContactId c, GroupId g,
boolean visible) throws DbException;
/** /**
* Stores the given transport keys, deleting any keys they have replaced. * Stores the given transport keys, deleting any keys they have replaced.
*/ */

View File

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

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api.db;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for database tasks. Also used for
* annotating methods that should run on the database executor.
* <p>
* The contract of this executor is that tasks are run in the order they're
* submitted, tasks are not run concurrently, and submitting a task will never
* block. Tasks must not run indefinitely. Tasks submitted during shutdown are
* discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface DatabaseExecutor {
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a database operation is attempted and the database is closed.
*/
public class DbClosedException extends DbException {
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.db;
public class DbException extends Exception {
public DbException() {
}
public DbException(Throwable t) {
super(t);
}
}

View File

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

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a database operation is attempted for a contact that is not in * Thrown when a database operation is attempted for a contact that is not in
@@ -6,6 +6,4 @@ package org.briarproject.api.db;
* not indicate a database error. * not indicate a database error.
*/ */
public class NoSuchContactException extends DbException { public class NoSuchContactException extends DbException {
private static final long serialVersionUID = -7048538231308207386L;
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a database operation is attempted for a group that is not in the * Thrown when a database operation is attempted for a group that is not in the
@@ -6,6 +6,4 @@ package org.briarproject.api.db;
* indicate a database error. * indicate a database error.
*/ */
public class NoSuchGroupException extends DbException { public class NoSuchGroupException extends DbException {
private static final long serialVersionUID = -5494178507342571697L;
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a database operation is attempted for a pseudonym that is not in * Thrown when a database operation is attempted for a pseudonym that is not in
@@ -6,6 +6,4 @@ package org.briarproject.api.db;
* not indicate a database error. * not indicate a database error.
*/ */
public class NoSuchLocalAuthorException extends DbException { public class NoSuchLocalAuthorException extends DbException {
private static final long serialVersionUID = 494398665376703860L;
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a database operation is attempted for a message that is not in * Thrown when a database operation is attempted for a message that is not in
@@ -6,6 +6,4 @@ package org.briarproject.api.db;
* not indicate a database error. * not indicate a database error.
*/ */
public class NoSuchMessageException extends DbException { public class NoSuchMessageException extends DbException {
private static final long serialVersionUID = 9191508339698803848L;
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
/** /**
* Thrown when a database operation is attempted for a transport that is not in * Thrown when a database operation is attempted for a transport that is not in
@@ -6,6 +6,4 @@ package org.briarproject.api.db;
* not indicate a database error. * not indicate a database error.
*/ */
public class NoSuchTransportException extends DbException { public class NoSuchTransportException extends DbException {
private static final long serialVersionUID = -6274982612759573100L;
} }

View File

@@ -1,21 +1,24 @@
package org.briarproject.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.api.event.Event; import org.briarproject.bramble.api.event.Event;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/** /**
* A wrapper around a database transaction. Transactions are not thread-safe. * A wrapper around a database transaction. Transactions are not thread-safe.
*/ */
@NotThreadSafe
public class Transaction { public class Transaction {
private final Object txn; private final Object txn;
private final boolean readOnly; private final boolean readOnly;
private List<Event> events = null; private List<Event> events = null;
private boolean complete = false; private boolean committed = false;
public Transaction(Object txn, boolean readOnly) { public Transaction(Object txn, boolean readOnly) {
this.txn = txn; this.txn = txn;
@@ -42,7 +45,7 @@ public class Transaction {
* committed. * committed.
*/ */
public void attach(Event e) { public void attach(Event e) {
if (events == null) events = new ArrayList<Event>(); if (events == null) events = new ArrayList<>();
events.add(e); events.add(e);
} }
@@ -55,18 +58,18 @@ public class Transaction {
} }
/** /**
* Returns true if the transaction is ready to be committed. * Returns true if the transaction has been committed.
*/ */
public boolean isComplete() { public boolean isCommitted() {
return complete; return committed;
} }
/** /**
* Marks the transaction as ready to be committed. This method must not be * Marks the transaction as committed. This method should only be called
* called more than once. * by the DatabaseComponent. It must not be called more than once.
*/ */
public void setComplete() { public void setCommitted() {
if (complete) throw new IllegalStateException(); if (committed) throw new IllegalStateException();
complete = true; committed = true;
} }
} }

View File

@@ -0,0 +1,7 @@
package org.briarproject.bramble.api.event;
/**
* An abstract superclass for events.
*/
public abstract class Event {
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.bramble.api.event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface EventBus {
/**
* Adds a listener to be notified when events occur.
*/
void addListener(EventListener l);
/**
* Removes a listener.
*/
void removeListener(EventListener l);
/**
* Notifies all listeners of an event.
*/
void broadcast(Event e);
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.bramble.api.event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* An interface for receiving notifications when events occur.
*/
@NotNullByDefault
public interface EventListener {
/**
* Called when an event is broadcast. Implementations of this method must
* not block.
*/
void eventOccurred(Event e);
}

View File

@@ -1,11 +1,21 @@
package org.briarproject.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
/** A pseudonym for a user. */ import javax.annotation.concurrent.Immutable;
/**
* A pseudonym for a user.
*/
@Immutable
@NotNullByDefault
public class Author { public class Author {
public enum Status { ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES } public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
}
private final AuthorId id; private final AuthorId id;
private final String name; private final String name;
@@ -25,17 +35,23 @@ public class Author {
this.publicKey = publicKey; this.publicKey = publicKey;
} }
/** Returns the author's unique identifier. */ /**
* Returns the author's unique identifier.
*/
public AuthorId getId() { public AuthorId getId() {
return id; return id;
} }
/** Returns the author's name. */ /**
* Returns the author's name.
*/
public String getName() { public String getName() {
return name; return name;
} }
/** Returns the public key used to verify the pseudonym's signatures. */ /**
* Returns the public key used to verify the pseudonym's signatures.
*/
public byte[] getPublicKey() { public byte[] getPublicKey() {
return publicKey; return publicKey;
} }

View File

@@ -1,8 +1,10 @@
package org.briarproject.api.identity; package org.briarproject.bramble.api.identity;
public interface AuthorConstants { public interface AuthorConstants {
/** The maximum length of an author's name in UTF-8 bytes. */ /**
* The maximum length of an author's name in UTF-8 bytes.
*/
int MAX_AUTHOR_NAME_LENGTH = 50; int MAX_AUTHOR_NAME_LENGTH = 50;
/** /**

View File

@@ -1,5 +1,8 @@
package org.briarproject.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AuthorFactory { public interface AuthorFactory {
Author createAuthor(String name, byte[] publicKey); Author createAuthor(String name, byte[] publicKey);

View File

@@ -1,20 +1,22 @@
package org.briarproject.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.nio.charset.Charset; import javax.annotation.concurrent.ThreadSafe;
/** /**
* Type-safe wrapper for a byte array that uniquely identifies an * Type-safe wrapper for a byte array that uniquely identifies an
* {@link org.briarproject.api.identity.Author Author}. * {@link Author}.
*/ */
@ThreadSafe
@NotNullByDefault
public class AuthorId extends UniqueId { public class AuthorId extends UniqueId {
/** /**
* Label for hashing authors to calculate their identities. * Label for hashing authors to calculate their identities.
*/ */
public static final byte[] LABEL = public static final String LABEL = "org.briarproject.bramble.AUTHOR_ID";
"AUTHOR_ID".getBytes(Charset.forName("US-ASCII"));
public AuthorId(byte[] id) { public AuthorId(byte[] id) {
super(id); super(id);

View File

@@ -0,0 +1,38 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface IdentityManager {
/**
* Stores the local pseudonym.
*/
void registerLocalAuthor(LocalAuthor a) throws DbException;
/**
* Returns the cached main local identity, non-blocking, or loads it from
* the db, blocking
*/
LocalAuthor getLocalAuthor() throws DbException;
/**
* Returns the cached main local identity, non-blocking, or loads it from
* the db, blocking, within the given Transaction.
*/
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/**
* Returns the trust-level status of the author
*/
Status getAuthorStatus(AuthorId a) throws DbException;
/**
* Returns the trust-level status of the author
*/
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
}

View File

@@ -1,6 +1,14 @@
package org.briarproject.api.identity; package org.briarproject.bramble.api.identity;
/** A pseudonym for the local user. */ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* A pseudonym for the local user.
*/
@Immutable
@NotNullByDefault
public class LocalAuthor extends Author { public class LocalAuthor extends Author {
private final byte[] privateKey; private final byte[] privateKey;
@@ -13,7 +21,9 @@ public class LocalAuthor extends Author {
this.created = created; this.created = created;
} }
/** Returns the private key used to generate the pseudonym's signatures. */ /**
* Returns the private key used to generate the pseudonym's signatures.
*/
public byte[] getPrivateKey() { public byte[] getPrivateKey() {
return privateKey; return privateKey;
} }

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.identity.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a local pseudonym is added.
*/
@Immutable
@NotNullByDefault
public class LocalAuthorAddedEvent extends Event {
private final AuthorId authorId;
public LocalAuthorAddedEvent(AuthorId authorId) {
this.authorId = authorId;
}
public AuthorId getAuthorId() {
return authorId;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.identity.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a local pseudonym is removed.
*/
@Immutable
@NotNullByDefault
public class LocalAuthorRemovedEvent extends Event {
private final AuthorId authorId;
public LocalAuthorRemovedEvent(AuthorId authorId) {
this.authorId = authorId;
}
public AuthorId getAuthorId() {
return authorId;
}
}

View File

@@ -1,9 +1,15 @@
package org.briarproject.api.keyagreement; package org.briarproject.bramble.api.keyagreement;
import org.briarproject.api.TransportId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class KeyAgreementConnection { public class KeyAgreementConnection {
private final DuplexTransportConnection conn; private final DuplexTransportConnection conn;
private final TransportId id; private final TransportId id;

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