Compare commits

..

312 Commits

Author SHA1 Message Date
akwizgran
68738a5a03 Refactor layouts for alias and link dialogs. 2018-10-31 15:28:58 +00:00
Torsten Grote
1a025d0f40 [android] Show existing alias in alias edit text view
This commit also uses LiveData Transformations to expose contact related information
2018-10-30 08:36:10 -03:00
Torsten Grote
a3593ea8ca [android] Show contact alias inside private groups and their memberlist 2018-10-29 19:41:01 -03:00
Torsten Grote
34eaedbd63 Show alias for introduction notices in private conversation 2018-10-29 19:23:22 -03:00
Torsten Grote
44e1ce32ce [android] Show alias for creator of private group in list of private groups 2018-10-29 18:38:20 -03:00
Torsten Grote
7af4b3d3ca [android] Show Author alias in AuthorView 2018-10-29 18:18:05 -03:00
Torsten Grote
1423ca7a15 [android] Add UI for changing and displaying contact alias
Note that this commit only shows the alias where the Contact is
available. In cases, where we only have the Author, only its name is
shown.

This also introduces the first ViewModel to share state between the
ConversationActivity and the AliasDialogFragment.
2018-10-29 18:18:05 -03:00
Torsten Grote
baf64e1129 [bramble] Add transactionless method for retrieving AuthorInfo to ContactManager 2018-10-29 18:16:34 -03:00
Torsten Grote
88adfabe09 Refactor Author.Status into dedicated AuthorInfo class and add alias 2018-10-29 17:23:45 -03:00
Torsten Grote
969150bff0 [bramble] Factor out database type placeholder replacement
to make it available in database schema migrations
2018-10-29 12:50:08 -03:00
Torsten Grote
8fc622f85d [bramble] Add support for contact aliases
Foundation for #41
2018-10-29 12:50:08 -03:00
akwizgran
22eed91019 Merge branch 'javalin-access-manager' into 'master'
[headless] Set up access manager before starting server

See merge request briar/briar!966
2018-10-29 15:35:48 +00:00
akwizgran
fcb88ed58c Merge branch '1147-bluetooth-discovery' into 'master'
Support Bluetooth discovery for adding contacts

See merge request briar/briar!954
2018-10-29 14:35:17 +00:00
Torsten Grote
0d940fc7d7 [headless] Set up access manager before starting server
This became necesary to due an upstream change we missed when bumping
the dependency:

ab19ff91b7
2018-10-29 11:20:48 -03:00
akwizgran
53da13794f Merge branch '1422-activity-log' into 'master'
Log when activities start and stop

See merge request briar/briar!959
2018-10-24 16:00:52 +00:00
akwizgran
2ab03f48cc Merge branch '1256-remove-contact' into 'master'
briar-headless: Add endpoint for removing a contact

See merge request briar/briar!962
2018-10-24 15:59:39 +00:00
Torsten Grote
436f45554d [briar-headless] update dependencies 2018-10-24 12:41:29 -03:00
Torsten Grote
51209b5eec briar-headless: Add endpoint for removing a contact 2018-10-24 12:12:33 -03:00
akwizgran
822597b4c6 Merge branch '1373-mirror-icons' into 'master'
Fix RTL icon mirroring in DevReportActivity

Closes #1373

See merge request briar/briar!960
2018-10-24 14:05:06 +00:00
akwizgran
7c01bc59c0 Merge branch '1252-dark-theme-system-default' into 'master'
Remove system default theme option on API < 28

Closes #1252

See merge request briar/briar!961
2018-10-24 13:52:20 +00:00
Torsten Grote
825d342f9b Remove system default theme option on API < 27
Closes #1252
2018-10-24 10:40:43 -03:00
Torsten Grote
34955fecbb Fix RTL icon mirroring in DevReportActivity
For some reason, the toolbar icon has a wrong layout direction,
so the autoMirrored attribute doesn't take any effect.
2018-10-22 16:53:17 -03:00
Torsten Grote
5c28b60a6b Log when activities start and stop
Remove BriarRecyclerView log messages
2018-10-22 14:11:36 -03:00
akwizgran
389b2b5b8e Merge branch '1423-check-lifecycle-state' into 'master'
Check lifecycle state before changing fragment

Closes #1423

See merge request briar/briar!958
2018-10-22 14:27:30 +00:00
Torsten Grote
78abfa3698 Check lifecycle state before changing fragment 2018-10-19 16:40:00 -03:00
akwizgran
9c4fb4fd34 Remove unused string. 2018-10-18 17:22:54 +01:00
akwizgran
3d6a336f6d Refactor permissions code, add comments, fix corner cases. 2018-10-18 17:16:49 +01:00
akwizgran
e47d41596a Merge branch '1254-inject-object-mapper' into 'master'
briar-headless: Inject a singleton ObjectMapper for JSON parsing

See merge request briar/briar!957
2018-10-18 15:40:20 +00:00
Torsten Grote
8cf54bcedb briar-headless: Inject a singleton ObjectMapper for JSON parsing 2018-10-18 09:55:34 -03:00
akwizgran
89d5145665 Bump version numbers for 1.1.3 release. 2018-10-17 17:51:11 +01:00
Torsten Grote
0706498b03 Merge branch 'upgrade-android-gradle-plugin' into 'master'
Upgrade Android Gradle plugin to 3.2.1.

See merge request briar/briar!956
2018-10-17 16:36:24 +00:00
akwizgran
b296500e7a Update translations. 2018-10-17 12:41:24 +01:00
akwizgran
60a8b03344 Upgrade Android Gradle plugin to 3.2.1. 2018-10-17 12:34:13 +01:00
Torsten Grote
ae16a93522 Merge branch 'compact-at-startup' into 'master'
Compact the database at startup

See merge request briar/briar!955
2018-10-16 16:02:40 +00:00
Torsten Grote
c9a2ff71ae Merge branch 'tor-v3-hidden-service-addresses' into 'master'
Add support for v3 hidden service addresses

See merge request briar/briar!952
2018-10-16 15:55:34 +00:00
akwizgran
16f4c60a56 Add test for compaction time. 2018-10-16 11:39:06 +01:00
akwizgran
76121eb871 Always compact the DB if migrations have been applied. 2018-10-16 11:24:47 +01:00
akwizgran
47c91a96ae Compact the database at startup. 2018-10-16 11:13:37 +01:00
akwizgran
14befb957b Add support for v3 hidden service addresses. 2018-10-16 10:15:18 +01:00
akwizgran
4b7a81177c Static imports. 2018-10-15 14:46:40 +01:00
Torsten Grote
b464fe1653 Merge branch 'message-terminology' into 'master'
Use "text" to refer to message text

See merge request briar/briar!948
2018-10-15 13:22:31 +00:00
akwizgran
09c6f09805 Merge branch '1420-tor-status-update' into 'master'
Disable TorPlugin before applying changed settings

Closes #1420

See merge request briar/briar!953
2018-10-15 12:54:41 +00:00
Torsten Grote
a93093182d Disable TorPlugin before applying changed settings
The is necessary for two reasons:

1. Since Tor 0.3.4.8, it doesn't reconnect when changing the value of
   UseBridges via the control connection without also resetting
   DisableNetwork
2. The TorPlugin needs to set itself to a disconnected state for the UI
   to properly reflect this new state

Fixes #1420
2018-10-15 09:43:12 -03:00
akwizgran
9515e93857 Cancel discovery after 10 seconds and try to connect. 2018-10-15 11:04:46 +01:00
akwizgran
efe15df940 Remove static import of R's fields. 2018-10-15 11:04:46 +01:00
akwizgran
de611857cf Discover BT devices if no address is provided. 2018-10-15 11:04:46 +01:00
akwizgran
8935ec2c2e Don't wait for state change if BT is already discoverable. 2018-10-15 11:04:45 +01:00
akwizgran
bd00fb1c04 Ask for coarse location permission before adding a contact. 2018-10-15 11:04:45 +01:00
akwizgran
3192015cfd Ask for Bluetooth discoverability before adding a contact. 2018-10-15 11:04:45 +01:00
Torsten Grote
e776ee02b0 Merge branch 'tor-0.3.4.8' into 'master'
Upgrade Tor to 0.3.4.8

See merge request briar/briar!951
2018-10-11 22:44:45 +00:00
akwizgran
c0553ec11f Upgrade Linux Tor binaries to 0.3.4.8. 2018-10-11 15:05:39 +01:00
akwizgran
75a871a2f8 Upgrade Android Tor binaries to 0.3.4.8. 2018-10-11 14:38:18 +01:00
akwizgran
d6d3d5acef Merge branch '1240-no-empty-messages' into 'master'
Don't allow empty message bodies

See merge request briar/briar!949
2018-10-10 14:52:34 +00:00
Torsten Grote
a361a2613c Merge branch 'test-configurations' into 'master'
Update test configurations for Android Studio 3.2

See merge request briar/briar!950
2018-10-10 12:38:19 +00:00
akwizgran
b68dbd6a75 Merge branch 'upgrade-dependencies' into 'master'
Upgrade some of the things

See merge request briar/briar!935
2018-10-10 11:42:45 +00:00
akwizgran
f1e89a3ff4 Don't allow empty message bodies. 2018-10-10 10:57:41 +01:00
akwizgran
056c23167d Update test configurations for Android Studio 3.2. 2018-10-10 10:43:07 +01:00
akwizgran
79d5612645 Use "text" to refer to message text. 2018-10-10 10:40:30 +01:00
akwizgran
a030f92275 Merge branch 'headless' into 'master'
Add Briar headless client that exposes a REST API

See merge request briar/briar!931
2018-10-09 15:43:31 +00:00
Torsten Grote
b3615b4a77 briar-headless: Last round of review comments 2018-10-09 12:19:21 -03:00
akwizgran
8a15fb242a Merge branch 'briar-integration-test-transaction' into 'master'
Remove custom DB transaction code from BriarIntegrationTest

See merge request briar/briar!946
2018-10-09 14:16:23 +00:00
Torsten Grote
e3686186ee Fix closing server with ^C 2018-10-08 18:40:21 -03:00
akwizgran
18ae388137 Merge branch '1395-low-memory-crash' into 'master'
Don't use non-AppCompat theme for AppCompat activities

Closes #1395

See merge request briar/briar!947
2018-10-08 12:03:20 +00:00
Torsten Grote
775031e893 Don't use non-AppCompat theme for AppCompat activities
Fixes #1395
2018-10-05 16:50:11 -03:00
Torsten Grote
9f91b91a4f Remove custom DB transaction code from BriarIntegrationTest 2018-10-05 15:41:29 -03:00
Torsten Grote
280f3ba1fc briar-headless: POST text as JSON in body instead of form parameter 2018-10-05 15:23:31 -03:00
Torsten Grote
66619fd3a4 briar-headless: Next round of review comments 2018-10-05 15:23:31 -03:00
akwizgran
c7eb0cbb6d Include body of private request if present. 2018-10-05 15:23:31 -03:00
akwizgran
1617a95bb9 Only include "body" for headers that can have bodies. 2018-10-05 15:23:31 -03:00
Torsten Grote
6f54718756 Use short type labels in JSON API instead of long Java-like namespaces 2018-10-05 15:23:31 -03:00
Torsten Grote
ea749f2128 Minor improvements to JsonDict output classes 2018-10-05 15:23:31 -03:00
akwizgran
b4b0d3daa6 Allow null values in JsonDict. 2018-10-05 15:23:31 -03:00
akwizgran
609c90f57e Convert Map#put() to assignment. 2018-10-05 15:23:31 -03:00
akwizgran
5cf68fa134 Use JsonDict for blog post headers. 2018-10-05 15:23:31 -03:00
akwizgran
61c9c6b8eb Add visitor to dispatch output() dynamically. 2018-10-05 15:23:31 -03:00
akwizgran
e97608da40 Add test to show that static dispatch won't work. 2018-10-05 15:23:31 -03:00
akwizgran
0bb80b1a15 Add JsonDict class for JSON output. 2018-10-05 15:23:31 -03:00
akwizgran
bda52ea548 Use maps for JSON output. 2018-10-05 15:23:31 -03:00
Torsten Grote
cf033dc29d briar-headless: Address second round of review comments 2018-10-05 15:23:31 -03:00
Torsten Grote
c12cedc371 briar-headless: Address first round of review comments 2018-10-05 15:23:31 -03:00
Torsten Grote
4b5e9bd64f Ensure the use SecureRandom when creating authentication token 2018-10-05 15:23:31 -03:00
Torsten Grote
8d55911dab Add unit test for WebSocketController
Also move the controller into an event package
2018-10-05 15:23:31 -03:00
Torsten Grote
e381f83512 Last code cleanup before submitting merge request 2018-10-05 15:23:31 -03:00
Torsten Grote
e4c7f13832 Add a README.md with API documentation
Also fix some smaller issues found during writing the documentation
2018-10-05 15:23:31 -03:00
Torsten Grote
b089a204d3 Add support for websocket authentication via basic auth
The token should be used as username and the password left empty
2018-10-05 15:23:31 -03:00
Torsten Grote
85fcb34997 Add briar-headless Android Studio run configuration 2018-10-05 15:23:31 -03:00
Torsten Grote
d6d132a9cf Add Bearer Authentication to REST API 2018-10-05 15:23:31 -03:00
Torsten Grote
98d1ea7730 briar-headless: Add more controller tests
Current controller line coverage: 100%
2018-10-05 15:23:31 -03:00
Torsten Grote
159fd34c0c Use Conversation Manager for message retrieval 2018-10-05 15:23:31 -03:00
Torsten Grote
9e7a387ea4 Turn output classes into Kotlin data classes 2018-10-05 15:23:31 -03:00
Torsten Grote
138e520e6c briar-headless: Add command line arguments 2018-10-05 15:23:31 -03:00
Torsten Grote
5783c1dfd8 briar-headless: Add a websocket controller for private message events
Also version API URLs
2018-10-05 15:23:31 -03:00
Torsten Grote
348968018a Migrate REST classes to Kotlin and upgrade Javalin 2018-10-05 15:23:31 -03:00
Torsten Grote
33c509cd1f briar-headless: Add Kotlin and first unit test for blogs with Mockk 2018-10-05 15:23:31 -03:00
Torsten Grote
bea77151bd briar-headless: Add API to list all contacts 2018-10-05 15:23:31 -03:00
Torsten Grote
787e62345f Add simple MessagingController 2018-10-05 15:23:31 -03:00
Torsten Grote
48f6a3b91f Add Tor plugin to headless client and introduce new ConfigurationManager 2018-10-05 15:23:31 -03:00
Torsten Grote
a798e25bf2 Save app data always in $HOME/.briar for now 2018-10-05 15:23:31 -03:00
Torsten Grote
31e4045cf7 Try to shutdown cleanly when server stops or SIGINT is received 2018-10-05 15:23:31 -03:00
Torsten Grote
5334a8c9ca Add basic support for listing and writing blog posts 2018-10-05 15:23:31 -03:00
Torsten Grote
d11f1d2805 Add a poor man's argument to explicitly turn on verbose logging 2018-10-05 15:23:31 -03:00
Torsten Grote
0d1ebddcd2 Allow account creation and reading password from STDIN 2018-10-05 15:23:31 -03:00
Torsten Grote
6c296c1348 Proof-of-Concept Headless Client 2018-10-05 15:23:31 -03:00
akwizgran
87701e5f07 Merge branch 'transactional-db' into 'master'
Transactional DB interface

See merge request briar/briar!945
2018-10-05 15:19:40 +00:00
Torsten Grote
3aae01d152 Merge branch 'panic-app-list' into 'master'
Update list of panic button apps after installing app

Closes #1392

See merge request briar/briar!940
2018-10-05 14:18:44 +00:00
akwizgran
bc298ba68a Remove unnecessary final modifiers. 2018-10-05 09:34:41 +01:00
akwizgran
2623eaa149 Remove unnecessary throwing variants. 2018-10-05 09:32:01 +01:00
akwizgran
7359b6942a Use transactional DB interface for ForumManagerImpl. 2018-10-04 15:59:10 +01:00
akwizgran
3bcc532b4b Add transactional DB interface. 2018-10-04 15:56:21 +01:00
akwizgran
4d08c69779 Revert spurious changes to run configurations. 2018-10-03 13:08:00 +01:00
Torsten Grote
a6cd8937f7 Remove space reserved for icons from preferences
Works around https://issuetracker.google.com/issues/111907042

Might be replacable with a solution from
https://issuetracker.google.com/issues/111907042 in the future.
2018-10-03 12:58:49 +01:00
akwizgran
e8566906ef Update gradle-witness to exclude android.jar from dependencies. 2018-10-03 12:48:29 +01:00
akwizgran
929102ed60 Upgrade build tools to 28.0.3. 2018-10-03 12:48:29 +01:00
akwizgran
3b871f5932 Update ProGuard rules for new OkHttp version. 2018-10-03 12:48:29 +01:00
akwizgran
b972d1fc13 Update ACRA usage for new version. 2018-10-03 12:48:28 +01:00
akwizgran
ccbeee60a7 Upgrade Rome, OkHttp and jsoup libraries. 2018-10-03 12:48:28 +01:00
akwizgran
074b10e177 Upgrade JNA library. 2018-10-03 12:48:28 +01:00
akwizgran
031516ccce Upgrade curve25519-java library. 2018-10-03 12:48:28 +01:00
akwizgran
7d2f1abb94 Upgrade Gradle APT and Animal Sniffer plugins. 2018-10-03 12:48:28 +01:00
akwizgran
00b9c76bb8 Upgrade ACRA. 2018-10-03 12:48:28 +01:00
akwizgran
4d9fab85cb Upgrade zxing, material tap target libraries. 2018-10-03 12:48:28 +01:00
akwizgran
bd2514a299 Upgrade support library to 28.0.0. 2018-10-03 12:48:27 +01:00
akwizgran
e795efc7fc Bump compileSdkVersion for bramble-android. 2018-10-03 12:48:27 +01:00
akwizgran
6691d2164f Upgrade Gradle Android plugin and build tools. 2018-10-03 12:48:27 +01:00
Administrator
a384450c36 Merge branch '1373-format-numbers' into 'master'
Format numbers in locale as well (not all languages use the same)

See merge request briar/briar!943
2018-10-03 11:41:56 +00:00
akwizgran
b375e9873c Merge branch '1409-localize-crash-screen' into 'master'
Localize crash screen in language defined in settings

Closes #1409

See merge request briar/briar!944
2018-10-03 07:53:41 +00:00
Torsten Grote
cb30c3885a Localize crash screen in language defined in settings 2018-10-02 17:56:33 -03:00
Torsten Grote
6ee81eb24c Format numbers in locale as well (not all languages use the same)
Done according to
https://developer.android.com/training/basics/supporting-devices/languages#FormatNumbers
2018-10-02 17:31:23 -03:00
Torsten Grote
c14ebe82ce Merge branch '1365-keep-screen-on' into 'master'
Keep screen on while QR code viewfinder is open

See merge request briar/briar!942
2018-10-02 11:20:46 +00:00
Torsten Grote
00e9f894b1 Merge branch 'remove-tor-patch' into 'master'
Remove unused patches

See merge request briar/briar!941
2018-10-02 11:13:06 +00:00
akwizgran
499c586a59 Keep screen on while scanning QR code. 2018-10-02 12:03:29 +01:00
akwizgran
64f9ce7306 Remove unused patches. 2018-10-02 11:49:29 +01:00
akwizgran
39478a7914 Bump version numbers for 1.1.2 release. 2018-10-01 14:58:45 +01:00
akwizgran
112e71a9cb Bump version numbers for 1.0.2 release. 2018-10-01 14:56:08 +01:00
akwizgran
5650bef310 Update translations. 2018-10-01 14:56:08 +01:00
akwizgran
2a87171c49 Merge branch 'manual-screenshots' into 'master'
Create Screenshot of Conversation for Manual

Closes #1377

See merge request briar/briar!910
2018-10-01 13:41:05 +00:00
akwizgran
071d961ed1 Remove debug logging. 2018-09-28 11:31:22 +01:00
akwizgran
cb9efc5fec Fix lint warnings. 2018-09-28 11:28:47 +01:00
akwizgran
f9e292f734 Update panic app list after installing app. 2018-09-28 11:27:08 +01:00
akwizgran
15cb5409e7 Merge branch '1352-panic-ripple-fdroid' into 'master'
Fix Panic Button bugs

Closes #1109 and #1352

See merge request briar/briar!937
2018-09-28 09:57:18 +00:00
akwizgran
fd07dc006d Update comment. 2018-09-28 09:55:47 +01:00
akwizgran
cc87c4e37d Merge branch '1391-start-end-api15' into 'master'
RTL language layout fixes

Closes #1391

See merge request briar/briar!938
2018-09-28 08:45:17 +00:00
akwizgran
4a10e876f6 Merge branch '1389-notice-shadows' into 'master'
Fix notice shadows

Closes #1389

See merge request briar/briar!939
2018-09-28 08:43:06 +00:00
Torsten Grote
fad0057c4a Fix notice shadows 2018-09-27 20:32:13 -03:00
Torsten Grote
5aabfcea9a Unmirror checkboxes in RTL layouts 2018-09-27 19:09:08 -03:00
Torsten Grote
f7d928c774 Fix start/end margins for API 15
Fixes #1391
2018-09-27 19:07:13 -03:00
Torsten Grote
bd983d9796 Remove non-functional uninstall panic action
Fixes #1109
2018-09-27 18:37:57 -03:00
Torsten Grote
de8d1b7d96 Allow sign out by trusted non-paired panic apps 2018-09-27 18:25:31 -03:00
Torsten Grote
9155f62d0b Remove Amnesty International's key and add F-Droid Ripple key instead
Fixes #1352
2018-09-27 18:17:14 -03:00
akwizgran
86684e228a Merge branch 'slow-bridges' into 'master'
Update bridge list, test for slow bridges

See merge request briar/briar!936
2018-09-27 16:10:22 +00:00
akwizgran
9615eff649 Add new bridges to replace slow ones. 2018-09-27 16:11:52 +01:00
akwizgran
9381d46f51 Remove two bridges that are slow to bootstrap. 2018-09-27 16:08:14 +01:00
akwizgran
e4a3a1ad40 Delete Tor state after testing each bridge. 2018-09-27 16:07:46 +01:00
akwizgran
905dc2a662 Merge branch 'qr-code-version-errors' into 'master'
Show different error message if QR code is too new

See merge request briar/briar!934
2018-09-24 16:42:43 +00:00
Torsten Grote
c2b7f85b8e Remove code from TestDataCreator that breaks encapsulation 2018-09-24 12:37:11 -03:00
Torsten Grote
ae81eb3737 Throw AssertionError when creating an account while a database key is in memory 2018-09-24 12:37:11 -03:00
Torsten Grote
60d949c342 Refactor tests so that all test data is created in the first test 2018-09-24 12:37:11 -03:00
Torsten Grote
1c90e64894 Split up UI and Screenshot tests
Closes #1377
2018-09-24 12:37:06 -03:00
Torsten Grote
f0e2d5281f Create Screenshot of Conversation for Manual 2018-09-24 12:34:26 -03:00
akwizgran
c7522dae1f Show different error message if QR code is too new. 2018-09-24 13:21:45 +01:00
Torsten Grote
097d14b9a1 Merge branch 'private-message-visitor' into 'master'
Use visitor pattern to create conversation items

See merge request briar/briar!933
2018-09-20 19:04:14 +00:00
akwizgran
0491c3cace Use a visitor to create ConversationItems. 2018-09-20 16:53:48 +01:00
akwizgran
cbae13feca Merge branch 'gradle-4.10' into 'master'
Upgrade the gradle wrapper to version 4.10.2

See merge request briar/briar!932
2018-09-20 15:34:33 +00:00
Torsten Grote
b7c8859c82 Upgrade the gradle wrapper to version 4.10.2 2018-09-20 11:52:19 -03:00
akwizgran
2e120f752c Add parameterised return type. 2018-09-20 15:19:22 +01:00
akwizgran
031eac54c5 Add private message visitor. 2018-09-20 14:43:19 +01:00
akwizgran
2c2596afdd Merge branch 'conversation-manager' into 'master'
Use ConversationManager for private message retrieval

See merge request briar/briar!912
2018-09-20 13:01:53 +00:00
akwizgran
d1be14effe Merge branch '1386-app-lock-after-signout' into 'master'
Fix app lock after sign-out bug

Closes #1386

See merge request briar/briar!930
2018-09-20 11:05:37 +00:00
akwizgran
b56e7ab07d Merge branch 'roboelectric-android-http-client' into 'master'
Remove AndroidHttpClient class after Roboelectric update

See merge request briar/briar!929
2018-09-20 11:04:52 +00:00
akwizgran
089e9589ed Merge branch '1378-rtl-support' into 'master'
Add support for right-to-left languages

Closes #1378, #1076, #1078, #964, #1080, and #1079

See merge request briar/briar!918
2018-09-20 10:59:44 +00:00
Torsten Grote
660ba16a14 Fix app lock after sign-out bug
It some cases, it was observered how the app was locked after the user
had signed out.
This commit ensures that set alarms are canceled and that no new ones
will be set after the LockManager service has been stopped.

Fixes #1386
2018-09-19 16:06:13 -03:00
Torsten Grote
b101c4b636 Remove AndroidHttpClient class after Roboelectric update 2018-09-19 15:15:38 -03:00
Torsten Grote
fdfddd2667 Fix small RTL UI glitches in blog post layouts 2018-09-19 14:56:45 -03:00
akwizgran
296546544f Remove auto-generated layout IDs. 2018-09-19 17:42:25 +01:00
akwizgran
ad579a6ba3 Restore max of 50 contacts. 2018-09-19 17:42:09 +01:00
Torsten Grote
90e82357ba Move back to previous way of creating at least one test contact 2018-09-19 11:38:00 -03:00
Torsten Grote
b3b40753d8 RTL support: Address review issues 2018-09-19 11:33:03 -03:00
Torsten Grote
e60df3cece Don't crash when creating test data with 0 contacts
If no contacts exist, at least one will be created
2018-09-19 11:33:03 -03:00
Torsten Grote
da3cb95151 Move TrustIndicator behind date in AuthorView
to prevent it from being pushed off-screen

Fixes #1076
2018-09-19 11:33:03 -03:00
Torsten Grote
c27885072f Ellipzise long contact names in ConversationActivity
Fixes #1078
2018-09-19 11:33:03 -03:00
Torsten Grote
6557d564c9 Add RTL support to remaining layouts 2018-09-19 11:33:03 -03:00
Torsten Grote
53edcaf3e9 Add RTL support to remaining list items
Also fixes several small UI glitches with long texts
2018-09-19 11:33:03 -03:00
Torsten Grote
5122c961b4 Simplify dev reporter and add RTL support 2018-09-19 11:33:03 -03:00
Torsten Grote
f83b9244d4 Clean up threaded discussion screen
Adds RTL support
Fixing cropping bug

Closes #964
2018-09-19 11:33:03 -03:00
Torsten Grote
81292967e0 Add RTL support to conversation message bubbles 2018-09-19 11:33:03 -03:00
Torsten Grote
b72f6b4fc3 Migrate Introduction Screen to ConstraintLayout
Adds RTL support
Fixes issue with long contact names

Closes #1080
2018-09-19 11:33:03 -03:00
Torsten Grote
488be49c93 Convert contact lists to ConstraintLayout
Adds support for RTL languages
Fixes issues with long contact names

Closes #1079
2018-09-19 11:33:03 -03:00
Torsten Grote
90db45817a Add RTL language support to all activities and fragments 2018-09-19 11:33:03 -03:00
akwizgran
81863b9db6 Merge branch '1248-rename-lock-app' into 'master'
Rename "Screen lock" to "Lock app"

Closes #1248 and #1245

See merge request briar/briar!924
2018-09-19 14:28:34 +00:00
akwizgran
da069adb57 Merge branch '1186-remove-lock-screen-notification-setting' into 'master'
Remove lockscreen notification setting

Closes #1186

See merge request briar/briar!925
2018-09-19 14:27:31 +00:00
Torsten Grote
46425b09fa Rename "Screen lock" to "App lock" 2018-09-19 10:22:43 -03:00
akwizgran
41e1a436c9 Merge branch 'centre-decrypting-db-message' into 'master'
Align "decrypting database" message to centre

See merge request briar/briar!926
2018-09-19 11:46:55 +00:00
Torsten Grote
989394d18b Merge branch 'fingerprint-permission' into 'master'
Add obsolete fingerprint permission to satisfy Android Studio

See merge request briar/briar!927
2018-09-19 11:32:58 +00:00
akwizgran
b6b3f9c292 Align "decrypting database" message to centre. 2018-09-19 12:23:13 +01:00
akwizgran
a52547f73b Add obsolete fingerprint permission. 2018-09-19 12:19:33 +01:00
akwizgran
24f823a3ce Remove lock screen notification setting. 2018-09-19 10:50:46 +01:00
akwizgran
a045d7d306 Merge branch '1384-expiry-time' into 'master'
Fix off-by-one error in expiry calculation

Closes #1384

See merge request briar/briar!923
2018-09-18 17:15:54 +00:00
akwizgran
a29d5efd93 Fix off-by-one error in expiry calculation. 2018-09-18 18:01:44 +01:00
akwizgran
37cd1cdddf Merge branch '541-faster-retransmission-eta' into 'master'
Allow retransmission if it will result in faster delivery

Closes #541

See merge request briar/briar!908
2018-09-18 14:26:22 +00:00
akwizgran
4f495bb4d3 Use now + max latency as ETA, add more tests. 2018-09-18 16:05:25 +02:00
goapunk
1a70200b65 Allow retransmission if faster.
* This commit introduces an estimated time of arrival (eta) to the
message status which helps to decide whether a message should be
retransmitted over a faster transport.
2018-09-18 16:05:25 +02:00
akwizgran
6925dfcbdd Merge branch '1240-message-refactoring' into 'master'
Remove raw representation from Message class

See merge request briar/briar!915
2018-09-18 13:30:26 +00:00
Torsten Grote
7d479063a9 ConversationManager: Address review issues 2018-09-18 10:10:21 -03:00
Torsten Grote
2309e73216 Fix bug where available invitations were marked answered
Now an invitiation was answered when it is no longer available
2018-09-18 10:10:21 -03:00
akwizgran
4b325f797b Combine LiveData observers, avoid redundant loads. 2018-09-18 10:10:21 -03:00
Torsten Grote
9be83c3cc7 Refactor ConversationItem creation 2018-09-18 10:10:21 -03:00
Torsten Grote
86f650503b Re-introduce InvitationResponse
This was done, so private responses don't need to include a Nameable already.
Retreiving a nameable is tricky and requires a data migration,
so we just don't do it now.
2018-09-18 10:10:21 -03:00
Torsten Grote
d430b4fd2d Move introduction role into IntroductionResponse 2018-09-18 10:10:21 -03:00
akwizgran
fcf7cf72ea Refactor doesExist() method. 2018-09-18 10:10:21 -03:00
Torsten Grote
b78dfea95f Remove ListenableFutureTask and replace it with LiveData 2018-09-18 10:10:21 -03:00
Torsten Grote
183fe08565 Rename object to nameable 2018-09-18 10:10:21 -03:00
Torsten Grote
7e32697696 Use ConversationManager to retrieve messages
This removes the public method for retrieving messages
from individual conversation clients
and just leaves methods that require a transaction
to be used by the ConversationManager only.
2018-09-18 10:10:21 -03:00
Torsten Grote
29758b174a Unify all events related to private messages 2018-09-18 10:10:21 -03:00
Torsten Grote
61e18f104e Unify all private message responses in one PrivateResponse class
This also adds `Shareable`s to invitation response
which is a precondition for #561
2018-09-18 10:10:21 -03:00
Torsten Grote
ffeca8817f Prepare private message retrieval through ConversationManager 2018-09-18 10:10:21 -03:00
Torsten Grote
59fae2fa3c Unify all private message requests in one PrivateRequest class 2018-09-18 10:10:21 -03:00
Torsten Grote
2d9345c018 Remove unnecessary information from private message classes 2018-09-18 10:10:21 -03:00
akwizgran
817df9c75a Merge branch '1247-flag-secure-warning' into 'master'
Add warning to FLAG_SECURE about app locking implications

Closes #1247

See merge request briar/briar!922
2018-09-17 16:08:43 +00:00
Torsten Grote
745515457e Add warning to FLAG_SECURE about app locking implications 2018-09-17 12:21:16 -03:00
akwizgran
ba5928218a Reduce code duplication in TestMessageFactory. 2018-09-14 17:50:17 +01:00
akwizgran
9476782ced Bump version numbers for 1.1.1 release. 2018-09-14 13:16:17 +01:00
akwizgran
74445acb55 Merge branch '1379-startup-failure-error' into 'master'
Correct startup database failure error messages

Closes #1379

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

Closes #1359

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

Closes #1367

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

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

Closes #1189

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

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

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

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

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

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

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

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

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

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

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

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

Closes #758

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

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

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

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

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

Closes #1349

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

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

Closes #1269

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

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

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

Closes #1358

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

View File

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

View File

@@ -36,6 +36,9 @@
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" /> <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" /> <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
</JavaCodeStyleSettings> </JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<Objective-C-extensions> <Objective-C-extensions>
<file> <file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
@@ -257,5 +260,11 @@
</rules> </rules>
</arrangement> </arrangement>
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="1" />
</codeStyleSettings>
</code_scheme> </code_scheme>
</component> </component>

View File

@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All in briar-headless" type="AndroidJUnit" factoryName="Android JUnit" nameIsGenerated="true">
<module name="briar-headless" />
<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="" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-headless" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit"> <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" /> <module name="bramble-api" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit"> <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" /> <module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

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

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit"> <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" /> <module name="briar-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit"> <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" /> <module name="briar-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" /> <module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" /> <module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
@@ -11,12 +10,10 @@
<option name="VM_PARAMETERS" value="-ea" /> <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="singleModule" />
</option> </option>
<envs />
<patterns /> <patterns />
<method /> <method />
</configuration> </configuration>

View File

@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" factoryName="Kotlin" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="-v" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" />
<option name="WORKING_DIRECTORY" value="" />
<module name="briar-headless" />
<envs />
<method>
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" />
</method>
</configuration>
</component>

View File

@@ -3,14 +3,14 @@ apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
android { android {
compileSdkVersion 27 compileSdkVersion 28
buildToolsVersion '27.0.3' buildToolsVersion '28.0.3'
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10013 versionCode 10103
versionName "1.0.13" versionName "1.1.3"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -28,7 +28,7 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.2.9.16@zip' tor 'org.briarproject:tor-android:0.3.4.8@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
@@ -41,12 +41,6 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3" testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3" testImplementation "org.hamcrest:hamcrest-core:1.3"
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
} }
project.afterEvaluate { project.afterEvaluate {

View File

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

View File

@@ -16,18 +16,27 @@ import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE; import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
@@ -37,8 +46,13 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_OFF;
import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -47,8 +61,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidBluetoothPlugin.class.getName()); Logger.getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
private final AndroidExecutor androidExecutor; private final AndroidExecutor androidExecutor;
private final Context appContext; private final Context appContext;
private final Clock clock;
private volatile boolean wasEnabledByUs = false; private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null; private volatile BluetoothStateReceiver receiver = null;
@@ -58,12 +75,13 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor, Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Backoff backoff, Context appContext, SecureRandom secureRandom, Clock clock,
DuplexPluginCallback callback, int maxLatency) { Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback, super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency); maxLatency);
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.appContext = appContext; this.appContext = appContext;
this.clock = clock;
} }
@Override @Override
@@ -182,6 +200,74 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
} }
} }
@Override
@Nullable
DuplexTransportConnection discoverAndConnect(String uuid) {
if (adapter == null) return null;
for (String address : discoverDevices()) {
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
return connectTo(address, uuid);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to "
+ scrubMacAddress(address));
}
}
}
LOG.info("Could not connect to any devices");
return null;
}
private Collection<String> discoverDevices() {
List<String> addresses = new ArrayList<>();
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();
DiscoveryReceiver receiver = new DiscoveryReceiver(intents);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
appContext.registerReceiver(receiver, filter);
try {
if (adapter.startDiscovery()) {
long now = clock.currentTimeMillis();
long end = now + MAX_DISCOVERY_MS;
while (now < end) {
Intent i = intents.poll(end - now, MILLISECONDS);
if (i == null) break;
String action = i.getAction();
if (ACTION_DISCOVERY_STARTED.equals(action)) {
LOG.info("Discovery started");
} else if (ACTION_DISCOVERY_FINISHED.equals(action)) {
LOG.info("Discovery finished");
break;
} else if (ACTION_FOUND.equals(action)) {
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
String address = d.getAddress();
if (LOG.isLoggable(INFO))
LOG.info("Discovered " + scrubMacAddress(address));
if (!addresses.contains(address))
addresses.add(address);
}
now = clock.currentTimeMillis();
}
} else {
LOG.info("Could not start discovery");
}
} catch (InterruptedException e) {
LOG.info("Interrupted while discovering devices");
Thread.currentThread().interrupt();
} finally {
LOG.info("Cancelling discovery");
adapter.cancelDiscovery();
appContext.unregisterReceiver(receiver);
}
// Shuffle the addresses so we don't always try the same one first
Collections.shuffle(addresses);
return addresses;
}
private void tryToClose(@Nullable Closeable c) { private void tryToClose(@Nullable Closeable c) {
try { try {
if (c != null) c.close(); if (c != null) c.close();
@@ -207,4 +293,18 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
} }
} }
} }
private static class DiscoveryReceiver extends BroadcastReceiver {
private final BlockingQueue<Intent> intents;
private DiscoveryReceiver(BlockingQueue<Intent> intents) {
this.intents = intents;
}
@Override
public void onReceive(Context ctx, Intent intent) {
intents.add(intent);
}
}
} }

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -33,17 +34,19 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private final Context appContext; private final Context appContext;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final EventBus eventBus; private final EventBus eventBus;
private final Clock clock;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
public AndroidBluetoothPluginFactory(Executor ioExecutor, public AndroidBluetoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, Context appContext, AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, EventBus eventBus, SecureRandom secureRandom, EventBus eventBus, Clock clock,
BackoffFactory backoffFactory) { 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.eventBus = eventBus;
this.clock = clock;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
} }
@@ -65,7 +68,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin( AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, ioExecutor, androidExecutor, appContext, connectionLimiter, ioExecutor, androidExecutor, appContext,
secureRandom, backoff, callback, MAX_LATENCY); secureRandom, clock, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -22,9 +22,11 @@ class AndroidResourceProvider implements ResourceProvider {
} }
@Override @Override
public InputStream getResourceInputStream(String name) { public InputStream getResourceInputStream(String name, String extension) {
Resources res = appContext.getResources(); Resources res = appContext.getResources();
int resId = res.getIdentifier(name, "raw", appContext.getPackageName()); // extension is ignored on Android, resources are retrieved without it
int resId =
res.getIdentifier(name, "raw", appContext.getPackageName());
return res.openRawResource(resId); return res.openRawResource(resId);
} }
} }

View File

@@ -1,43 +1,42 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.support.test:monitor:1.0.2:monitor-1.0.2.aar:38ef4fa98a32dc55550ff49bb36a583e178b3a9b830fcb8dcc27bfc4254bc2bc', 'com.android.tools.analytics-library:protos:26.2.1:protos-26.2.1.jar:2f371f5b1f551e85ab08be4d6a2873471b3d44afd1ebf6aa3298f3b796bf691f',
'com.android.support.test:runner:1.0.2:runner-1.0.2.aar:f04b9ae342975ba1cb3e4a06e13426e3e6b8a73faa45acba604493d83c9a4f00', 'com.android.tools.analytics-library:shared:26.2.1:shared-26.2.1.jar:4c1e4e705fa4d45f23aaea230557f6508155012d9c296337787c1d7b26a97f5a',
'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf', 'com.android.tools.analytics-library:tracker:26.2.1:tracker-26.2.1.jar:4a624ecc976539f755ddb0bb8dfc2dd3d08326cfec59a098dbd70f701ca7fb75',
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3', 'com.android.tools.build:aapt2:3.2.1-4818971:aapt2-3.2.1-4818971-linux.jar:f431b6f96c91a2c155144b091a9c97d9805c589fe8efc9c930b6cd346cb60a1e',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3', 'com.android.tools.build:apksig:3.2.1:apksig-3.2.1.jar:2b46f2feffea66037aab29e4261b2433c190194a6ef97b958511eb157f2ccba5',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418', 'com.android.tools.build:apkzlib:3.2.1:apkzlib-3.2.1.jar:c39ad0313905932431fe81c8899c2cf39a4d92ad6c4edcaa4b25432f461452aa',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89', 'com.android.tools.build:builder-model:3.2.1:builder-model-3.2.1.jar:a9f68e6abcec122f9cb5ad352d3f05a3eb03acbcdca95e4d25c16310c2c965ff',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b', 'com.android.tools.build:builder-test-api:3.2.1:builder-test-api-3.2.1.jar:533ac6c2b5884bb54967a33791f2628dfdfac7981af39417a333b43d4379b6be',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389', 'com.android.tools.build:builder:3.2.1:builder-3.2.1.jar:aedcbfd115dbe91d09b4113e66ef50589b558d0aa3b2f133b1d867c9b87fae83',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c', 'com.android.tools.build:gradle-api:3.2.1:gradle-api-3.2.1.jar:57cf0ac5ac1dca8afdb3f62b94265e776e7dcfa641cc3844fb53a05193de208d',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72', 'com.android.tools.build:manifest-merger:26.2.1:manifest-merger-26.2.1.jar:8830573263361035d38cfdcb51e2db94029c93865b21334f5fbf8a27984281a6',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55', 'com.android.tools.ddms:ddmlib:26.2.1:ddmlib-26.2.1.jar:a4bf0a29a19980bf27269465cc782064656750b77c26728f82f9e148b705218b',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd', 'com.android.tools.external.com-intellij:intellij-core:26.2.1:intellij-core-26.2.1.jar:4925ad1892c2687cb1a63427d440ef519c8c59215fefe0dc5d541d5d411fcafe',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec', 'com.android.tools.external.com-intellij:kotlin-compiler:26.2.1:kotlin-compiler-26.2.1.jar:daa064fd708f340ee25fb9823c4c74104ac77f1370b76d907eb9ae6daec0a2ae',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4', 'com.android.tools.external.org-jetbrains:uast:26.2.1:uast-26.2.1.jar:f10f7258d2ab9189562cc0f9ad838c0378fdba439229173390a99de02ebac75b',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265', 'com.android.tools.layoutlib:layoutlib-api:26.2.1:layoutlib-api-26.2.1.jar:ddbf4fca123733fa011595b1cc1f4ac2937ed327b60990711fafc33c775c2ade',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0', 'com.android.tools.lint:lint-api:26.2.1:lint-api-26.2.1.jar:3b57e739de567b98bc9ab56c2c0ee66fc026b4adf5843e8f9804ca0666a6f66e',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751', 'com.android.tools.lint:lint-checks:26.2.1:lint-checks-26.2.1.jar:c86f4cc9aaee722ee4ad70062f7b5af91e9b041914af27adc09f545ab0fb3bc6',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001', 'com.android.tools.lint:lint-gradle-api:26.2.1:lint-gradle-api-26.2.1.jar:2283e7af32e301565f2a797e531f0fc8c648077d457afb3ffdddbee638976c2f',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d', 'com.android.tools.lint:lint-gradle:26.2.1:lint-gradle-26.2.1.jar:8fd90b2f3ec788cbb9801c07ab3e1ea2255aa31a6093157d7ea0ff13d0315ecb',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067', 'com.android.tools.lint:lint-kotlin:26.2.1:lint-kotlin-26.2.1.jar:7a6a5d2b18f69cf1b900d857c2632b4c683713c533295933b8b759f8cab4a877',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68', 'com.android.tools.lint:lint:26.2.1:lint-26.2.1.jar:7848b82ae988b90dee259ae7c7e86e05cbf52db6cd21c8bbd38ce7df08f3f8c5',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df', 'com.android.tools:annotations:26.2.1:annotations-26.2.1.jar:7391c6a1e080174b96e64ceb078dadd31ce4d8a2d2fee0ec65be202126f90f24',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323', 'com.android.tools:common:26.2.1:common-26.2.1.jar:a50aab2d6411ff68f4004a87c7e93d87d8e980a0ec3b352246549897ea2d78e5',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2', 'com.android.tools:dvlib:26.2.1:dvlib-26.2.1.jar:72a83bf2839b1df9b1fbf67ba45d1bfb9f966cd774da4320c762b2be8f1688aa',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855', 'com.android.tools:repository:26.2.1:repository-26.2.1.jar:fa74dae09103faef703df38550ad8fa244c5b6d1bf90d6198be932292b3d9cc1',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59', 'com.android.tools:sdk-common:26.2.1:sdk-common-26.2.1.jar:759d4b292ca69a35cf961fca377b54158fc6c88108978006999442e80a011cf4',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1', 'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed', 'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32', 'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3', '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-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.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b', 'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99', 'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e', 'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f', 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd', 'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4', 'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
@@ -46,8 +45,8 @@ dependencyVerification {
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4', 'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038', 'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86', 'commons-codec:commons-codec:1.9:commons-codec-1.9.jar:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce',
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f', 'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c', 'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
@@ -58,13 +57,13 @@ dependencyVerification {
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8', 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6', 'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550', 'org.apache.httpcomponents:httpclient:4.5.2:httpclient-4.5.2.jar:0dffc621400d6c632f55787d996b8aeca36b30746a716e079a985f24d8074057',
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9', 'org.apache.httpcomponents:httpcore:4.4.5:httpcore-4.4.5.jar:64d5453874cab7e40a7065cb01a9a9ca1053845a9786b478878b679e0580cec3',
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa', 'org.apache.httpcomponents:httpmime:4.5.2:httpmime-4.5.2.jar:231a3f7e4962053db2be8461d5422e68fc458a3a7dd7d8ada803a348e21f8f07',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae', 'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4', 'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d', 'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa', 'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
@@ -73,9 +72,10 @@ dependencyVerification {
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', '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.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd', 'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71:kotlin-stdlib-common-1.2.71.jar:63999687ff2fce8a592dd180ffbbf8f1d21c26b4044c55cdc74ff3cf3b3cf328',
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4', 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.71:kotlin-stdlib-1.2.71.jar:4c895c270b87f5fec2a2796e1d89c15407ee821de961527c28588bb46afbc68b',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7', 'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c', 'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
@@ -84,11 +84,11 @@ dependencyVerification {
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16', 'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4', 'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80', 'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9', 'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4',
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be', 'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf',
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10', 'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215',
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040', 'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220', 'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54', 'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461',
] ]
} }

View File

@@ -0,0 +1,10 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface Nameable {
String getName();
}

View File

@@ -38,4 +38,18 @@ public abstract class StringMap extends Hashtable<String, String> {
public void putInt(String key, int value) { public void putInt(String key, int value) {
put(key, String.valueOf(value)); put(key, String.valueOf(value));
} }
public long getLong(String key, long defaultValue) {
String s = get(key);
if (s == null) return defaultValue;
try {
return Long.valueOf(s);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public void putLong(String key, long value) {
put(key, String.valueOf(value));
}
} }

View File

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

View File

@@ -16,7 +16,6 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; 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; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable @Immutable
@@ -49,14 +48,9 @@ public abstract class BdfMessageValidator implements MessageValidator {
throw new InvalidMessageException( throw new InvalidMessageException(
"Timestamp is too far in the future"); "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 { try {
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH, BdfList bodyList = clientHelper.toList(m.getBody());
raw.length - MESSAGE_HEADER_LENGTH); BdfMessageContext result = validateMessage(m, g, bodyList);
BdfMessageContext result = validateMessage(m, g, body);
Metadata meta = metadataEncoder.encode(result.getDictionary()); Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies()); return new MessageContext(meta, result.getDependencies());
} catch (FormatException e) { } catch (FormatException e) {

View File

@@ -16,8 +16,6 @@ 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 @NotNullByDefault
public interface ClientHelper { public interface ClientHelper {
@@ -32,16 +30,12 @@ public interface ClientHelper {
Message createMessageForStoringMetadata(GroupId g); Message createMessageForStoringMetadata(GroupId g);
@Nullable
Message getMessage(MessageId m) throws DbException; Message getMessage(MessageId m) throws DbException;
@Nullable
Message getMessage(Transaction txn, MessageId m) throws DbException; 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;

View File

@@ -4,8 +4,12 @@ import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class Contact { public class Contact {
@@ -13,13 +17,21 @@ public class Contact {
private final ContactId id; private final ContactId id;
private final Author author; private final Author author;
private final AuthorId localAuthorId; private final AuthorId localAuthorId;
@Nullable
private final String alias;
private final boolean verified, active; private final boolean verified, active;
public Contact(ContactId id, Author author, AuthorId localAuthorId, public Contact(ContactId id, Author author, AuthorId localAuthorId,
boolean verified, boolean active) { @Nullable String alias, boolean verified, boolean active) {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
this.id = id; this.id = id;
this.author = author; this.author = author;
this.localAuthorId = localAuthorId; this.localAuthorId = localAuthorId;
this.alias = alias;
this.verified = verified; this.verified = verified;
this.active = active; this.active = active;
} }
@@ -36,6 +48,11 @@ public class Contact {
return localAuthorId; return localAuthorId;
} }
@Nullable
public String getAlias() {
return alias;
}
public boolean isVerified() { public boolean isVerified() {
return verified; return verified;
} }

View File

@@ -5,11 +5,14 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection; import java.util.Collection;
import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
public interface ContactManager { public interface ContactManager {
@@ -93,6 +96,12 @@ public interface ContactManager {
void setContactActive(Transaction txn, ContactId c, boolean active) void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Return true if a contact with this name and public key already exists * Return true if a contact with this name and public key already exists
*/ */
@@ -105,6 +114,16 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException; throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
interface ContactHook { interface ContactHook {
void addingContact(Transaction txn, Contact c) throws DbException; void addingContact(Transaction txn, Contact c) throws DbException;

View File

@@ -76,6 +76,19 @@ public interface DatabaseComponent {
*/ */
void endTransaction(Transaction txn); void endTransaction(Transaction txn);
/**
* Runs the given task within a transaction.
*/
<E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task.
*/
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/** /**
* Stores a contact associated with the given local and remote pseudonyms, * Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact. * and returns an ID for the contact.
@@ -151,13 +164,13 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns a batch of raw messages for the given contact, with a total * Returns a batch of messages for the given contact, with a total length
* length less than or equal to the given length, for transmission over a * less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no * transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length. * sendable messages that fit in the given length.
*/ */
@Nullable @Nullable
Collection<byte[]> generateBatch(Transaction txn, ContactId c, Collection<Message> generateBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
@@ -178,14 +191,14 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Returns a batch of raw messages for the given contact, with a total * Returns a batch of messages for the given contact, with a total length
* length less than or equal to the given length, for transmission over a * less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Only messages that have been * transport with the given maximum latency. Only messages that have been
* requested by the contact are returned. Returns null if there are no * requested by the contact are returned. Returns null if there are no
* sendable messages that fit in the given length. * sendable messages that fit in the given length.
*/ */
@Nullable @Nullable
Collection<byte[]> generateRequestedBatch(Transaction txn, ContactId c, Collection<Message> generateRequestedBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
@@ -263,6 +276,15 @@ public interface DatabaseComponent {
*/ */
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException; Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(Transaction txn, MessageId m) throws DbException;
/** /**
* Returns the IDs of all delivered messages in the given group. * Returns the IDs of all delivered messages in the given group.
* <p/> * <p/>
@@ -297,15 +319,6 @@ public interface DatabaseComponent {
Collection<MessageId> getMessagesToShare(Transaction txn) Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException; throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(Transaction txn, MessageId m) throws DbException;
/** /**
* Returns the metadata for all delivered messages in the given group. * Returns the metadata for all delivered messages in the given group.
* <p/> * <p/>
@@ -502,6 +515,12 @@ public interface DatabaseComponent {
void setContactActive(Transaction txn, ContactId c, boolean active) void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Sets the given group's visibility to the given contact. * Sets the given group's visibility to the given contact.
*/ */

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.db;
public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E;
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.db;
public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E;
}

View File

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

View File

@@ -6,6 +6,10 @@ public interface MigrationListener {
* This is called when a migration is started while opening the database. * This is called when a migration is started while opening the database.
* It will be called once for each migration being applied. * It will be called once for each migration being applied.
*/ */
void onMigrationRun(); void onDatabaseMigration();
/**
* This is called when compaction is started while opening the database.
*/
void onDatabaseCompaction();
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.Nameable;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -13,11 +14,7 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class Author { public class Author implements Nameable {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
}
/** /**
* The current version of the author structure. * The current version of the author structure.

View File

@@ -0,0 +1,42 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class AuthorInfo {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
public boolean isContact() {
return this == UNVERIFIED || this == VERIFIED;
}
}
private final Status status;
@Nullable
private final String alias;
public AuthorInfo(Status status, @Nullable String alias) {
this.status = status;
this.alias = alias;
}
public AuthorInfo(Status status) {
this(status, null);
}
public Status getStatus() {
return status;
}
@Nullable
public String getAlias() {
return alias;
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault @NotNullByDefault
@@ -37,14 +36,4 @@ public interface IdentityManager {
*/ */
LocalAuthor getLocalAuthor(Transaction txn) throws DbException; LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/**
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(AuthorId a) throws DbException;
/**
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
} }

View File

@@ -3,7 +3,13 @@ package org.briarproject.bramble.api.keyagreement;
public interface KeyAgreementConstants { public interface KeyAgreementConstants {
/** /**
* The current version of the BQP protocol. Version number 89 is reserved. * The version of the BQP protocol used in beta releases. This version
* number is reserved.
*/
byte BETA_PROTOCOL_VERSION = 89;
/**
* The current version of the BQP protocol.
*/ */
byte PROTOCOL_VERSION = 4; byte PROTOCOL_VERSION = 4;
@@ -15,7 +21,7 @@ public interface KeyAgreementConstants {
/** /**
* The connection timeout in milliseconds. * The connection timeout in milliseconds.
*/ */
long CONNECTION_TIMEOUT = 20 * 1000; long CONNECTION_TIMEOUT = 60_000;
/** /**
* The transport identifier for Bluetooth. * The transport identifier for Bluetooth.

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.keyagreement;
import java.io.IOException;
/**
* Thrown when a QR code that has been scanned uses a protocol version that is
* not supported.
*/
public class UnsupportedVersionException extends IOException {
private final boolean tooOld;
public UnsupportedVersionException(boolean tooOld) {
this.tooOld = tooOld;
}
public boolean isTooOld() {
return tooOld;
}
}

View File

@@ -34,7 +34,8 @@ public interface LifecycleManager {
*/ */
enum LifecycleState { enum LifecycleState {
STARTING, MIGRATING_DATABASE, STARTING_SERVICES, RUNNING, STOPPING; STARTING, MIGRATING_DATABASE, COMPACTING_DATABASE, STARTING_SERVICES,
RUNNING, STOPPING;
public boolean isAfter(LifecycleState state) { public boolean isAfter(LifecycleState state) {
return ordinal() > state.ordinal(); return ordinal() > state.ordinal();

View File

@@ -4,7 +4,8 @@ public interface TorConstants {
TransportId ID = new TransportId("org.briarproject.bramble.tor"); TransportId ID = new TransportId("org.briarproject.bramble.tor");
String PROP_ONION = "onion"; String PROP_ONION_V2 = "onion";
String PROP_ONION_V3 = "onion3";
int SOCKS_PORT = 59050; int SOCKS_PORT = 59050;
int CONTROL_PORT = 59051; int CONTROL_PORT = 59051;
@@ -12,12 +13,13 @@ public interface TorConstants {
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
String PREF_TOR_NETWORK = "network"; String PREF_TOR_NETWORK = "network2";
String PREF_TOR_PORT = "port"; String PREF_TOR_PORT = "port";
String PREF_TOR_DISABLE_BLOCKED = "disableWhenBlocked"; String PREF_TOR_MOBILE = "useMobileData";
int PREF_TOR_NETWORK_NEVER = 0; int PREF_TOR_NETWORK_AUTOMATIC = 0;
int PREF_TOR_NETWORK_WIFI = 1; int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
int PREF_TOR_NETWORK_ALWAYS = 2; int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
int PREF_TOR_NETWORK_NEVER = 3;
} }

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.api.sync; package org.briarproject.bramble.api.sync;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
public class Message { public class Message {
@@ -13,17 +13,16 @@ public class Message {
private final MessageId id; private final MessageId id;
private final GroupId groupId; private final GroupId groupId;
private final long timestamp; private final long timestamp;
private final byte[] raw; private final byte[] body;
public Message(MessageId id, GroupId groupId, long timestamp, byte[] raw) { public Message(MessageId id, GroupId groupId, long timestamp, byte[] body) {
if (raw.length <= MESSAGE_HEADER_LENGTH) if (body.length == 0) throw new IllegalArgumentException();
throw new IllegalArgumentException(); if (body.length > MAX_MESSAGE_BODY_LENGTH)
if (raw.length > MAX_MESSAGE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.id = id; this.id = id;
this.groupId = groupId; this.groupId = groupId;
this.timestamp = timestamp; this.timestamp = timestamp;
this.raw = raw; this.body = body;
} }
/** /**
@@ -50,15 +49,15 @@ public class Message {
/** /**
* Returns the length of the raw message in bytes. * Returns the length of the raw message in bytes.
*/ */
public int getLength() { public int getRawLength() {
return raw.length; return MESSAGE_HEADER_LENGTH + body.length;
} }
/** /**
* Returns the raw message. * Returns the message body.
*/ */
public byte[] getRaw() { public byte[] getBody() {
return raw; return body;
} }
@Override @Override

View File

@@ -9,5 +9,5 @@ public interface MessageFactory {
Message createMessage(byte[] raw); Message createMessage(byte[] raw);
Message createMessage(MessageId m, byte[] raw); byte[] getRawMessage(Message m);
} }

View File

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

View File

@@ -7,5 +7,5 @@ import java.io.InputStream;
@NotNullByDefault @NotNullByDefault
public interface ResourceProvider { public interface ResourceProvider {
InputStream getResourceInputStream(String name); InputStream getResourceInputStream(String name, String extension);
} }

View File

@@ -0,0 +1,23 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.system.Clock;
public class ArrayClock implements Clock {
private final long[] times;
private int index = 0;
public ArrayClock(long... times) {
this.times = times;
}
@Override
public long currentTimeMillis() {
return times[index++];
}
@Override
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}

View File

@@ -0,0 +1,24 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.system.Clock;
import java.util.concurrent.atomic.AtomicLong;
public class SettableClock implements Clock {
private final AtomicLong time;
public SettableClock(AtomicLong time) {
this.time = time;
}
@Override
public long currentTimeMillis() {
return time.get();
}
@Override
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}

View File

@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION; import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -32,7 +33,6 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH; import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
public class TestUtils { public class TestUtils {
@@ -40,6 +40,7 @@ public class TestUtils {
private static final AtomicInteger nextTestDir = private static final AtomicInteger nextTestDir =
new AtomicInteger((int) (Math.random() * 1000 * 1000)); new AtomicInteger((int) (Math.random() * 1000 * 1000));
private static final Random random = new Random(); private static final Random random = new Random();
private static final long timestamp = System.currentTimeMillis();
public static File getTestDirectory() { public static File getTestDirectory() {
int name = nextTestDir.getAndIncrement(); int name = nextTestDir.getAndIncrement();
@@ -101,9 +102,8 @@ public class TestUtils {
String name = getRandomString(nameLength); String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
long created = System.currentTimeMillis();
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey, return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey,
created); timestamp);
} }
public static Author getAuthor() { public static Author getAuthor() {
@@ -131,14 +131,13 @@ public class TestUtils {
public static Message getMessage(GroupId groupId) { public static Message getMessage(GroupId groupId) {
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH); int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
return getMessage(groupId, MESSAGE_HEADER_LENGTH + bodyLength); return getMessage(groupId, bodyLength);
} }
public static Message getMessage(GroupId groupId, int rawLength) { public static Message getMessage(GroupId groupId, int bodyLength) {
MessageId id = new MessageId(getRandomId()); MessageId id = new MessageId(getRandomId());
byte[] raw = getRandomBytes(rawLength); byte[] body = getRandomBytes(bodyLength);
long timestamp = System.currentTimeMillis(); return new Message(id, groupId, timestamp, body);
return new Message(id, groupId, timestamp, raw);
} }
public static double getMedian(Collection<? extends Number> samples) { public static double getMedian(Collection<? extends Number> samples) {
@@ -174,4 +173,10 @@ public class TestUtils {
Collection<? extends Number> samples) { Collection<? extends Number> samples) {
return Math.sqrt(getVariance(samples)); return Math.sqrt(getVariance(samples));
} }
public static boolean isOptionalTestEnabled(Class testClass) {
String optionalTests = System.getenv("OPTIONAL_TESTS");
return optionalTests != null &&
asList(optionalTests.split(",")).contains(testClass.getName());
}
} }

View File

@@ -14,7 +14,7 @@ dependencies {
implementation 'com.h2database:h2:1.4.192' // The last version that supports Java 1.6 implementation 'com.h2database:h2:1.4.192' // The last version that supports Java 1.6
implementation 'org.bitlet:weupnp:0.1.4' implementation 'org.bitlet:weupnp:0.1.4'
implementation 'net.i2p.crypto:eddsa:0.2.0' implementation 'net.i2p.crypto:eddsa:0.2.0'
implementation 'org.whispersystems:curve25519-java:0.4.1' implementation 'org.whispersystems:curve25519-java:0.5.0'
implementation 'org.briarproject:jtorctl:0.3' implementation 'org.briarproject:jtorctl:0.3'
apt 'com.google.dagger:dagger-compiler:2.0.2' apt 'com.google.dagger:dagger-compiler:2.0.2'
@@ -33,7 +33,7 @@ dependencies {
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }
// needed to make test output available to bramble-j2se // needed to make test output available to bramble-java
configurations { configurations {
testOutput.extendsFrom(testCompile) testOutput.extendsFrom(testCompile)
} }

View File

@@ -159,6 +159,8 @@ class AccountManagerImpl implements AccountManager {
@Override @Override
public boolean createAccount(String name, String password) { public boolean createAccount(String name, String password) {
synchronized (stateChangeLock) { synchronized (stateChangeLock) {
if (hasDatabaseKey())
throw new AssertionError("Already have a database key");
LocalAuthor localAuthor = identityManager.createLocalAuthor(name); LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
identityManager.registerLocalAuthor(localAuthor); identityManager.registerLocalAuthor(localAuthor);
SecretKey key = crypto.generateSecretKey(); SecretKey key = crypto.generateSecretKey();
@@ -181,6 +183,7 @@ class AccountManagerImpl implements AccountManager {
LOG.info("Deleting account"); LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
databaseKey = null;
} }
} }

View File

@@ -41,7 +41,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.bramble.util.ValidationUtils.checkSize;
@@ -127,9 +126,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Message getMessage(Transaction txn, MessageId m) throws DbException { public Message getMessage(Transaction txn, MessageId m) throws DbException {
byte[] raw = db.getRawMessage(txn, m); return db.getMessage(txn, m);
if (raw == null) return null;
return messageFactory.createMessage(m, raw);
} }
@Override @Override
@@ -149,10 +146,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(Transaction txn, MessageId m) public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
byte[] raw = db.getRawMessage(txn, m); return toList(db.getMessage(txn, m).getBody());
if (raw == null) return null;
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
} }
@Override @Override
@@ -364,9 +358,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList toList(Message m) throws FormatException { public BdfList toList(Message m) throws FormatException {
byte[] raw = m.getRaw(); return toList(m.getBody());
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
} }
@Override @Override

View File

@@ -10,6 +10,9 @@ import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
@@ -18,21 +21,32 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
class ContactManagerImpl implements ContactManager { class ContactManagerImpl implements ContactManager {
private final DatabaseComponent db; private final DatabaseComponent db;
private final KeyManager keyManager; private final KeyManager keyManager;
private final IdentityManager identityManager;
private final List<ContactHook> hooks; private final List<ContactHook> hooks;
@Inject @Inject
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager) { ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
IdentityManager identityManager) {
this.db = db; this.db = db;
this.keyManager = keyManager; this.keyManager = keyManager;
this.identityManager = identityManager;
hooks = new CopyOnWriteArrayList<>(); hooks = new CopyOnWriteArrayList<>();
} }
@@ -148,6 +162,17 @@ class ContactManagerImpl implements ContactManager {
db.setContactActive(txn, c, active); db.setContactActive(txn, c, active);
} }
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
db.transaction(false, txn -> db.setContactAlias(txn, c, alias));
}
@Override @Override
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId, public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException { AuthorId localAuthorId) throws DbException {
@@ -176,4 +201,23 @@ class ContactManagerImpl implements ContactManager {
db.removeContact(txn, c); db.removeContact(txn, c);
} }
@Override
public AuthorInfo getAuthorInfo(AuthorId a) throws DbException {
return db.transactionWithResult(true, txn -> getAuthorInfo(txn, a));
}
@Override
public AuthorInfo getAuthorInfo(Transaction txn, AuthorId authorId)
throws DbException {
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
if (localAuthor.getId().equals(authorId))
return new AuthorInfo(OURSELVES);
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
if (contacts.size() > 1) throw new AssertionError();
Contact c = contacts.iterator().next();
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
else return new AuthorInfo(UNVERIFIED, c.getAlias());
}
} }

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -297,6 +298,15 @@ interface Database<T> {
*/ */
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException; Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(T txn, MessageId m) throws DbException;
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state * For missing dependencies and dependencies in other groups, the state
@@ -411,7 +421,7 @@ interface Database<T> {
* Read-only. * Read-only.
*/ */
Collection<MessageId> getMessagesToOffer(T txn, ContactId c, Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
int maxMessages) throws DbException; int maxMessages, int maxLatency) throws DbException;
/** /**
* Returns the IDs of some messages that are eligible to be requested from * Returns the IDs of some messages that are eligible to be requested from
@@ -428,8 +438,8 @@ interface Database<T> {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength) Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
throws DbException; int maxLatency) throws DbException;
/** /**
* Returns the IDs of any messages that need to be validated. * Returns the IDs of any messages that need to be validated.
@@ -464,15 +474,6 @@ interface Database<T> {
*/ */
long getNextSendTime(T txn, ContactId c) throws DbException; long getNextSendTime(T txn, ContactId c) throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(T txn, MessageId m) throws DbException;
/** /**
* Returns the IDs of some messages that are eligible to be sent to the * Returns the IDs of some messages that are eligible to be sent to the
* given contact and have been requested by the contact, up to the given * given contact and have been requested by the contact, up to the given
@@ -481,7 +482,7 @@ interface Database<T> {
* Read-only. * Read-only.
*/ */
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c, Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
int maxLength) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
* Returns all settings in the given namespace. * Returns all settings in the given namespace.
@@ -615,6 +616,12 @@ interface Database<T> {
void setContactActive(T txn, ContactId c, boolean active) void setContactActive(T txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for a contact.
*/
void setContactAlias(T txn, ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Sets the given group's visibility to the given contact to either * Sets the given group's visibility to the given contact to either
* {@link Visibility VISIBLE} or {@link Visibility SHARED}. * {@link Visibility VISIBLE} or {@link Visibility SHARED}.
@@ -646,11 +653,11 @@ interface Database<T> {
throws DbException; throws DbException;
/** /**
* Updates the transmission count and expiry time of the given message * Updates the transmission count, expiry time and estimated time of arrival
* with respect to the given contact, using the latency of the transport * of the given message with respect to the given contact, using the latency
* over which it was sent. * of the transport over which it was sent.
*/ */
void updateExpiryTime(T txn, ContactId c, MessageId m, int maxLatency) void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
throws DbException; throws DbException;
/** /**

View File

@@ -9,7 +9,9 @@ import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException; import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
@@ -166,6 +168,31 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
for (Event e : transaction.getEvents()) eventBus.broadcast(e); for (Event e : transaction.getEvents()) eventBus.broadcast(e);
} }
@Override
public <E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
task.run(txn);
commitTransaction(txn);
} finally {
endTransaction(txn);
}
}
@Override
public <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
R result = task.call(txn);
commitTransaction(txn);
return result;
} finally {
endTransaction(txn);
}
}
private T unbox(Transaction transaction) { private T unbox(Transaction transaction) {
if (transaction.isCommitted()) throw new IllegalStateException(); if (transaction.isCommitted()) throw new IllegalStateException();
return txnClass.cast(transaction.unbox()); return txnClass.cast(transaction.unbox());
@@ -307,17 +334,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable @Nullable
@Override @Override
public Collection<byte[]> generateBatch(Transaction transaction, public Collection<Message> generateBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException { ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToSend(txn, c, maxLength); Collection<MessageId> ids =
List<byte[]> messages = new ArrayList<>(ids.size()); db.getMessagesToSend(txn, c, maxLength, maxLatency);
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) { for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m)); messages.add(db.getMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency); db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
} }
if (ids.isEmpty()) return null; if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids); db.lowerRequestedFlag(txn, c, ids);
@@ -333,9 +361,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToOffer(txn, c, maxMessages); Collection<MessageId> ids =
db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
if (ids.isEmpty()) return null; if (ids.isEmpty()) return null;
for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency); for (MessageId m : ids)
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
return new Offer(ids); return new Offer(ids);
} }
@@ -356,18 +386,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable @Nullable
@Override @Override
public Collection<byte[]> generateRequestedBatch(Transaction transaction, public Collection<Message> generateRequestedBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException { ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids = db.getRequestedMessagesToSend(txn, c, Collection<MessageId> ids =
maxLength); db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
List<byte[]> messages = new ArrayList<>(ids.size()); List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) { for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m)); messages.add(db.getMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency); db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
} }
if (ids.isEmpty()) return null; if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids); db.lowerRequestedFlag(txn, c, ids);
@@ -457,6 +487,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getLocalAuthors(txn); return db.getLocalAuthors(txn);
} }
@Override
public Message getMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getMessage(txn, m);
}
@Override @Override
public Collection<MessageId> getMessageIds(Transaction transaction, public Collection<MessageId> getMessageIds(Transaction transaction,
GroupId g) throws DbException { GroupId g) throws DbException {
@@ -487,16 +526,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getMessagesToShare(txn); return db.getMessagesToShare(txn);
} }
@Nullable
@Override
public byte[] getRawMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getRawMessage(txn, m);
}
@Override @Override
public Map<MessageId, Metadata> getMessageMetadata(Transaction transaction, public Map<MessageId, Metadata> getMessageMetadata(Transaction transaction,
GroupId g) throws DbException { GroupId g) throws DbException {
@@ -656,7 +685,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
merged.putAll(s); merged.putAll(s);
if (!merged.equals(old)) { if (!merged.equals(old)) {
db.mergeSettings(txn, s, namespace); db.mergeSettings(txn, s, namespace);
transaction.attach(new SettingsUpdatedEvent(namespace)); transaction.attach(new SettingsUpdatedEvent(namespace, merged));
} }
} }
@@ -830,6 +859,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
transaction.attach(new ContactStatusChangedEvent(c, active)); transaction.attach(new ContactStatusChangedEvent(c, active));
} }
@Override
public void setContactAlias(Transaction transaction, ContactId c,
String alias) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
db.setContactAlias(txn, c, alias);
}
@Override @Override
public void setGroupVisibility(Transaction transaction, ContactId c, public void setGroupVisibility(Transaction transaction, ContactId c,
GroupId g, Visibility v) throws DbException { GroupId g, Visibility v) throws DbException {
@@ -856,7 +895,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
if (db.getMessageState(txn, m) != DELIVERED) if (db.getMessageState(txn, m) != DELIVERED)
throw new IllegalArgumentException("Shared undelivered message"); throw new IllegalArgumentException(
"Shared undelivered message");
db.setMessageShared(txn, m); db.setMessageShared(txn, m);
transaction.attach(new MessageSharedEvent(m)); transaction.attach(new MessageSharedEvent(m));
} }
@@ -882,7 +922,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throw new NoSuchMessageException(); throw new NoSuchMessageException();
State dependentState = db.getMessageState(txn, dependent.getId()); State dependentState = db.getMessageState(txn, dependent.getId());
for (MessageId dependency : dependencies) { for (MessageId dependency : dependencies) {
db.addMessageDependency(txn, dependent, dependency, dependentState); db.addMessageDependency(txn, dependent, dependency,
dependentState);
} }
} }
@@ -914,7 +955,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction); T txn = unbox(transaction);
for (KeySet ks : keys) { for (KeySet ks : keys) {
TransportId t = ks.getTransportKeys().getTransportId(); TransportId t = ks.getTransportKeys().getTransportId();
if (db.containsTransport(txn, t)) db.updateTransportKeys(txn, ks); if (db.containsTransport(txn, t))
db.updateTransportKeys(txn, ks);
} }
} }
} }

View File

@@ -2,6 +2,8 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import static java.util.concurrent.TimeUnit.DAYS;
interface DatabaseConstants { interface DatabaseConstants {
/** /**
@@ -23,4 +25,16 @@ interface DatabaseConstants {
*/ */
String SCHEMA_VERSION_KEY = "schemaVersion"; String SCHEMA_VERSION_KEY = "schemaVersion";
/**
* The {@link Settings} key under which the time of the last database
* compaction is stored.
*/
String LAST_COMPACTED_KEY = "lastCompacted";
/**
* The maximum time between database compactions in milliseconds. When the
* database is opened it will be compacted if more than this amount of time
* has passed since the last compaction.
*/
long MAX_COMPACTION_INTERVAL_MS = DAYS.toMillis(30);
} }

View File

@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.ShutdownManager; import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import java.sql.Connection; import java.sql.Connection;
@@ -18,8 +19,9 @@ public class DatabaseModule {
@Provides @Provides
@Singleton @Singleton
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) { Database<Connection> provideDatabase(DatabaseConfig config,
return new H2Database(config, clock); MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
} }
@Provides @Provides

View File

@@ -0,0 +1,34 @@
package org.briarproject.bramble.db;
class DatabaseTypes {
private final String hashType, secretType, binaryType;
private final String counterType, stringType;
public DatabaseTypes(String hashType, String secretType, String binaryType,
String counterType, String stringType) {
this.hashType = hashType;
this.secretType = secretType;
this.binaryType = binaryType;
this.counterType = counterType;
this.stringType = stringType;
}
/**
* Replaces database type placeholders in a statement with the actual types.
* These placeholders are currently supported:
* <li> _HASH
* <li> _SECRET
* <li> _BINARY
* <li> _COUNTER
* <li> _STRING
*/
String replaceTypes(String s) {
s = s.replaceAll("_HASH", hashType);
s = s.replaceAll("_SECRET", secretType);
s = s.replaceAll("_BINARY", binaryType);
s = s.replaceAll("_COUNTER", counterType);
s = s.replaceAll("_STRING", stringType);
return s;
}
}

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -12,6 +13,7 @@ import java.io.File;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -28,6 +30,8 @@ class H2Database extends JdbcDatabase {
private static final String BINARY_TYPE = "BINARY"; private static final String BINARY_TYPE = "BINARY";
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT"; private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
private static final String STRING_TYPE = "VARCHAR"; private static final String STRING_TYPE = "VARCHAR";
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
private final DatabaseConfig config; private final DatabaseConfig config;
private final String url; private final String url;
@@ -36,9 +40,9 @@ class H2Database extends JdbcDatabase {
private volatile SecretKey key = null; private volatile SecretKey key = null;
@Inject @Inject
H2Database(DatabaseConfig config, Clock clock) { H2Database(DatabaseConfig config, MessageFactory messageFactory,
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, Clock clock) {
clock); super(dbTypes, messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();
@@ -104,4 +108,22 @@ class H2Database extends JdbcDatabase {
String getUrl() { String getUrl() {
return url; return url;
} }
@Override
protected void compactAndClose() throws DbException {
Connection c = null;
Statement s = null;
try {
c = createConnection();
closeAllConnections();
s = c.createStatement();
s.execute("SHUTDOWN COMPACT");
s.close();
c.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(c);
throw new DbException(e);
}
}
} }

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -29,6 +30,8 @@ class HyperSqlDatabase extends JdbcDatabase {
private static final String COUNTER_TYPE = private static final String COUNTER_TYPE =
"INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)"; "INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)";
private static final String STRING_TYPE = "VARCHAR"; private static final String STRING_TYPE = "VARCHAR";
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
private final DatabaseConfig config; private final DatabaseConfig config;
private final String url; private final String url;
@@ -37,9 +40,9 @@ class HyperSqlDatabase extends JdbcDatabase {
private volatile SecretKey key = null; private volatile SecretKey key = null;
@Inject @Inject
HyperSqlDatabase(DatabaseConfig config, Clock clock) { HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, Clock clock) {
clock); super(dbTypes, messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();
@@ -59,20 +62,24 @@ class HyperSqlDatabase extends JdbcDatabase {
@Override @Override
public void close() throws DbException { public void close() throws DbException {
Connection c = null;
Statement s = null;
try { try {
super.closeAllConnections(); super.closeAllConnections();
Connection c = createConnection(); c = createConnection();
Statement s = c.createStatement(); s = c.createStatement();
s.executeQuery("SHUTDOWN"); s.executeQuery("SHUTDOWN");
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s);
tryToClose(c);
throw new DbException(e); throw new DbException(e);
} }
} }
@Override @Override
public long getFreeSpace() throws DbException { public long getFreeSpace() {
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
long maxSize = config.getMaxSize(); long maxSize = config.getMaxSize();
long free = dir.getFreeSpace(); long free = dir.getFreeSpace();
@@ -102,4 +109,22 @@ class HyperSqlDatabase extends JdbcDatabase {
String hex = StringUtils.toHexString(key.getBytes()); String hex = StringUtils.toHexString(key.getBytes());
return DriverManager.getConnection(url + ";crypt_key=" + hex); return DriverManager.getConnection(url + ";crypt_key=" + hex);
} }
@Override
protected void compactAndClose() throws DbException {
Connection c = null;
Statement s = null;
try {
super.closeAllConnections();
c = createConnection();
s = c.createStatement();
s.executeQuery("SHUTDOWN COMPACT");
s.close();
c.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(c);
throw new DbException(e);
}
}
} }

View File

@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbClosedException; import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -20,6 +21,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State; import org.briarproject.bramble.api.sync.ValidationManager.State;
@@ -36,6 +38,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -53,20 +56,25 @@ import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.sql.Types.INTEGER; import static java.sql.Types.INTEGER;
import static java.util.Collections.singletonList; import static java.sql.Types.VARCHAR;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.db.Metadata.REMOVE; import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING; import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN; import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE; import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
import static org.briarproject.bramble.db.DatabaseConstants.LAST_COMPACTED_KEY;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_COMPACTION_INTERVAL_MS;
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY; import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry; import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
/** /**
* A generic database implementation that can be used with any JDBC-compatible * A generic database implementation that can be used with any JDBC-compatible
@@ -76,7 +84,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
abstract class JdbcDatabase implements Database<Connection> { abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing // Package access for testing
static final int CODE_SCHEMA_VERSION = 39; static final int CODE_SCHEMA_VERSION = 41;
// Rotation period offsets for incoming transport keys // Rotation period offsets for incoming transport keys
private static final int OFFSET_PREV = -1; private static final int OFFSET_PREV = -1;
@@ -106,6 +114,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " authorId _HASH NOT NULL," + " authorId _HASH NOT NULL,"
+ " formatVersion INT NOT NULL," + " formatVersion INT NOT NULL,"
+ " name _STRING NOT NULL," + " name _STRING NOT NULL,"
+ " alias _STRING," // Null if no alias exists
+ " publicKey _BINARY NOT NULL," + " publicKey _BINARY NOT NULL,"
+ " localAuthorId _HASH NOT NULL," + " localAuthorId _HASH NOT NULL,"
+ " verified BOOLEAN NOT NULL," + " verified BOOLEAN NOT NULL,"
@@ -216,6 +225,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " requested BOOLEAN NOT NULL," + " requested BOOLEAN NOT NULL,"
+ " expiry BIGINT NOT NULL," + " expiry BIGINT NOT NULL,"
+ " txCount INT NOT NULL," + " txCount INT NOT NULL,"
+ " eta BIGINT NOT NULL,"
+ " PRIMARY KEY (messageId, contactId)," + " PRIMARY KEY (messageId, contactId),"
+ " FOREIGN KEY (messageId)" + " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)" + " REFERENCES messages (messageId)"
@@ -302,9 +312,9 @@ abstract class JdbcDatabase implements Database<Connection> {
Logger.getLogger(JdbcDatabase.class.getName()); Logger.getLogger(JdbcDatabase.class.getName());
// Different database libraries use different names for certain types // Different database libraries use different names for certain types
private final String hashType, secretType, binaryType; private final MessageFactory messageFactory;
private final String counterType, stringType;
private final Clock clock; private final Clock clock;
private final DatabaseTypes dbTypes;
// Locking: connectionsLock // Locking: connectionsLock
private final LinkedList<Connection> connections = new LinkedList<>(); private final LinkedList<Connection> connections = new LinkedList<>();
@@ -312,19 +322,17 @@ abstract class JdbcDatabase implements Database<Connection> {
private int openConnections = 0; // Locking: connectionsLock private int openConnections = 0; // Locking: connectionsLock
private boolean closed = false; // Locking: connectionsLock private boolean closed = false; // Locking: connectionsLock
@Nullable
protected abstract Connection createConnection() throws SQLException; protected abstract Connection createConnection() throws SQLException;
protected abstract void compactAndClose() throws DbException;
private final Lock connectionsLock = new ReentrantLock(); private final Lock connectionsLock = new ReentrantLock();
private final Condition connectionsChanged = connectionsLock.newCondition(); private final Condition connectionsChanged = connectionsLock.newCondition();
JdbcDatabase(String hashType, String secretType, String binaryType, JdbcDatabase(DatabaseTypes databaseTypes, MessageFactory messageFactory,
String counterType, String stringType, Clock clock) { Clock clock) {
this.hashType = hashType; this.dbTypes = databaseTypes;
this.secretType = secretType; this.messageFactory = messageFactory;
this.binaryType = binaryType;
this.counterType = counterType;
this.stringType = stringType;
this.clock = clock; this.clock = clock;
} }
@@ -337,13 +345,16 @@ abstract class JdbcDatabase implements Database<Connection> {
throw new DbException(e); throw new DbException(e);
} }
// Open the database and create the tables and indexes if necessary // Open the database and create the tables and indexes if necessary
boolean compact;
Connection txn = startTransaction(); Connection txn = startTransaction();
try { try {
if (reopen) { if (reopen) {
checkSchemaVersion(txn, listener); Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
compact = migrateSchema(txn, s, listener) || isCompactionDue(s);
} else { } else {
createTables(txn); createTables(txn);
storeSchemaVersion(txn, CODE_SCHEMA_VERSION); initialiseSettings(txn);
compact = false;
} }
createIndexes(txn); createIndexes(txn);
commitTransaction(txn); commitTransaction(txn);
@@ -351,6 +362,25 @@ abstract class JdbcDatabase implements Database<Connection> {
abortTransaction(txn); abortTransaction(txn);
throw e; throw e;
} }
// Compact the database if necessary
if (compact) {
if (listener != null) listener.onDatabaseCompaction();
long start = now();
compactAndClose();
logDuration(LOG, "Compacting database", start);
// Allow the next transaction to reopen the DB
synchronized (connectionsLock) {
closed = false;
}
txn = startTransaction();
try {
storeLastCompacted(txn);
commitTransaction(txn);
} catch (DbException e) {
abortTransaction(txn);
throw e;
}
}
} }
/** /**
@@ -358,17 +388,18 @@ abstract class JdbcDatabase implements Database<Connection> {
* version used by the current code and applies any suitable migrations to * version used by the current code and applies any suitable migrations to
* the data if necessary. * the data if necessary.
* *
* @return true if any migrations were applied, false if the schema was
* already current
* @throws DataTooNewException if the data uses a newer schema than the * @throws DataTooNewException if the data uses a newer schema than the
* current code * current code
* @throws DataTooOldException if the data uses an older schema than the * @throws DataTooOldException if the data uses an older schema than the
* current code and cannot be migrated * current code and cannot be migrated
*/ */
private void checkSchemaVersion(Connection txn, private boolean migrateSchema(Connection txn, Settings s,
@Nullable MigrationListener listener) throws DbException { @Nullable MigrationListener listener) throws DbException {
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
int dataSchemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1); int dataSchemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
if (dataSchemaVersion == -1) throw new DbException(); if (dataSchemaVersion == -1) throw new DbException();
if (dataSchemaVersion == CODE_SCHEMA_VERSION) return; if (dataSchemaVersion == CODE_SCHEMA_VERSION) return false;
if (CODE_SCHEMA_VERSION < dataSchemaVersion) if (CODE_SCHEMA_VERSION < dataSchemaVersion)
throw new DataTooNewException(); throw new DataTooNewException();
// Apply any suitable migrations in order // Apply any suitable migrations in order
@@ -377,7 +408,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (start == dataSchemaVersion) { if (start == dataSchemaVersion) {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Migrating from schema " + start + " to " + end); LOG.info("Migrating from schema " + start + " to " + end);
if (listener != null) listener.onMigrationRun(); if (listener != null) listener.onDatabaseMigration();
// Apply the migration // Apply the migration
m.migrate(txn); m.migrate(txn);
// Store the new schema version // Store the new schema version
@@ -387,11 +418,24 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
if (dataSchemaVersion != CODE_SCHEMA_VERSION) if (dataSchemaVersion != CODE_SCHEMA_VERSION)
throw new DataTooOldException(); throw new DataTooOldException();
return true;
} }
// Package access for testing // Package access for testing
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {
return singletonList(new Migration38_39()); return Arrays.asList(
new Migration38_39(),
new Migration39_40(),
new Migration40_41(dbTypes)
);
}
private boolean isCompactionDue(Settings s) {
long lastCompacted = s.getLong(LAST_COMPACTED_KEY, 0);
long elapsed = clock.currentTimeMillis() - lastCompacted;
if (LOG.isLoggable(INFO))
LOG.info(elapsed + " ms since last compaction");
return elapsed > MAX_COMPACTION_INTERVAL_MS;
} }
private void storeSchemaVersion(Connection txn, int version) private void storeSchemaVersion(Connection txn, int version)
@@ -401,6 +445,19 @@ abstract class JdbcDatabase implements Database<Connection> {
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE); mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
} }
private void storeLastCompacted(Connection txn) throws DbException {
Settings s = new Settings();
s.putLong(LAST_COMPACTED_KEY, clock.currentTimeMillis());
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
}
private void initialiseSettings(Connection txn) throws DbException {
Settings s = new Settings();
s.putInt(SCHEMA_VERSION_KEY, CODE_SCHEMA_VERSION);
s.putLong(LAST_COMPACTED_KEY, clock.currentTimeMillis());
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
}
private void tryToClose(@Nullable ResultSet rs) { private void tryToClose(@Nullable ResultSet rs) {
try { try {
if (rs != null) rs.close(); if (rs != null) rs.close();
@@ -409,7 +466,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
private void tryToClose(@Nullable Statement s) { protected void tryToClose(@Nullable Statement s) {
try { try {
if (s != null) s.close(); if (s != null) s.close();
} catch (SQLException e) { } catch (SQLException e) {
@@ -417,24 +474,32 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
protected void tryToClose(@Nullable Connection c) {
try {
if (c != null) c.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
private void createTables(Connection txn) throws DbException { private void createTables(Connection txn) throws DbException {
Statement s = null; Statement s = null;
try { try {
s = txn.createStatement(); s = txn.createStatement();
s.executeUpdate(insertTypeNames(CREATE_SETTINGS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_SETTINGS));
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_LOCAL_AUTHORS));
s.executeUpdate(insertTypeNames(CREATE_CONTACTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_CONTACTS));
s.executeUpdate(insertTypeNames(CREATE_GROUPS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUPS));
s.executeUpdate(insertTypeNames(CREATE_GROUP_METADATA)); s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUP_METADATA));
s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUP_VISIBILITIES));
s.executeUpdate(insertTypeNames(CREATE_MESSAGES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGES));
s.executeUpdate(insertTypeNames(CREATE_MESSAGE_METADATA)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_METADATA));
s.executeUpdate(insertTypeNames(CREATE_MESSAGE_DEPENDENCIES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_DEPENDENCIES));
s.executeUpdate(insertTypeNames(CREATE_OFFERS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS));
s.executeUpdate(insertTypeNames(CREATE_STATUSES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS));
s.executeUpdate(insertTypeNames(CREATE_OUTGOING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_KEYS));
s.executeUpdate(insertTypeNames(CREATE_INCOMING_KEYS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS));
s.close(); s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s);
@@ -459,15 +524,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
private String insertTypeNames(String s) {
s = s.replaceAll("_HASH", hashType);
s = s.replaceAll("_SECRET", secretType);
s = s.replaceAll("_BINARY", binaryType);
s = s.replaceAll("_COUNTER", counterType);
s = s.replaceAll("_STRING", stringType);
return s;
}
@Override @Override
public Connection startTransaction() throws DbException { public Connection startTransaction() throws DbException {
Connection txn; Connection txn;
@@ -482,7 +538,6 @@ abstract class JdbcDatabase implements Database<Connection> {
if (txn == null) { if (txn == null) {
// Open a new connection // Open a new connection
txn = createConnection(); txn = createConnection();
if (txn == null) throw new DbException();
txn.setAutoCommit(false); txn.setAutoCommit(false);
connectionsLock.lock(); connectionsLock.lock();
try { try {
@@ -726,7 +781,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setLong(3, m.getTimestamp()); ps.setLong(3, m.getTimestamp());
ps.setInt(4, state.getValue()); ps.setInt(4, state.getValue());
ps.setBoolean(5, messageShared); ps.setBoolean(5, messageShared);
byte[] raw = m.getRaw(); byte[] raw = messageFactory.getRawMessage(m);
ps.setInt(6, raw.length); ps.setInt(6, raw.length);
ps.setBytes(7, raw); ps.setBytes(7, raw);
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
@@ -740,7 +795,7 @@ abstract class JdbcDatabase implements Database<Connection> {
boolean offered = removeOfferedMessage(txn, c, m.getId()); boolean offered = removeOfferedMessage(txn, c, m.getId());
boolean seen = offered || (sender != null && c.equals(sender)); boolean seen = offered || (sender != null && c.equals(sender));
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(), addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
m.getLength(), state, e.getValue(), messageShared, raw.length, state, e.getValue(), messageShared,
false, seen); false, seen);
} }
// Update denormalised column in messageDependencies if dependency // Update denormalised column in messageDependencies if dependency
@@ -799,8 +854,9 @@ abstract class JdbcDatabase implements Database<Connection> {
try { try {
String sql = "INSERT INTO statuses (messageId, contactId, groupId," String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
+ " timestamp, length, state, groupShared, messageShared," + " timestamp, length, state, groupShared, messageShared,"
+ " deleted, ack, seen, requested, expiry, txCount)" + " deleted, ack, seen, requested, expiry, txCount, eta)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0)"; + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0,"
+ " 0)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes()); ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt()); ps.setInt(2, c.getInt());
@@ -1193,8 +1249,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT authorId, formatVersion, name, publicKey," String sql = "SELECT authorId, formatVersion, name, alias,"
+ " localAuthorId, verified, active" + " publicKey, localAuthorId, verified, active"
+ " FROM contacts" + " FROM contacts"
+ " WHERE contactId = ?"; + " WHERE contactId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
@@ -1204,15 +1260,17 @@ abstract class JdbcDatabase implements Database<Connection> {
AuthorId authorId = new AuthorId(rs.getBytes(1)); AuthorId authorId = new AuthorId(rs.getBytes(1));
int formatVersion = rs.getInt(2); int formatVersion = rs.getInt(2);
String name = rs.getString(3); String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4); String alias = rs.getString(4);
AuthorId localAuthorId = new AuthorId(rs.getBytes(5)); byte[] publicKey = rs.getBytes(5);
boolean verified = rs.getBoolean(6); AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
boolean active = rs.getBoolean(7); boolean verified = rs.getBoolean(7);
boolean active = rs.getBoolean(8);
rs.close(); rs.close();
ps.close(); ps.close();
Author author = Author author =
new Author(authorId, formatVersion, name, publicKey); new Author(authorId, formatVersion, name, publicKey);
return new Contact(c, author, localAuthorId, verified, active); return new Contact(c, author, localAuthorId, alias, verified,
active);
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(rs); tryToClose(rs);
tryToClose(ps); tryToClose(ps);
@@ -1227,7 +1285,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT contactId, authorId, formatVersion, name," String sql = "SELECT contactId, authorId, formatVersion, name,"
+ " publicKey, localAuthorId, verified, active" + " alias, publicKey, localAuthorId, verified, active"
+ " FROM contacts"; + " FROM contacts";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
rs = ps.executeQuery(); rs = ps.executeQuery();
@@ -1237,14 +1295,15 @@ abstract class JdbcDatabase implements Database<Connection> {
AuthorId authorId = new AuthorId(rs.getBytes(2)); AuthorId authorId = new AuthorId(rs.getBytes(2));
int formatVersion = rs.getInt(3); int formatVersion = rs.getInt(3);
String name = rs.getString(4); String name = rs.getString(4);
byte[] publicKey = rs.getBytes(5); String alias = rs.getString(5);
byte[] publicKey = rs.getBytes(6);
Author author = Author author =
new Author(authorId, formatVersion, name, publicKey); new Author(authorId, formatVersion, name, publicKey);
AuthorId localAuthorId = new AuthorId(rs.getBytes(6)); AuthorId localAuthorId = new AuthorId(rs.getBytes(7));
boolean verified = rs.getBoolean(7); boolean verified = rs.getBoolean(8);
boolean active = rs.getBoolean(8); boolean active = rs.getBoolean(9);
contacts.add(new Contact(contactId, author, localAuthorId, contacts.add(new Contact(contactId, author, localAuthorId,
verified, active)); alias, verified, active));
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -1285,8 +1344,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT contactId, formatVersion, name, publicKey," String sql = "SELECT contactId, formatVersion, name, alias,"
+ " localAuthorId, verified, active" + " publicKey, localAuthorId, verified, active"
+ " FROM contacts" + " FROM contacts"
+ " WHERE authorId = ?"; + " WHERE authorId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
@@ -1297,14 +1356,15 @@ abstract class JdbcDatabase implements Database<Connection> {
ContactId c = new ContactId(rs.getInt(1)); ContactId c = new ContactId(rs.getInt(1));
int formatVersion = rs.getInt(2); int formatVersion = rs.getInt(2);
String name = rs.getString(3); String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4); String alias = rs.getString(4);
AuthorId localAuthorId = new AuthorId(rs.getBytes(5)); byte[] publicKey = rs.getBytes(5);
boolean verified = rs.getBoolean(6); AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
boolean active = rs.getBoolean(7); boolean verified = rs.getBoolean(7);
boolean active = rs.getBoolean(8);
Author author = Author author =
new Author(remote, formatVersion, name, publicKey); new Author(remote, formatVersion, name, publicKey);
contacts.add(new Contact(c, author, localAuthorId, verified, contacts.add(new Contact(c, author, localAuthorId, alias,
active)); verified, active));
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -1482,6 +1542,35 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public Message getMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT groupId, timestamp, raw FROM messages"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1));
long timestamp = rs.getLong(2);
byte[] raw = rs.getBytes(3);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (raw == null) throw new MessageDeletedException();
if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
return new Message(m, g, timestamp, body);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override @Override
public Collection<MessageId> getMessageIds(Connection txn, GroupId g) public Collection<MessageId> getMessageIds(Connection txn, GroupId g)
throws DbException { throws DbException {
@@ -1834,8 +1923,9 @@ abstract class JdbcDatabase implements Database<Connection> {
@Override @Override
public Collection<MessageId> getMessagesToOffer(Connection txn, public Collection<MessageId> getMessagesToOffer(Connection txn,
ContactId c, int maxMessages) throws DbException { ContactId c, int maxMessages, int maxLatency) throws DbException {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@@ -1844,13 +1934,14 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE" + " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE" + " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = FALSE" + " AND seen = FALSE AND requested = FALSE"
+ " AND expiry < ?" + " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp LIMIT ?"; + " ORDER BY timestamp LIMIT ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue()); ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now); ps.setLong(3, now);
ps.setInt(4, maxMessages); ps.setLong(4, eta);
ps.setInt(5, maxMessages);
rs = ps.executeQuery(); rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>(); List<MessageId> ids = new ArrayList<>();
while (rs.next()) ids.add(new MessageId(rs.getBytes(1))); while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
@@ -1891,8 +1982,9 @@ abstract class JdbcDatabase implements Database<Connection> {
@Override @Override
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c, public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
int maxLength) throws DbException { int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@@ -1901,12 +1993,13 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE" + " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE" + " AND deleted = FALSE"
+ " AND seen = FALSE" + " AND seen = FALSE"
+ " AND expiry < ?" + " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp"; + " ORDER BY timestamp";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue()); ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now); ps.setLong(3, now);
ps.setLong(4, eta);
rs = ps.executeQuery(); rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>(); List<MessageId> ids = new ArrayList<>();
int total = 0; int total = 0;
@@ -2018,34 +2111,11 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
@Nullable
public byte[] getRawMessage(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT raw FROM messages WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] raw = rs.getBytes(1);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return raw;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override @Override
public Collection<MessageId> getRequestedMessagesToSend(Connection txn, public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
ContactId c, int maxLength) throws DbException { ContactId c, int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@@ -2054,12 +2124,13 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE" + " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE" + " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = TRUE" + " AND seen = FALSE AND requested = TRUE"
+ " AND expiry < ?" + " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp"; + " ORDER BY timestamp";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue()); ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now); ps.setLong(3, now);
ps.setLong(4, eta);
rs = ps.executeQuery(); rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>(); List<MessageId> ids = new ArrayList<>();
int total = 0; int total = 0;
@@ -2718,6 +2789,25 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public void setContactAlias(Connection txn, ContactId c,
@Nullable String alias) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE contacts SET alias = ? WHERE contactId = ?";
ps = txn.prepareStatement(sql);
if (alias == null) ps.setNull(1, VARCHAR);
else ps.setString(1, alias);
ps.setInt(2, c.getInt());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
@Override @Override
public void setGroupVisibility(Connection txn, ContactId c, GroupId g, public void setGroupVisibility(Connection txn, ContactId c, GroupId g,
boolean shared) throws DbException { boolean shared) throws DbException {
@@ -2870,7 +2960,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public void updateExpiryTime(Connection txn, ContactId c, MessageId m, public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m,
int maxLatency) throws DbException { int maxLatency) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@@ -2886,13 +2976,16 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rs.next()) throw new DbStateException(); if (rs.next()) throw new DbStateException();
rs.close(); rs.close();
ps.close(); ps.close();
sql = "UPDATE statuses SET expiry = ?, txCount = txCount + 1" sql = "UPDATE statuses"
+ " SET expiry = ?, txCount = txCount + 1, eta = ?"
+ " WHERE messageId = ? AND contactId = ?"; + " WHERE messageId = ? AND contactId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long eta = now + maxLatency;
ps.setLong(1, calculateExpiry(now, maxLatency, txCount)); ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
ps.setBytes(2, m.getBytes()); ps.setLong(2, eta);
ps.setInt(3, c.getInt()); ps.setBytes(3, m.getBytes());
ps.setInt(4, c.getInt());
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
class Migration39_40 implements Migration<Connection> {
private static final Logger LOG =
Logger.getLogger(Migration39_40.class.getName());
@Override
public int getStartVersion() {
return 39;
}
@Override
public int getEndVersion() {
return 40;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE statuses"
+ " ADD eta BIGINT");
s.execute("UPDATE statuses SET eta = 0");
s.execute("ALTER TABLE statuses"
+ " ALTER COLUMN eta"
+ " SET NOT NULL");
} catch (SQLException e) {
tryToClose(s);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}

View File

@@ -0,0 +1,56 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
class Migration40_41 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration40_41.class.getName());
private final DatabaseTypes dbTypes;
public Migration40_41(DatabaseTypes databaseTypes) {
this.dbTypes = databaseTypes;
}
@Override
public int getStartVersion() {
return 40;
}
@Override
public int getEndVersion() {
return 41;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias VARCHAR"));
} catch (SQLException e) {
tryToClose(s);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}

View File

@@ -1,29 +1,21 @@
package org.briarproject.bramble.identity; package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.Author.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@@ -118,26 +110,4 @@ class IdentityManagerImpl implements IdentityManager {
return db.getLocalAuthors(txn).iterator().next(); return db.getLocalAuthors(txn).iterator().next();
} }
@Override
public Status getAuthorStatus(AuthorId authorId) throws DbException {
Transaction txn = db.startTransaction(true);
try {
return getAuthorStatus(txn, authorId);
} finally {
db.endTransaction(txn);
}
}
@Override
public Status getAuthorStatus(Transaction txn, AuthorId authorId)
throws DbException {
if (getLocalAuthor(txn).getId().equals(authorId)) return OURSELVES;
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
if (contacts.isEmpty()) return UNKNOWN;
for (Contact c : contacts) {
if (c.isVerified()) return VERIFIED;
}
return UNVERIFIED;
}
} }

View File

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

View File

@@ -1,13 +1,13 @@
package org.briarproject.bramble.keyagreement; package org.briarproject.bramble.keyagreement;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfReader; import org.briarproject.bramble.api.data.BdfReader;
import org.briarproject.bramble.api.data.BdfReaderFactory; import org.briarproject.bramble.api.data.BdfReaderFactory;
import org.briarproject.bramble.api.keyagreement.Payload; import org.briarproject.bramble.api.keyagreement.Payload;
import org.briarproject.bramble.api.keyagreement.PayloadParser; import org.briarproject.bramble.api.keyagreement.PayloadParser;
import org.briarproject.bramble.api.keyagreement.TransportDescriptor; import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
import org.briarproject.bramble.api.keyagreement.UnsupportedVersionException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants; import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.LanTcpConstants; import org.briarproject.bramble.api.plugin.LanTcpConstants;
@@ -21,6 +21,7 @@ import java.util.List;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.BETA_PROTOCOL_VERSION;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
@@ -43,8 +44,11 @@ class PayloadParserImpl implements PayloadParser {
// First byte: the protocol version // First byte: the protocol version
int protocolVersion = in.read(); int protocolVersion = in.read();
if (protocolVersion == -1) throw new FormatException(); if (protocolVersion == -1) throw new FormatException();
if (protocolVersion != PROTOCOL_VERSION) if (protocolVersion != PROTOCOL_VERSION) {
throw new UnsupportedVersionException(); boolean tooOld = protocolVersion < PROTOCOL_VERSION ||
protocolVersion == BETA_PROTOCOL_VERSION;
throw new UnsupportedVersionException(tooOld);
}
// The rest of the payload is a BDF list with one or more elements // The rest of the payload is a BDF list with one or more elements
BdfReader r = bdfReaderFactory.createReader(in); BdfReader r = bdfReaderFactory.createReader(in);
BdfList payload = r.readList(); BdfList payload = r.readList();

View File

@@ -29,6 +29,7 @@ import javax.inject.Inject;
import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
@@ -159,11 +160,17 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
} }
@Override @Override
public void onMigrationRun() { public void onDatabaseMigration() {
state = MIGRATING_DATABASE; state = MIGRATING_DATABASE;
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE)); eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
} }
@Override
public void onDatabaseCompaction() {
state = COMPACTING_DATABASE;
eventBus.broadcast(new LifecycleEvent(COMPACTING_DATABASE));
}
@Override @Override
public void stopServices() { public void stopServices() {
try { try {

View File

@@ -21,8 +21,8 @@ import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent; import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent; import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.util.StringUtils;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
@@ -45,6 +45,9 @@ 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.api.plugin.BluetoothConstants.UUID_BYTES;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
import static org.briarproject.bramble.util.StringUtils.macToBytes;
import static org.briarproject.bramble.util.StringUtils.macToString;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -95,6 +98,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
abstract DuplexTransportConnection connectTo(String address, String uuid) abstract DuplexTransportConnection connectTo(String address, String uuid)
throws IOException; throws IOException;
@Nullable
abstract DuplexTransportConnection discoverAndConnect(String uuid);
BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, SecureRandom secureRandom, Executor ioExecutor, SecureRandom secureRandom,
Backoff backoff, DuplexPluginCallback callback, int maxLatency) { Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
@@ -146,16 +152,15 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} }
updateProperties(); updateProperties();
running = true; running = true;
loadSettings(); loadSettings(callback.getSettings());
if (shouldAllowContactConnections()) { if (shouldAllowContactConnections()) {
if (isAdapterEnabled()) bind(); if (isAdapterEnabled()) bind();
else enableAdapter(); else enableAdapter();
} }
} }
private void loadSettings() { private void loadSettings(Settings settings) {
contactConnections = contactConnections = settings.getBoolean(PREF_BT_ENABLE, false);
callback.getSettings().getBoolean(PREF_BT_ENABLE, false);
} }
private boolean shouldAllowContactConnections() { private boolean shouldAllowContactConnections() {
@@ -193,7 +198,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
address = getBluetoothAddress(); address = getBluetoothAddress();
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Local address " + scrubMacAddress(address)); LOG.info("Local address " + scrubMacAddress(address));
if (!StringUtils.isNullOrEmpty(address)) { if (!isNullOrEmpty(address)) {
p.put(PROP_ADDRESS, address); p.put(PROP_ADDRESS, address);
changed = true; changed = true;
} }
@@ -256,9 +261,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
// Try to connect to known devices in parallel // Try to connect to known devices in parallel
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) { for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
String address = e.getValue().get(PROP_ADDRESS); String address = e.getValue().get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue; if (isNullOrEmpty(address)) continue;
String uuid = e.getValue().get(PROP_UUID); String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue; if (isNullOrEmpty(uuid)) continue;
ContactId c = e.getKey(); ContactId c = e.getKey();
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
if (!isRunning() || !shouldAllowContactConnections()) return; if (!isRunning() || !shouldAllowContactConnections()) return;
@@ -309,9 +314,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
if (!isRunning() || !shouldAllowContactConnections()) return null; if (!isRunning() || !shouldAllowContactConnections()) return null;
if (!connectionLimiter.canOpenContactConnection()) return null; if (!connectionLimiter.canOpenContactConnection()) return null;
String address = p.get(PROP_ADDRESS); String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null; if (isNullOrEmpty(address)) return null;
String uuid = p.get(PROP_UUID); String uuid = p.get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) return null; if (isNullOrEmpty(uuid)) return null;
DuplexTransportConnection conn = connect(address, uuid); DuplexTransportConnection conn = connect(address, uuid);
if (conn == null) return null; if (conn == null) return null;
// TODO: Why don't we reset the backoff here? // TODO: Why don't we reset the backoff here?
@@ -326,9 +331,6 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
@Override @Override
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
if (!isRunning()) return null; if (!isRunning()) return null;
// There's no point listening if we can't discover our own address
String address = getBluetoothAddress();
if (address == null) return null;
// No truncation necessary because COMMIT_LENGTH = 16 // No truncation necessary because COMMIT_LENGTH = 16
String uuid = UUID.nameUUIDFromBytes(commitment).toString(); String uuid = UUID.nameUUIDFromBytes(commitment).toString();
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
@@ -346,7 +348,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} }
BdfList descriptor = new BdfList(); BdfList descriptor = new BdfList();
descriptor.add(TRANSPORT_ID_BLUETOOTH); descriptor.add(TRANSPORT_ID_BLUETOOTH);
descriptor.add(StringUtils.macToBytes(address)); String address = getBluetoothAddress();
if (address != null) descriptor.add(macToBytes(address));
return new BluetoothKeyAgreementListener(descriptor, ss); return new BluetoothKeyAgreementListener(descriptor, ss);
} }
@@ -354,6 +357,14 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, BdfList descriptor) { byte[] commitment, BdfList descriptor) {
if (!isRunning()) return null; if (!isRunning()) return null;
// No truncation necessary because COMMIT_LENGTH = 16
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
DuplexTransportConnection conn;
if (descriptor.size() == 1) {
if (LOG.isLoggable(INFO))
LOG.info("Discovering address for key agreement UUID " + uuid);
conn = discoverAndConnect(uuid);
} else {
String address; String address;
try { try {
address = parseAddress(descriptor); address = parseAddress(descriptor);
@@ -361,11 +372,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
LOG.info("Invalid address in key agreement descriptor"); LOG.info("Invalid address in key agreement descriptor");
return null; return null;
} }
// No truncation necessary because COMMIT_LENGTH = 16
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to key agreement UUID " + uuid); LOG.info("Connecting to key agreement UUID " + uuid);
DuplexTransportConnection conn = connect(address, uuid); conn = connect(address, uuid);
}
if (conn != null) connectionLimiter.keyAgreementConnectionOpened(conn); if (conn != null) connectionLimiter.keyAgreementConnectionOpened(conn);
return conn; return conn;
} }
@@ -373,7 +383,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private String parseAddress(BdfList descriptor) throws FormatException { private String parseAddress(BdfList descriptor) throws FormatException {
byte[] mac = descriptor.getRaw(1); byte[] mac = descriptor.getRaw(1);
if (mac.length != 6) throw new FormatException(); if (mac.length != 6) throw new FormatException();
return StringUtils.macToString(mac); return macToString(mac);
} }
@Override @Override
@@ -387,7 +397,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} else if (e instanceof SettingsUpdatedEvent) { } else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e; SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) if (s.getNamespace().equals(ID.getString()))
ioExecutor.execute(this::onSettingsUpdated); ioExecutor.execute(() -> onSettingsUpdated(s.getSettings()));
} else if (e instanceof KeyAgreementListeningEvent) { } else if (e instanceof KeyAgreementListeningEvent) {
ioExecutor.execute(connectionLimiter::keyAgreementStarted); ioExecutor.execute(connectionLimiter::keyAgreementStarted);
} else if (e instanceof KeyAgreementStoppedListeningEvent) { } else if (e instanceof KeyAgreementStoppedListeningEvent) {
@@ -395,9 +405,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} }
} }
private void onSettingsUpdated() { private void onSettingsUpdated(Settings settings) {
boolean wasAllowed = shouldAllowContactConnections(); boolean wasAllowed = shouldAllowContactConnections();
loadSettings(); loadSettings(settings);
boolean isAllowed = shouldAllowContactConnections(); boolean isAllowed = shouldAllowContactConnections();
if (wasAllowed && !isAllowed) { if (wasAllowed && !isAllowed) {
LOG.info("Contact connections disabled"); LOG.info("Contact connections disabled");

View File

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

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.plugin.tor; package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.ResourceProvider;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@@ -24,14 +23,11 @@ class CircumventionProviderImpl implements CircumventionProvider {
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES = private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(asList(BRIDGES)); new HashSet<>(asList(BRIDGES));
private final ResourceProvider resourceProvider;
@Nullable @Nullable
private volatile List<String> bridges = null; private volatile List<String> bridges = null;
@Inject @Inject
CircumventionProviderImpl(ResourceProvider resourceProvider) { CircumventionProviderImpl() {
this.resourceProvider = resourceProvider;
} }
@Override @Override
@@ -50,8 +46,8 @@ class CircumventionProviderImpl implements CircumventionProvider {
List<String> bridges = this.bridges; List<String> bridges = this.bridges;
if (bridges != null) return new ArrayList<>(bridges); if (bridges != null) return new ArrayList<>(bridges);
InputStream is = InputStream is = getClass().getClassLoader()
resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME); .getResourceAsStream(BRIDGE_FILE_NAME);
Scanner scanner = new Scanner(is); Scanner scanner = new Scanner(is);
bridges = new ArrayList<>(); bridges = new ArrayList<>();

View File

@@ -28,7 +28,6 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.IoUtils; 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;
@@ -64,15 +63,17 @@ 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.bramble.api.plugin.TorConstants.CONTROL_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.ID; import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WITH_BRIDGES;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion; import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -87,7 +88,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final String OWNER = "__OwningControllerProcess"; private static final String OWNER = "__OwningControllerProcess";
private static final int COOKIE_TIMEOUT_MS = 3000; private static final int COOKIE_TIMEOUT_MS = 3000;
private static final int COOKIE_POLLING_INTERVAL_MS = 200; private static final int COOKIE_POLLING_INTERVAL_MS = 200;
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}"); private static final Pattern ONION_V2 = Pattern.compile("[a-z2-7]{16}");
private static final Pattern ONION_V3 = Pattern.compile("[a-z2-7]{56}");
private final Executor ioExecutor, connectionStatusExecutor; private final Executor ioExecutor, connectionStatusExecutor;
private final NetworkManager networkManager; private final NetworkManager networkManager;
@@ -108,6 +110,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private volatile ServerSocket socket = null; private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null; private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null; private volatile TorControlConnection controlConnection = null;
private volatile Settings settings = null;
protected volatile boolean running = false; protected volatile boolean running = false;
@@ -166,10 +169,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public void start() throws PluginException { public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
if (!torDirectory.exists()) {
if (!torDirectory.mkdirs()) {
LOG.warning("Could not create Tor directory.");
throw new PluginException();
}
}
// Load the settings
settings = callback.getSettings();
// Install or update the assets if necessary // Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets(); if (!assetsAreUpToDate()) installAssets();
if (cookieFile.exists() && !cookieFile.delete()) if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted"); LOG.warning("Old auth cookie not deleted");
// Migrate old settings before having a chance to stop
migrateSettings();
// Start a new Tor process // Start a new Tor process
LOG.info("Starting Tor"); LOG.info("Starting Tor");
String torPath = torFile.getAbsolutePath(); String torPath = torFile.getAbsolutePath();
@@ -286,22 +299,23 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
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);
InputStream in = InputStream in = resourceProvider
resourceProvider.getResourceInputStream("tor_" + architecture); .getResourceInputStream("tor_" + architecture, ".zip");
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 {
InputStream in = resourceProvider.getResourceInputStream("geoip"); InputStream in = resourceProvider.getResourceInputStream("geoip",
".zip");
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() { private InputStream getConfigInputStream() {
return resourceProvider.getResourceInputStream("torrc"); return getClass().getClassLoader().getResourceAsStream("torrc");
} }
private void tryToClose(@Nullable Closeable c) { private void tryToClose(@Nullable Closeable c) {
@@ -348,9 +362,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void bind() { private void bind() {
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
// 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(PREF_TOR_PORT); String portString = settings.get(PREF_TOR_PORT);
int port; int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0; if (isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString); else port = Integer.parseInt(portString);
// Bind a server socket to receive connections from Tor // Bind a server socket to receive connections from Tor
ServerSocket ss = null; ServerSocket ss = null;
@@ -393,7 +407,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void publishHiddenService(String port) { private void publishHiddenService(String port) {
if (!running) return; if (!running) return;
LOG.info("Creating hidden service"); LOG.info("Creating hidden service");
String privKey = callback.getSettings().get(HS_PRIVKEY); String privKey = settings.get(HS_PRIVKEY);
Map<Integer, String> portLines = Map<Integer, String> portLines =
Collections.singletonMap(80, "127.0.0.1:" + port); Collections.singletonMap(80, "127.0.0.1:" + port);
Map<String, String> response; Map<String, String> response;
@@ -415,11 +429,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return; return;
} }
// Publish the hidden service's onion hostname in transport properties // Publish the hidden service's onion hostname in transport properties
String hostname = response.get(HS_ADDRESS); String onion2 = response.get(HS_ADDRESS);
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Hidden service " + scrubOnion(hostname)); LOG.info("Hidden service " + scrubOnion(onion2));
TransportProperties p = new TransportProperties(); TransportProperties p = new TransportProperties();
p.put(PROP_ONION, hostname); p.put(PROP_ONION_V2, onion2);
callback.mergeLocalProperties(p); callback.mergeLocalProperties(p);
if (privKey == null) { if (privKey == null) {
// Save the hidden service's private key for next time // Save the hidden service's private key for next time
@@ -518,26 +532,41 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public DuplexTransportConnection createConnection(TransportProperties p) { public DuplexTransportConnection createConnection(TransportProperties p) {
if (!isRunning()) return null; if (!isRunning()) return null;
String onion = p.get(PROP_ONION); String bestOnion = null;
if (StringUtils.isNullOrEmpty(onion)) return null; String onion2 = p.get(PROP_ONION_V2);
if (!ONION.matcher(onion).matches()) { String onion3 = p.get(PROP_ONION_V3);
// not scrubbing this address, so we are able to find the problem if (!isNullOrEmpty(onion2)) {
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion); if (ONION_V2.matcher(onion2).matches()) {
return null; bestOnion = onion2;
} else {
// Don't scrub the address so we can find the problem
if (LOG.isLoggable(INFO))
LOG.info("Invalid v2 hostname: " + onion2);
} }
}
if (!isNullOrEmpty(onion3)) {
if (ONION_V3.matcher(onion3).matches()) {
bestOnion = onion3;
} else {
// Don't scrub the address so we can find the problem
if (LOG.isLoggable(INFO))
LOG.info("Invalid v3 hostname: " + onion3);
}
}
if (bestOnion == null) return null;
Socket s = null; Socket s = null;
try { try {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubOnion(onion)); LOG.info("Connecting to " + scrubOnion(bestOnion));
s = torSocketFactory.createSocket(onion + ".onion", 80); s = torSocketFactory.createSocket(bestOnion + ".onion", 80);
s.setSoTimeout(socketTimeout); s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubOnion(onion)); LOG.info("Connected to " + scrubOnion(bestOnion));
return new TorTransportConnection(this, s); return new TorTransportConnection(this, s);
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to " + scrubOnion(onion) + ": " + LOG.info("Could not connect to " + scrubOnion(bestOnion)
e.toString()); + ": " + e.toString());
} }
tryToClose(s); tryToClose(s);
return null; return null;
@@ -576,7 +605,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public void orConnStatus(String status, String orName) { public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status); if (LOG.isLoggable(INFO))
LOG.info("OR connection " + status + " " + orName);
if (status.equals("CLOSED") || status.equals("FAILED")) { if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity // Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus()); updateConnectionStatus(networkManager.getNetworkStatus());
@@ -613,6 +643,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e; SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) { if (s.getNamespace().equals(ID.getString())) {
LOG.info("Tor settings updated"); LOG.info("Tor settings updated");
settings = s.getSettings();
// Works around a bug introduced in Tor 0.3.4.8. Could be
// replaced with callback.transportDisabled() when fixed.
disableNetwork();
updateConnectionStatus(networkManager.getNetworkStatus()); updateConnectionStatus(networkManager.getNetworkStatus());
} }
} else if (e instanceof NetworkStatusEvent) { } else if (e instanceof NetworkStatusEvent) {
@@ -620,6 +654,16 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
private void disableNetwork() {
connectionStatusExecutor.execute(() -> {
try {
enableNetwork(false);
} catch (IOException ex) {
logException(LOG, WARNING, ex);
}
});
}
private void updateConnectionStatus(NetworkStatus status) { private void updateConnectionStatus(NetworkStatus status) {
connectionStatusExecutor.execute(() -> { connectionStatusExecutor.execute(() -> {
if (!running) return; if (!running) return;
@@ -628,10 +672,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
String country = locationUtils.getCurrentCountry(); String country = locationUtils.getCurrentCountry();
boolean blocked = boolean blocked =
circumventionProvider.isTorProbablyBlocked(country); circumventionProvider.isTorProbablyBlocked(country);
Settings s = callback.getSettings(); int network = settings.getInt(PREF_TOR_NETWORK,
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS); PREF_TOR_NETWORK_AUTOMATIC);
boolean disableWhenBlocked = boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true);
s.getBoolean(PREF_TOR_DISABLE_BLOCKED, true); boolean bridgesWork = circumventionProvider.doBridgesWork(country);
boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC;
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi); LOG.info("Online: " + online + ", wifi: " + wifi);
@@ -643,25 +688,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) { if (!online) {
LOG.info("Disabling network, device is offline"); LOG.info("Disabling network, device is offline");
enableNetwork(false); enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER } else if (network == PREF_TOR_NETWORK_NEVER ||
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) { (!useMobile && !wifi)) {
LOG.info("Disabling network due to data setting"); LOG.info("Disabling network due to setting");
enableNetwork(false); enableNetwork(false);
} else if (blocked) { } else if (automatic && blocked && !bridgesWork) {
if (circumventionProvider.doBridgesWork(country)) { LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
(automatic && bridgesWork)) {
LOG.info("Enabling network, using bridges"); LOG.info("Enabling network, using bridges");
enableBridges(true); enableBridges(true);
enableNetwork(true); enableNetwork(true);
} else if (disableWhenBlocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else { } else {
LOG.info("Enabling network but country is blocked"); LOG.info("Enabling network, not using bridges");
enableBridges(false);
enableNetwork(true);
}
} else {
LOG.info("Enabling network");
enableBridges(false); enableBridges(false);
enableNetwork(true); enableNetwork(true);
} }
@@ -671,6 +711,21 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}); });
} }
// TODO remove when sufficient time has passed. Added 2018-08-15
private void migrateSettings() {
Settings sOld = callback.getSettings();
int oldNetwork = sOld.getInt("network", -1);
if (oldNetwork == -1) return;
Settings s = new Settings();
if (oldNetwork == 0) {
s.putInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_NEVER);
} else if (oldNetwork == 1) {
s.putBoolean(PREF_TOR_MOBILE, false);
}
s.putInt("network", -1);
callback.mergeSettings(s);
}
private static class ConnectionStatus { private static class ConnectionStatus {
// All of the following are locking: this // All of the following are locking: this

View File

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

View File

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

View File

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

View File

@@ -36,14 +36,11 @@ class MessageFactoryImpl implements MessageFactory {
@Override @Override
public Message createMessage(GroupId g, long timestamp, byte[] body) { public Message createMessage(GroupId g, long timestamp, byte[] body) {
if (body.length == 0) throw new IllegalArgumentException();
if (body.length > MAX_MESSAGE_BODY_LENGTH) if (body.length > MAX_MESSAGE_BODY_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
MessageId id = getMessageId(g, timestamp, body); MessageId id = getMessageId(g, timestamp, body);
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length]; return new Message(id, g, timestamp, body);
System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
return new Message(id, g, timestamp, raw);
} }
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) { private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
@@ -58,7 +55,7 @@ class MessageFactoryImpl implements MessageFactory {
@Override @Override
public Message createMessage(byte[] raw) { public Message createMessage(byte[] raw) {
if (raw.length < MESSAGE_HEADER_LENGTH) if (raw.length <= MESSAGE_HEADER_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (raw.length > MAX_MESSAGE_LENGTH) if (raw.length > MAX_MESSAGE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@@ -69,18 +66,16 @@ class MessageFactoryImpl implements MessageFactory {
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH]; byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length); System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
MessageId id = getMessageId(g, timestamp, body); MessageId id = getMessageId(g, timestamp, body);
return new Message(id, g, timestamp, raw); return new Message(id, g, timestamp, body);
} }
@Override @Override
public Message createMessage(MessageId m, byte[] raw) { public byte[] getRawMessage(Message m) {
if (raw.length < MESSAGE_HEADER_LENGTH) byte[] body = m.getBody();
throw new IllegalArgumentException(); byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
if (raw.length > MAX_MESSAGE_LENGTH) System.arraycopy(m.getGroupId().getBytes(), 0, raw, 0, UniqueId.LENGTH);
throw new IllegalArgumentException(); ByteUtils.writeUint64(m.getTimestamp(), raw, UniqueId.LENGTH);
byte[] groupId = new byte[UniqueId.LENGTH]; System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH); return raw;
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
return new Message(m, new GroupId(groupId), timestamp, raw);
} }
} }

View File

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

View File

@@ -124,7 +124,8 @@ class SyncRecordReaderImpl implements SyncRecordReader {
if (!hasMessage()) throw new FormatException(); if (!hasMessage()) throw new FormatException();
if (nextRecord == null) throw new AssertionError(); if (nextRecord == null) throw new AssertionError();
byte[] payload = nextRecord.getPayload(); byte[] payload = nextRecord.getPayload();
if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException(); if (payload.length <= MESSAGE_HEADER_LENGTH)
throw new FormatException();
// Validate timestamp // Validate timestamp
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH); long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
if (timestamp < 0) throw new FormatException(); if (timestamp < 0) throw new FormatException();

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.record.RecordWriter; import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.record.RecordWriterFactory; import org.briarproject.bramble.api.record.RecordWriterFactory;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.SyncRecordWriter; import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory; import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
@@ -13,16 +14,19 @@ import javax.inject.Inject;
@NotNullByDefault @NotNullByDefault
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory { class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
private final MessageFactory messageFactory;
private final RecordWriterFactory recordWriterFactory; private final RecordWriterFactory recordWriterFactory;
@Inject @Inject
SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) { SyncRecordWriterFactoryImpl(MessageFactory messageFactory,
RecordWriterFactory recordWriterFactory) {
this.messageFactory = messageFactory;
this.recordWriterFactory = recordWriterFactory; this.recordWriterFactory = recordWriterFactory;
} }
@Override @Override
public SyncRecordWriter createRecordWriter(OutputStream out) { public SyncRecordWriter createRecordWriter(OutputStream out) {
RecordWriter writer = recordWriterFactory.createRecordWriter(out); RecordWriter writer = recordWriterFactory.createRecordWriter(out);
return new SyncRecordWriterImpl(writer); return new SyncRecordWriterImpl(messageFactory, writer);
} }
} }

View File

@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.record.Record; import org.briarproject.bramble.api.record.Record;
import org.briarproject.bramble.api.record.RecordWriter; import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
@@ -24,10 +26,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
@NotNullByDefault @NotNullByDefault
class SyncRecordWriterImpl implements SyncRecordWriter { class SyncRecordWriterImpl implements SyncRecordWriter {
private final MessageFactory messageFactory;
private final RecordWriter writer; private final RecordWriter writer;
private final ByteArrayOutputStream payload = new ByteArrayOutputStream(); private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
SyncRecordWriterImpl(RecordWriter writer) { SyncRecordWriterImpl(MessageFactory messageFactory, RecordWriter writer) {
this.messageFactory = messageFactory;
this.writer = writer; this.writer = writer;
} }
@@ -44,7 +48,8 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
} }
@Override @Override
public void writeMessage(byte[] raw) throws IOException { public void writeMessage(Message m) throws IOException {
byte[] raw = messageFactory.getRawMessage(m);
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw)); writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
} }

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98 Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8 Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
Bridge 178.62.62.193:8443 391B1F9B6A28A1C5FAE1872283985F975E5DB029
Bridge 45.76.29.92:8443 ECF1DD51A46FDEF2C50CED992EEEAE8DED18DA0C

View File

@@ -16,8 +16,8 @@ import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser; import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test; import org.junit.Test;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
@@ -28,8 +28,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
new BdfMessageValidator(clientHelper, metadataEncoder, clock) { new BdfMessageValidator(clientHelper, metadataEncoder, clock) {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) BdfList body) {
throws InvalidMessageException, FormatException {
throw new AssertionError(); throw new AssertionError();
} }
}; };
@@ -57,8 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE)); will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH, oneOf(clientHelper).toList(message.getBody());
raw.length - MESSAGE_HEADER_LENGTH);
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -69,7 +67,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) { metadataEncoder, clock) {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException { BdfList b) {
assertSame(message, m); assertSame(message, m);
assertSame(group, g); assertSame(group, g);
assertSame(body, b); assertSame(body, b);
@@ -81,35 +79,14 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
assertSame(meta, messageContext.getMetadata()); assertSame(meta, messageContext.getMetadata());
} }
@Test(expected = InvalidMessageException.class)
public void testRejectsTooShortMessage() throws Exception {
byte[] invalidRaw = new byte[MESSAGE_HEADER_LENGTH];
// Use a mock message so the length of the raw message can be invalid
Message invalidMessage = context.mock(Message.class);
context.checking(new Expectations() {{
oneOf(invalidMessage).getTimestamp();
will(returnValue(timestamp));
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(invalidMessage).getRaw();
will(returnValue(invalidRaw));
}});
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
}
@Test @Test
public void testAcceptsMinLengthMessage() throws Exception { public void testAcceptsMinLengthMessage() throws Exception {
byte[] shortRaw = new byte[MESSAGE_HEADER_LENGTH + 1]; Message shortMessage = getMessage(groupId, 1);
Message shortMessage =
new Message(messageId, groupId, timestamp, shortRaw);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(shortRaw, MESSAGE_HEADER_LENGTH, oneOf(clientHelper).toList(shortMessage.getBody());
shortRaw.length - MESSAGE_HEADER_LENGTH);
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -120,7 +97,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) { metadataEncoder, clock) {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException { BdfList b) {
assertSame(shortMessage, m); assertSame(shortMessage, m);
assertSame(group, g); assertSame(group, g);
assertSame(body, b); assertSame(body, b);
@@ -137,8 +114,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH, oneOf(clientHelper).toList(message.getBody());
raw.length - MESSAGE_HEADER_LENGTH);
will(throwException(new FormatException())); will(throwException(new FormatException()));
}}); }});
@@ -150,8 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH, oneOf(clientHelper).toList(message.getBody());
raw.length - MESSAGE_HEADER_LENGTH);
will(returnValue(body)); will(returnValue(body));
}}); }});
@@ -160,7 +135,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) { metadataEncoder, clock) {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException { BdfList b) throws FormatException {
throw new FormatException(); throw new FormatException();
} }
}; };

View File

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

View File

@@ -5,12 +5,17 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
import org.junit.Test; import org.junit.Test;
@@ -20,10 +25,20 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Random; import java.util.Random;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class ContactManagerImplTest extends BrambleMockTestCase { public class ContactManagerImplTest extends BrambleMockTestCase {
@@ -31,16 +46,20 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
private final Mockery context = new Mockery(); private final Mockery context = new Mockery();
private final DatabaseComponent db = context.mock(DatabaseComponent.class); private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final KeyManager keyManager = context.mock(KeyManager.class); private final KeyManager keyManager = context.mock(KeyManager.class);
private final IdentityManager identityManager =
context.mock(IdentityManager.class);
private final ContactManager contactManager; private final ContactManager contactManager;
private final ContactId contactId = new ContactId(42); private final ContactId contactId = new ContactId(42);
private final Author remote = getAuthor(); private final Author remote = getAuthor();
private final AuthorId local = new AuthorId(getRandomId()); private final AuthorId local = new AuthorId(getRandomId());
private final LocalAuthor localAuthor = getLocalAuthor();
private final String alias = getRandomString(MAX_AUTHOR_NAME_LENGTH);
private final boolean verified = false, active = true; private final boolean verified = false, active = true;
private final Contact contact = private final Contact contact =
new Contact(contactId, remote, local, verified, active); new Contact(contactId, remote, local, alias, verified, active);
public ContactManagerImplTest() { public ContactManagerImplTest() {
contactManager = new ContactManagerImpl(db, keyManager); contactManager = new ContactManagerImpl(db, keyManager, identityManager);
} }
@Test @Test
@@ -105,7 +124,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true); oneOf(db).startTransaction(true);
will(returnValue(txn)); will(returnValue(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId()); oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(Collections.emptyList())); will(returnValue(emptyList()));
oneOf(db).endTransaction(txn); oneOf(db).endTransaction(txn);
}}); }});
@@ -131,7 +150,8 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testActiveContacts() throws Exception { public void testActiveContacts() throws Exception {
Collection<Contact> activeContacts = Collections.singletonList(contact); Collection<Contact> activeContacts = Collections.singletonList(contact);
Collection<Contact> contacts = new ArrayList<>(activeContacts); Collection<Contact> contacts = new ArrayList<>(activeContacts);
contacts.add(new Contact(new ContactId(3), remote, local, true, false)); contacts.add(new Contact(new ContactId(3), remote, local, alias, true,
false));
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(db).startTransaction(true); oneOf(db).startTransaction(true);
@@ -171,6 +191,23 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
contactManager.setContactActive(txn, contactId, active); contactManager.setContactActive(txn, contactId, active);
} }
@Test
public void testSetContactAlias() throws Exception {
Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(equal(false)), withDbRunnable(txn));
oneOf(db).setContactAlias(txn, contactId, alias);
}});
contactManager.setContactAlias(contactId, alias);
}
@Test(expected = IllegalArgumentException.class)
public void testSetContactAliasTooLong() throws Exception {
contactManager.setContactAlias(contactId,
getRandomString(MAX_AUTHOR_NAME_LENGTH + 1));
}
@Test @Test
public void testContactExists() throws Exception { public void testContactExists() throws Exception {
Transaction txn = new Transaction(null, true); Transaction txn = new Transaction(null, true);
@@ -186,4 +223,79 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
assertTrue(contactManager.contactExists(remote.getId(), local)); assertTrue(contactManager.contactExists(remote.getId(), local));
} }
@Test
public void testGetAuthorStatus() throws Exception {
Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(equal(true)),
withDbCallable(txn));
oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(contacts));
}});
AuthorInfo authorInfo =
contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(UNVERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias());
}
@Test
public void testGetAuthorStatusTransaction() throws DbException {
Transaction txn = new Transaction(null, true);
// check unknown author
context.checking(new Expectations() {{
oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(emptyList()));
}});
AuthorInfo authorInfo =
contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(UNKNOWN, authorInfo.getStatus());
assertNull(authorInfo.getAlias());
// check unverified contact
Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true));
checkAuthorStatusContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(UNVERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias());
// check verified contact
contacts = singletonList(new Contact(new ContactId(1), remote,
localAuthor.getId(), alias, true, true));
checkAuthorStatusContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(VERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias());
// check ourselves
context.checking(new Expectations() {{
oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor));
never(db).getContactsByAuthorId(txn, remote.getId());
}});
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
assertEquals(OURSELVES, authorInfo.getStatus());
assertNull(authorInfo.getAlias());
}
private void checkAuthorStatusContext(Transaction txn, AuthorId authorId,
Collection<Contact> contacts) throws DbException {
context.checking(new Expectations() {{
oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor));
oneOf(db).getContactsByAuthorId(txn, authorId);
will(returnValue(contacts));
}});
}
} }

View File

@@ -11,6 +11,8 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import org.briarproject.bramble.test.ArrayClock;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -74,24 +76,4 @@ public class ScryptKdfTest extends BrambleTestCase {
PasswordBasedKdf kdf = new ScryptKdf(clock); PasswordBasedKdf kdf = new ScryptKdf(clock);
assertEquals(256, kdf.chooseCostParameter()); assertEquals(256, kdf.chooseCostParameter());
} }
private static class ArrayClock implements Clock {
private final long[] times;
private int index = 0;
private ArrayClock(long... times) {
this.times = times;
}
@Override
public long currentTimeMillis() {
return times[index++];
}
@Override
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}
} }

View File

@@ -64,6 +64,7 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN; import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE; import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
@@ -72,9 +73,11 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId; import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@@ -97,10 +100,9 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private final Group group; private final Group group;
private final Author author; private final Author author;
private final LocalAuthor localAuthor; private final LocalAuthor localAuthor;
private final String alias;
private final Message message, message1;
private final MessageId messageId, messageId1; private final MessageId messageId, messageId1;
private final int size;
private final byte[] raw;
private final Message message;
private final Metadata metadata; private final Metadata metadata;
private final TransportId transportId; private final TransportId transportId;
private final int maxLatency; private final int maxLatency;
@@ -115,18 +117,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
groupId = group.getId(); groupId = group.getId();
author = getAuthor(); author = getAuthor();
localAuthor = getLocalAuthor(); localAuthor = getLocalAuthor();
messageId = new MessageId(getRandomId()); alias = getRandomString(5);
messageId1 = new MessageId(getRandomId()); message = getMessage(groupId);
long timestamp = System.currentTimeMillis(); message1 = getMessage(groupId);
size = 1234; messageId = message.getId();
raw = new byte[size]; messageId1 = message1.getId();
message = new Message(messageId, groupId, timestamp, raw);
metadata = new Metadata(); metadata = new Metadata();
metadata.put("foo", new byte[] {'b', 'a', 'r'}); metadata.put("foo", new byte[] {'b', 'a', 'r'});
transportId = getTransportId(); transportId = getTransportId();
maxLatency = Integer.MAX_VALUE; maxLatency = Integer.MAX_VALUE;
contactId = new ContactId(234); contactId = new ContactId(234);
contact = new Contact(contactId, author, localAuthor.getId(), contact = new Contact(contactId, author, localAuthor.getId(), alias,
true, true); true, true);
keySetId = new KeySetId(345); keySetId = new KeySetId(345);
} }
@@ -290,11 +291,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not) // Check whether the contact is in the DB (which it's not)
exactly(16).of(database).startTransaction(); exactly(17).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(16).of(database).containsContact(txn, contactId); exactly(17).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(16).of(database).abortTransaction(txn); exactly(17).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown); shutdown);
@@ -452,6 +453,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.endTransaction(transaction); db.endTransaction(transaction);
} }
transaction = db.startTransaction(false);
try {
db.setContactAlias(transaction, contactId, alias);
fail();
} catch (NoSuchContactException expected) {
// Expected
} finally {
db.endTransaction(transaction);
}
transaction = db.startTransaction(false); transaction = db.startTransaction(false);
try { try {
db.setGroupVisibility(transaction, contactId, groupId, SHARED); db.setGroupVisibility(transaction, contactId, groupId, SHARED);
@@ -646,7 +657,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
transaction = db.startTransaction(false); transaction = db.startTransaction(false);
try { try {
db.getRawMessage(transaction, messageId); db.getMessage(transaction, messageId);
fail(); fail();
} catch (NoSuchMessageException expected) { } catch (NoSuchMessageException expected) {
// Expected // Expected
@@ -865,23 +876,23 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test @Test
public void testGenerateBatch() throws Exception { public void testGenerateBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1); Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1); Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(database).startTransaction(); oneOf(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getMessagesToSend(txn, contactId, size * 2); oneOf(database).getMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId); oneOf(database).getMessage(txn, messageId);
will(returnValue(raw)); will(returnValue(message));
oneOf(database).updateExpiryTime(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
oneOf(database).getRawMessage(txn, messageId1); oneOf(database).getMessage(txn, messageId1);
will(returnValue(raw1)); will(returnValue(message1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency); maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids); oneOf(database).lowerRequestedFlag(txn, contactId, ids);
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
@@ -893,7 +904,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false); Transaction transaction = db.startTransaction(false);
try { try {
assertEquals(messages, db.generateBatch(transaction, contactId, assertEquals(messages, db.generateBatch(transaction, contactId,
size * 2, maxLatency)); MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction); db.commitTransaction(transaction);
} finally { } finally {
db.endTransaction(transaction); db.endTransaction(transaction);
@@ -909,11 +920,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getMessagesToOffer(txn, contactId, 123); oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).updateExpiryTime(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
oneOf(database).updateExpiryTime(txn, contactId, messageId1, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency); maxLatency);
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
}}); }});
@@ -961,24 +972,23 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test @Test
public void testGenerateRequestedBatch() throws Exception { public void testGenerateRequestedBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1); Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1); Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(database).startTransaction(); oneOf(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getRequestedMessagesToSend(txn, contactId, oneOf(database).getRequestedMessagesToSend(txn, contactId,
size * 2); MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId); oneOf(database).getMessage(txn, messageId);
will(returnValue(raw)); will(returnValue(message));
oneOf(database).updateExpiryTime(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
oneOf(database).getRawMessage(txn, messageId1); oneOf(database).getMessage(txn, messageId1);
will(returnValue(raw1)); will(returnValue(message1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency); maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids); oneOf(database).lowerRequestedFlag(txn, contactId, ids);
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
@@ -990,7 +1000,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false); Transaction transaction = db.startTransaction(false);
try { try {
assertEquals(messages, db.generateRequestedBatch(transaction, assertEquals(messages, db.generateRequestedBatch(transaction,
contactId, size * 2, maxLatency)); contactId, MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction); db.commitTransaction(transaction);
} finally { } finally {
db.endTransaction(transaction); db.endTransaction(transaction);

View File

@@ -7,10 +7,12 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.TestDatabaseConfig; import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.TestUtils; import org.briarproject.bramble.test.TestUtils;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.After; import org.junit.After;
@@ -45,6 +47,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
protected final DatabaseConfig config = protected final DatabaseConfig config =
new TestDatabaseConfig(testDir, 1024 * 1024); new TestDatabaseConfig(testDir, 1024 * 1024);
protected final MessageFactory messageFactory = new TestMessageFactory();
protected final SecretKey key = getSecretKey(); protected final SecretKey key = getSecretKey();
protected final Clock clock = new SystemClock(); protected final Clock clock = new SystemClock();

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig; import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.UTest; import org.briarproject.bramble.test.UTest;
import java.io.IOException; import java.io.IOException;
@@ -26,9 +29,11 @@ public abstract class DatabasePerformanceComparisonTest
* How many blocks of each condition to compare. * How many blocks of each condition to compare.
*/ */
private static final int COMPARISON_BLOCKS = 10; private static final int COMPARISON_BLOCKS = 10;
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(boolean conditionA, abstract Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock); DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock);
@Override @Override
protected void benchmark(String name, protected void benchmark(String name,
@@ -71,8 +76,9 @@ public abstract class DatabasePerformanceComparisonTest
private Database<Connection> openDatabase(boolean conditionA) private Database<Connection> openDatabase(boolean conditionA)
throws DbException { throws DbException {
Database<Connection> db = createDatabase(conditionA, Database<Connection> db = createDatabase(conditionA,
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock()); new TestDatabaseConfig(testDir, MAX_SIZE),
db.open(getSecretKey(), null); new TestMessageFactory(), new SystemClock());
db.open(databaseKey, null);
return db; return db;
} }

View File

@@ -96,6 +96,9 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
*/ */
private static final int STEADY_STATE_BLOCKS = 5; private static final int STEADY_STATE_BLOCKS = 5;
// All our transports use a maximum latency of 30 seconds
private static final int MAX_LATENCY = 30 * 1000;
protected final File testDir = getTestDirectory(); protected final File testDir = getTestDirectory();
private final File resultsFile = new File(getTestName() + ".tsv"); private final File resultsFile = new File(getTestName() + ".tsv");
protected final Random random = new Random(); protected final Random random = new Random();
@@ -448,7 +451,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> { benchmark(name, db -> {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
db.getMessagesToOffer(txn, pickRandom(contacts).getId(), db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS); MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn); db.commitTransaction(txn);
}); });
} }
@@ -470,7 +473,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> { benchmark(name, db -> {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
db.getMessagesToSend(txn, pickRandom(contacts).getId(), db.getMessagesToSend(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS); MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn); db.commitTransaction(txn);
}); });
} }
@@ -506,11 +509,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
} }
@Test @Test
public void testGetRawMessage() throws Exception { public void testGetMessage() throws Exception {
String name = "getRawMessage(T, MessageId)"; String name = "getMessage(T, MessageId)";
benchmark(name, db -> { benchmark(name, db -> {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
db.getRawMessage(txn, pickRandom(messages).getId()); db.getMessage(txn, pickRandom(messages).getId());
db.commitTransaction(txn); db.commitTransaction(txn);
}); });
} }
@@ -521,7 +524,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> { benchmark(name, db -> {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(), db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS); MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn); db.commitTransaction(txn);
}); });
} }

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig; import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.util.IoUtils; import org.briarproject.bramble.util.IoUtils;
import java.io.File; import java.io.File;
@@ -20,8 +23,10 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey;
public abstract class DatabaseTraceTest extends DatabasePerformanceTest { public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig, abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock); MessageFactory messageFactory, Clock clock);
@Nullable @Nullable
protected abstract File getTraceFile(); protected abstract File getTraceFile();
@@ -43,8 +48,9 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private Database<Connection> openDatabase() throws DbException { private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase( Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock()); new TestDatabaseConfig(testDir, MAX_SIZE),
db.open(getSecretKey(), null); new TestMessageFactory(), new SystemClock());
db.open(databaseKey, null);
return db; return db;
} }

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -13,7 +14,8 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
} }
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) { protected JdbcDatabase createDatabase(DatabaseConfig config,
return new H2Database(config, clock); MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
} }
} }

View File

@@ -1,16 +1,14 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
public class H2DatabaseTest extends JdbcDatabaseTest { public class H2DatabaseTest extends JdbcDatabaseTest {
public H2DatabaseTest() throws Exception {
super();
}
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) { protected JdbcDatabase createDatabase(DatabaseConfig config,
return new H2Database(config, clock); MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
} }
} }

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -14,8 +15,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
@Override @Override
Database<Connection> createDatabase(DatabaseConfig databaseConfig, Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock) { MessageFactory messageFactory, Clock clock) {
return new H2Database(databaseConfig, clock) { return new H2Database(databaseConfig, messageFactory, clock) {
@Override @Override
@Nonnull @Nonnull
String getUrl() { String getUrl() {

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -12,9 +13,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) { DatabaseConfig databaseConfig, MessageFactory messageFactory,
if (conditionA) return new H2Database(databaseConfig, clock); Clock clock) {
else return new HyperSqlDatabase(databaseConfig, clock); if (conditionA)
return new H2Database(databaseConfig, messageFactory, clock);
else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
} }
@Override @Override

View File

@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
@Override @Override
Database<Connection> createDatabase( Database<Connection> createDatabase(
List<Migration<Connection>> migrations) { List<Migration<Connection>> migrations) {
return new H2Database(config, clock) { return new H2Database(config, messageFactory, clock) {
@Override @Override
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {
return migrations; return migrations;

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -17,8 +18,9 @@ public class H2SelfDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) { DatabaseConfig databaseConfig, MessageFactory messageFactory,
return new H2Database(databaseConfig, clock); Clock clock) {
return new H2Database(databaseConfig, messageFactory, clock);
} }
@Override @Override

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -19,11 +20,12 @@ public class H2SleepDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) { DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
if (conditionA) { if (conditionA) {
return new H2Database(databaseConfig, clock); return new H2Database(databaseConfig, messageFactory, clock);
} else { } else {
return new H2Database(databaseConfig, clock) { return new H2Database(databaseConfig, messageFactory, clock) {
@Override @Override
@NotNullByDefault @NotNullByDefault
public void commitTransaction(Connection txn) public void commitTransaction(Connection txn)

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -14,7 +15,8 @@ public class HyperSqlDatabasePerformanceTest
} }
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) { protected JdbcDatabase createDatabase(DatabaseConfig config,
return new HyperSqlDatabase(config, clock); MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory, clock);
} }
} }

View File

@@ -1,16 +1,14 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
public class HyperSqlDatabaseTest extends JdbcDatabaseTest { public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
public HyperSqlDatabaseTest() throws Exception {
super();
}
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) { protected JdbcDatabase createDatabase(DatabaseConfig config,
return new HyperSqlDatabase(config, clock); MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory ,clock);
} }
} }

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