Compare commits

..

266 Commits

Author SHA1 Message Date
akwizgran
189ec874cc @GuardedBy annotations. 2019-02-15 10:16:26 +00:00
akwizgran
8c25732d13 Miscellaneous code cleanups. 2019-02-15 10:16:19 +00:00
akwizgran
c59ef29cdb Minor code cleanups. 2019-02-14 17:37:53 +00:00
akwizgran
56ac755e96 Lint cleanups. 2019-02-14 17:37:51 +00:00
akwizgran
98633f5e7c A few more null safety cleanups. 2019-02-14 17:29:55 +00:00
akwizgran
86130e845a Null safety cleanups. 2019-02-14 17:29:55 +00:00
akwizgran
8ecec8bcf5 More static imports. 2019-02-14 17:29:52 +00:00
akwizgran
ad9191b076 Static imports. 2019-02-14 13:56:20 +00:00
Torsten Grote
b342759e06 Merge branch '978-tor-only-on-battery' into 'master'
Add a setting to disable Tor when running on battery

Closes #978

See merge request briar/briar!1032
2019-02-06 14:46:33 +00:00
akwizgran
93d99b0111 Tweak wording of Tor battery setting. 2019-02-06 14:23:15 +00:00
akwizgran
61e8d576d2 Update mobile data log message, simplify logic. 2019-02-06 14:20:04 +00:00
Torsten Grote
75c37a258e Add a setting to disable Tor when running on battery 2019-02-05 13:46:26 -02:00
akwizgran
e964dae64b Merge branch '1468-image-size-tests' into 'master'
Add tests for parsing image sizes

See merge request briar/briar!1026
2019-01-15 17:26:55 +00:00
akwizgran
986d884b40 Refactor ImageManager to ImageHelper. 2019-01-15 17:14:57 +00:00
akwizgran
9557afabc6 Change MIME types to "image/jpeg", unsuppress warning. 2019-01-15 16:49:18 +00:00
Torsten Grote
ebe6b0d4c0 [android] Split up AttachmentController tests into integration and unit 2019-01-15 16:33:03 +00:00
Torsten Grote
6e83fb7aef [android] add tests for getting attachment items from AttachmentController 2019-01-15 16:33:00 +00:00
Torsten Grote
7a5ec2af12 [android] Add test for MarkEnforcingInputStream 2019-01-15 16:32:23 +00:00
akwizgran
ce1fde496c Merge branch '1477-check-attachment-support' into 'master'
Find out if contacts support image attachments and enable them

Closes #1477

See merge request briar/briar!1019
2019-01-15 15:35:48 +00:00
akwizgran
4b62c51fbf Revert to using a fixed delay for the onboarding. 2019-01-15 15:23:30 +00:00
akwizgran
226ed3dd73 Wrap long line, remove redundant variable. 2019-01-14 14:31:31 +00:00
akwizgran
ab07dfb32c Use expression lambda. 2019-01-14 14:26:09 +00:00
akwizgran
20c51c1aa4 Group together fields with the same access restrictions. 2019-01-14 14:25:32 +00:00
Torsten Grote
232c2129a7 [android] use a LiveData in ConversationActivity to get notified when transition ended 2019-01-14 14:22:31 +00:00
Torsten Grote
3620edbfc9 [android] set a transition animation duration for ConversationActivity
so we know better for how long to delay the onboarding dialogs
2019-01-14 14:21:34 +00:00
Torsten Grote
ad71d69149 Create and use method in MessagingManager for checking for image support 2019-01-14 14:21:33 +00:00
Torsten Grote
f73f8ca7e7 [android] do not show two private conversation onboardings at the same time
Checking for introduction onboarding is now done in the ViewModel
together with the image onboarding. The latter has preference. If both
could be shown, the introduction onboarding will be delayed to the next
time the user enters the conversation.
2019-01-14 14:21:33 +00:00
Torsten Grote
16c701a71a [android] only enable image feature if contact supports it
Also show an onboarding the first time, the feature gets activiated
2019-01-14 14:21:19 +00:00
akwizgran
8183b7b26a Merge branch '1469-hide-ui-without-flashing' into 'master'
Hide UI without flashing

Closes #1469

See merge request briar/briar!1030
2019-01-11 17:22:04 +00:00
akwizgran
bd48c97eab Merge branch 'upgrade-jackson-2.9.8' into 'master'
Upgrade Jackson to 2.9.8

See merge request briar/briar!1031
2019-01-11 17:07:07 +00:00
akwizgran
925dc29a1f Merge branch 'hide-ui-api-15' into 'master'
Improve UI hiding behaviour

See merge request briar/briar!1029
2019-01-11 17:03:24 +00:00
akwizgran
91777fd942 Hide UI without flashing. 2019-01-11 16:59:53 +00:00
akwizgran
fbce8f81c7 Merge branch '1475-transition-name' into 'master'
Use a unique transition name for each AttachmentItem

See merge request briar/briar!1028
2019-01-11 16:54:24 +00:00
akwizgran
d7c72c4d68 Use a unique transition name for each AttachmentItem. 2019-01-11 16:45:20 +00:00
akwizgran
4faf535801 Reduce visibility. 2019-01-11 16:45:20 +00:00
akwizgran
526ef7c6d8 Add array entries for new translations. 2019-01-11 15:13:06 +00:00
akwizgran
798dff1a03 Update translations, add Macedonian and Ukrainian. 2019-01-11 12:18:15 +00:00
akwizgran
a4336776c9 Merge branch '1475-image-transitions' into 'master'
Resolve main issues with image transition animation

See merge request briar/briar!1016
2019-01-09 15:01:29 +00:00
akwizgran
418451cbd9 Use consistent conditions to decide whether to scroll. 2019-01-09 14:30:57 +00:00
akwizgran
045fcfc5fa Remove translucent window effect. 2019-01-09 14:30:57 +00:00
Torsten Grote
ef998577db [android] add nullability annotations to ImageActivity 2019-01-09 14:30:57 +00:00
Torsten Grote
a53345a3c9 [android] scroll down when new messages arrive while conversation is visible
Also shows new message notification when ConversationActivity is paused
2019-01-09 14:30:56 +00:00
Torsten Grote
ed8c09282d [android] enable image shared element transition for API 21+22
There's an Android framework bug (#224270) on these APIs that causes a NPE
when the shared element is not visible anymore when returning.
Since we know restore the list position, the shared element should be
visible and thus not produce NPEs anymore.
2019-01-09 14:30:56 +00:00
Torsten Grote
42197b5b5c [android] Fix enter transition to fullscreen ImageActivity 2019-01-09 14:30:56 +00:00
Torsten Grote
374fc7035b [android] Save and restore list position of conversation across restarts 2019-01-09 14:30:55 +00:00
akwizgran
9b796c7cc3 Merge branch '1438-send-image-attachments-multiple' into 'master'
UX for sending multiple image attachments

See merge request briar/briar!1015
2019-01-04 17:04:43 +00:00
akwizgran
532edff642 Minor code cleanups. 2019-01-04 16:55:29 +00:00
akwizgran
6857252471 Merge branch '1480-window-background' into 'master'
[android] Change light theme background color closer to white

See merge request briar/briar!1020
2018-12-21 16:48:18 +00:00
Torsten Grote
c229e19452 [android] remove images from preview that could not be loaded
We will not even attempt to attach them
2018-12-21 11:05:34 -02:00
Torsten Grote
42bca09d16 [android] Add gap between attached image previews 2018-12-21 11:05:34 -02:00
Torsten Grote
9eacbfa659 [android] Remove palette library
we are not extracting photo colors anymore
2018-12-21 11:05:34 -02:00
Torsten Grote
f14e546dc6 [android] allow to attach multiple images 2018-12-21 11:05:34 -02:00
akwizgran
684c64a1d9 Merge branch '1310-disable-enter-transition-for-samsung7' into 'master'
[android] Disable Conversation Enter Transition for Samsung 7 devices

Closes #1310

See merge request briar/briar!1023
2018-12-19 11:32:51 +00:00
akwizgran
6fdab959b1 Merge branch '631-inject-fragments-early' into 'master'
Inject fragments earlier in their lifecycle

Closes #631

See merge request briar/briar!1024
2018-12-19 11:24:31 +00:00
Torsten Grote
c8487483ff [android] Also consider Android 7.1 (API 25) to be Samsung7
which is used for disabling certain features due to crashes there.
2018-12-18 18:17:27 -02:00
Torsten Grote
a159b23dc0 [android] Disable Conversation Enter Transition for Samsung 7 devices 2018-12-18 18:16:32 -02:00
Torsten Grote
5070a27a83 [android] also fix some activity nullability issues 2018-12-18 18:12:05 -02:00
Torsten Grote
9ce73a6840 [android] inject fragments already in onAttach()
This also removes the need to override the inject method even when
there's nothing to inject.

While passing over all fragments, some nullability issues also have been
addressed.
2018-12-18 18:01:04 -02:00
akwizgran
6e9928f20f Merge branch '1484-wait-for-component-to-be-created' into 'master'
[android] AliasFragment: Wait for activity component to be created

Closes #1484

See merge request briar/briar!1022
2018-12-18 17:46:19 +00:00
Torsten Grote
b31d61afc5 [android] AliasFragment: Wait for activity component to be created
before injecting the ViewModel
2018-12-18 15:32:26 -02:00
akwizgran
5a99cb93cc Merge branch '1482-check-earlier-for-sign-in' into 'master'
[android] don't crash when re-opening conversation after briar exited

Closes #1482

See merge request briar/briar!1021
2018-12-18 12:58:39 +00:00
Torsten Grote
d0bbebd25e [android] don't crash when re-opening conversation after briar exited 2018-12-17 18:42:06 -02:00
Torsten Grote
4307d26606 [android] Change light theme background color closer to white 2018-12-17 17:25:12 -02:00
akwizgran
0089c1ac6d Merge branch '1468-restrict-image-size' into 'master'
Fix first issues related to image size

See merge request briar/briar!1018
2018-12-17 12:48:15 +00:00
akwizgran
2a7aac4930 Upgrade Jackson to 2.9.8. 2018-12-17 12:09:36 +00:00
akwizgran
a37b6d81ed Merge branch '1242-save-snackbar-fix' into 'master'
[android] Clarify the meaning of image save state

See merge request briar/briar!1017
2018-12-17 11:17:12 +00:00
Torsten Grote
1d09a6708a [android] don't ever load an entire image into memory
This happens on API 27+28 if loading TIFF or WebP files.
Using an InputStream with a read limit prevents this.
2018-12-14 20:11:43 -02:00
Torsten Grote
d3b6f484c8 [android] allow image transformations in full-screen view
to prevent crashes from huge images
2018-12-14 20:11:43 -02:00
Torsten Grote
039c6edb66 [android] increase scale levels of PhotoView 2018-12-14 20:11:43 -02:00
Torsten Grote
8b9f89eab2 [android] Clarify the meaning of image save state 2018-12-14 12:27:47 -02:00
akwizgran
1e2c17b170 Merge branch '1242-display-image-attachments-multiple' into 'master'
Swipe left/right in image screen for images from same message

See merge request briar/briar!1012
2018-12-13 16:33:24 +00:00
Torsten Grote
a994966095 [android] address review comments for image fullscreen swiping 2018-12-13 12:00:51 -02:00
Torsten Grote
2bea581654 [android] Swipe left/right in image screen to see other images from the same message 2018-12-13 11:59:41 -02:00
Torsten Grote
87377666aa Merge branch '1473-display-multiple-images' into 'master'
UX for displaying multiple image attachments

Closes #1473

See merge request briar/briar!1010
2018-12-13 13:07:24 +00:00
akwizgran
9d07b2e141 Resolve merge conflicts.
# Conflicts:
#   briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java
#   briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
2018-12-13 11:41:04 +00:00
akwizgran
5c312b49e2 Merge branch '1438-send-image-attachments' into 'master'
Store attachments and actually attach them to sent messages

Closes #1438

See merge request briar/briar!1006
2018-12-13 10:27:09 +00:00
Torsten Grote
f56efe45cd Merge branch '1477-get-client-minor-version' into 'master'
Add method for querying client minor version supported by contact

See merge request briar/briar!1014
2018-12-12 19:34:55 +00:00
Torsten Grote
2332a58681 [android] address review comments for displaying multiple images 2018-12-12 17:00:44 -02:00
Torsten Grote
8c6dfaa196 [android] Use @UiThread instead of @MainThread 2018-12-12 16:18:43 -02:00
Torsten Grote
3cfb04b60d Establish some rules for handling InputStreams
* Methods shouldn't place any special requirements on the streams
  passed into them
* This implies that if a stream's going to be marked and reset,
  that should all happen within one method
* This also implies that if a method needs to mark and reset a stream,
  it should wrap the stream in a BufferedInputStream before doing so,
  rather than requiring a markable stream to be passed in
2018-12-12 16:17:50 -02:00
Torsten Grote
e85fbfb952 [android] close InputStream with new IoUtils method 2018-12-12 16:17:50 -02:00
Torsten Grote
80ee35d926 [core] Return fake mini PNG as Attachment instead of throwing exception 2018-12-12 16:17:50 -02:00
Torsten Grote
4796902b9c [android] store attachments and actually attach them to sent messages 2018-12-12 16:17:50 -02:00
akwizgran
149e67c0f7 Reduce code duplication in tests. 2018-12-12 11:57:35 +00:00
akwizgran
1d5214117f Add tests for getClientMinorVersion(). 2018-12-11 17:55:39 +00:00
akwizgran
b8f248ca9c Add tests for getClientVisibility(). 2018-12-11 17:51:42 +00:00
Torsten Grote
dfb71a03a5 [android] Only retrieve image sizes for single images in messages
We need to do this to know the height of messages when binding the view.
The size of single images can be different (e.g. due to orientation).
For multiple images, we use a fixed size, so no retrieval is required.
2018-12-11 15:38:05 -02:00
Torsten Grote
961fdc8e72 [android] Show multiple images in message bubble 2018-12-11 15:28:21 -02:00
Torsten Grote
c3d44663cd [android] Use a nested RecyclerView with a single items to show image attachments
This is preparation for showing multiple image attachments in one
message bubble.
2018-12-11 15:28:21 -02:00
akwizgran
0081472489 Add method for querying contact's client minor version. 2018-12-11 17:25:29 +00:00
akwizgran
cdf4f3a24b Merge branch '1232-add-contacts-remotely-api' into 'master'
[api] Add interface for adding contacts remotely

See merge request briar/briar!1007
2018-12-10 10:53:37 +00:00
Torsten Grote
fb1d8e860f [api] Add interface for adding contacts remotely 2018-12-10 08:30:50 -02:00
akwizgran
a3c526ec9a Merge branch '1298-scrub-wifi-address-in-crash-report' into 'master'
Scrub wifi IP address in crash reports.

Closes #1298

See merge request briar/briar!1013
2018-12-10 10:12:42 +00:00
Jordi Salvat
dee488d06d Scrub wifi IP address in crash reports. 2018-12-10 01:07:37 +01:00
Torsten Grote
b29c7d8022 Merge branch '1385-make-link-cover-entire-word' into 'master'
[android] fix start of link in error message for adding contacts

Closes #1385

See merge request briar/briar!1011
2018-12-07 19:13:54 +00:00
akwizgran
0725d207ec Merge branch '1432-headless-integration-tests' into 'master'
[headless] Add first integration test for ContactController

See merge request briar/briar!1008
2018-12-07 17:37:22 +00:00
akwizgran
5a7599a88d Merge branch '1242-display-image-attachments-save' into 'master'
Allow the user to save image attachment outside of Briar

See merge request briar/briar!1005
2018-12-07 17:31:42 +00:00
Torsten Grote
59cd98db81 [android] Get image extension from MimeTypeMap and store it in AttachmentItem 2018-12-07 15:11:09 -02:00
Torsten Grote
768488eb04 [android] Show (tinted) security icon when warning about saving attachments 2018-12-07 14:39:43 -02:00
Torsten Grote
a6b1ad48c3 [android] Add support for saving image attachments on API < 19
This is done by using the WRITE_EXTERNAL_STORAGE permission
to write the file directly without using the system activity.
2018-12-07 13:01:44 -02:00
Torsten Grote
77299a68ed [android] Allow the user to save image attachment outside of Briar 2018-12-07 13:01:42 -02:00
akwizgran
5e5705c73b Merge branch '1438-send-image-attachments-ui' into 'master'
Implement UX for sending image attachments

See merge request briar/briar!1004
2018-12-07 14:58:23 +00:00
Torsten Grote
e6229a3a13 [android] Factor out image preview into its own view class 2018-12-06 17:56:02 -02:00
Torsten Grote
5fbacb4ee4 [android] Split out an EmojiTextInputView from TextInputViews
This also removes the TextInputController whose job is now done by the view.
2018-12-06 17:56:02 -02:00
Torsten Grote
c7f4e976ed [android] Require users of TextInputView to set its controller 2018-12-06 17:56:02 -02:00
Torsten Grote
419f2d966a [android] Show a toast when an image could not be attached 2018-12-06 17:56:02 -02:00
Torsten Grote
d6c18db9e9 [android] set image preview size to 1/4 of screen height 2018-12-06 17:56:02 -02:00
Torsten Grote
8fe49d9961 [android] Re-factor TextInputViews 2018-12-06 17:56:02 -02:00
Torsten Grote
f536cfdab8 [android] first round of review comments for attaching images 2018-12-06 17:56:02 -02:00
Torsten Grote
4d594acad5 [android] Save attached (but not sent) image on screen rotation 2018-12-06 17:56:02 -02:00
Torsten Grote
800dfed5c1 [android] support adding image attachments to private messages 2018-12-06 17:55:59 -02:00
Jordi Salvat
54b823e401 [android] fix start of link in error message for adding contacts 2018-12-06 20:44:36 +01:00
Torsten Grote
52ec56d690 Merge branch 'invalid-slide-direction' into 'master'
Revert change to slide direction

Closes #1478

See merge request briar/briar!1009
2018-12-06 15:32:07 +00:00
akwizgran
7b3afcca99 Revert change to slide direction. 2018-12-06 15:18:16 +00:00
Torsten Grote
a22d03d028 [headless] wait for lifecycle manager to finish starting
before starting web server
2018-12-05 16:08:03 -02:00
Torsten Grote
d857338ad0 [headless] Add first integration test for ContactController 2018-12-05 16:04:14 -02:00
akwizgran
a5c9e7c74d Merge branch '1242-display-image-attachments-fullscreen' into 'master'
Add ImageActivity to show image attachment in full-screen

See merge request briar/briar!999
2018-11-30 18:04:55 +00:00
Torsten Grote
8a4a343147 [android] Move image to the top if it is overlapping the toolbar 2018-11-30 15:53:38 -02:00
akwizgran
dcd5e34c6b Improve UI hiding behaviour. 2018-11-30 12:40:45 +00:00
Torsten Grote
7b22d3b84d [android] Address review issues for image fullscreen view 2018-11-28 17:26:01 -02:00
Torsten Grote
c8fa23273f [android] support pull down to dismiss pattern for ImageActivity 2018-11-28 17:26:01 -02:00
Torsten Grote
fbe5df8938 [android] Add ImageActivity to show images in full-screen 2018-11-28 17:26:01 -02:00
akwizgran
008cf95741 Merge branch '1467-conversation-scrolling' into 'master'
Only scroll conversation list to bottom, when already at bottom

Closes #1467

See merge request briar/briar!1000
2018-11-27 09:32:05 +00:00
Torsten Grote
3eb066a836 [android] Use new IoUtils to close InputStreams 2018-11-26 16:28:06 -02:00
Torsten Grote
674b29af25 [android] static constant all caps 2018-11-26 16:23:51 -02:00
Torsten Grote
b8ca5ab557 [android] Only scroll conversation list to bottom, when already at bottom
Closes #1467
2018-11-26 16:23:17 -02:00
Torsten Grote
6e17709f46 Merge branch 'try-to-close' into 'master'
Move tryToClose() methods into utility classes

See merge request briar/briar!1002
2018-11-26 18:22:24 +00:00
akwizgran
726d90145c Merge branch '1242-display-image-attachments' into 'master'
[android] display image attachments for conversation messages

See merge request briar/briar!997
2018-11-26 17:19:37 +00:00
Torsten Grote
165211eb9b Merge branch '1259-headless-mac-os' into 'master'
Enable headless app to start on MacOS

See merge request briar/briar!1003
2018-11-26 12:01:27 +00:00
akwizgran
868c61e5d6 Move tryToClose() methods into utility classes. 2018-11-23 15:02:27 +00:00
Torsten Grote
798bb6d4f7 [android] scale thumbnails to minimum size, don't upscale to maximum size 2018-11-23 11:25:18 -02:00
akwizgran
bc352a2dc6 Enable Tor on Mac OS once binaries are available. 2018-11-23 13:07:12 +00:00
akwizgran
ce7d6d3db5 Code cleanup. 2018-11-23 12:56:34 +00:00
akwizgran
61276c81d2 Make it possible to start the headless app on MacOS.
The app is still non-functional because we don't have a Tor plugin.
2018-11-23 12:52:40 +00:00
Torsten Grote
c09abdb088 Merge branch 'location-permission-sdk-23' into 'master'
Change location permission to uses-permission-sdk-23

See merge request briar/briar!1001
2018-11-22 12:03:07 +00:00
akwizgran
45a11badd5 Change location permission to uses-permission-sdk-23. 2018-11-20 16:16:47 +00:00
Torsten Grote
152ac3df43 [android] improve bitmap transformation hashKey and DiskCacheKey 2018-11-20 11:49:21 -02:00
Torsten Grote
dd5ad86db8 [android] Use DataFetcherFactory to create data fetchers and allow cancelling loads 2018-11-20 11:49:21 -02:00
Torsten Grote
10e9fb308d [android] Display Image Attachements: Address first round of review comments 2018-11-19 20:35:07 -02:00
Torsten Grote
de8e95692a [android] support RTL languages when rounding thumbnail corners 2018-11-19 20:35:07 -02:00
Torsten Grote
d6b52cf4ec [android] Use our own BitmapTransformation for rounded image corners 2018-11-19 20:35:07 -02:00
Torsten Grote
8a839fb5e4 [android] display image attachments for conversation messages 2018-11-19 20:35:07 -02:00
akwizgran
fbf8642edb Merge branch '1464-message-status-mixed' into 'master'
[core] fix wrong order of message status flags in conversation headers

Closes #1464

See merge request briar/briar!998
2018-11-16 13:44:39 +00:00
Torsten Grote
ade6a14342 Merge branch 'validation-refactoring' into 'master'
Reorganise validation code

See merge request briar/briar!991
2018-11-15 17:18:15 +00:00
Torsten Grote
d500ff81c3 Merge branch 'require-non-null' into 'master'
Add static requireNonNull() method

See merge request briar/briar!996
2018-11-15 16:50:16 +00:00
Torsten Grote
3053e3cfa7 [core] fix wrong order of message status flags in conversation headers 2018-11-15 14:39:05 -02:00
akwizgran
6964a67ca3 Add static requireNonNull() method. 2018-11-15 11:13:15 +00:00
Torsten Grote
f4b06e1fb3 Merge branch 'load-latest-message-eagerly' into 'master'
Load latest message eagerly

See merge request briar/briar!995
2018-11-14 16:01:59 +00:00
akwizgran
4db075d643 Only consider the latest item for preloading. 2018-11-14 15:13:25 +00:00
akwizgran
78a8ae6b8e Sort headers and eagerly load text of latest message. 2018-11-14 15:01:54 +00:00
Torsten Grote
7866037d02 Merge branch '1460-introduction-request-text' into 'master'
Show correct text when an existing contact is introduced

Closes #1460

See merge request briar/briar!994
2018-11-14 11:23:26 +00:00
akwizgran
35716051fb Show correct text when an existing contact is introduced. 2018-11-14 11:05:46 +00:00
Torsten Grote
6cafea836f Merge branch 'eager-singletons' into 'master'
Singletons that call registration methods must be eager

See merge request briar/briar!993
2018-11-13 18:03:28 +00:00
akwizgran
bd0fd229c6 Merge branch '1242-attachment-input-stream' into 'master'
Attachments will use InputStream rather than ByteBuffer

See merge request briar/briar!992
2018-11-13 17:41:39 +00:00
akwizgran
ea05a5c703 Singletons that call registration methods must be eager. 2018-11-13 17:40:06 +00:00
akwizgran
4103eaf639 Reorganise validation code (no functional changes). 2018-11-13 17:16:47 +00:00
Torsten Grote
753a25bc2a [core] Attachments will use InputStream rather than ByteBuffer 2018-11-13 15:12:34 -02:00
akwizgran
8f4c3c4528 Bump version numbers for 1.1.5 release. 2018-11-13 13:01:01 +00:00
akwizgran
636a7dfe72 Update translations. 2018-11-13 12:59:51 +00:00
akwizgran
08e99edd42 Merge branch 'unpack-tor-binaries' into 'master'
Always unpack and include latest Tor binaries

See merge request briar/briar!987
2018-11-13 12:56:47 +00:00
akwizgran
e28bc475df Merge branch '1242-optional-message-text' into 'master'
Add support for private messages without text

See merge request briar/briar!990
2018-11-13 10:47:52 +00:00
Torsten Grote
88276a4d44 Add support for private messages without text 2018-11-12 18:11:03 -02:00
akwizgran
f9987c89df Merge branch 'disable-tor-connection-padding' into 'master'
Disable Tor's connection padding

See merge request briar/briar!989
2018-11-12 14:03:22 +00:00
Torsten Grote
2c8cb8301f Merge branch '1455-stream-context-may-be-null' into 'master'
Stream context may be null

Closes #1455

See merge request briar/briar!988
2018-11-12 12:50:01 +00:00
akwizgran
c00ee80f0f Update test expectations. 2018-11-12 12:20:04 +00:00
akwizgran
3bfedfdc3d Add action for nullable DB callables. 2018-11-12 12:16:42 +00:00
akwizgran
ecb63d1acb Add interface for DB tasks will nullable results. 2018-11-12 12:13:26 +00:00
akwizgran
b24914408d Stream context may be null. 2018-11-12 11:31:59 +00:00
akwizgran
5ede63edd5 Always unpack and include latest Tor binaries. 2018-11-08 17:48:26 +00:00
akwizgran
4e523c5fbc Merge branch '1242-display-image-attachments' into 'master'
[android] refactor conversation items and view holders

See merge request briar/briar!984
2018-11-08 16:08:58 +00:00
akwizgran
cf79ed5633 IntentFilter may not be thread-safe. 2018-11-08 14:54:53 +00:00
akwizgran
0a0a6a6369 Disable Tor's connection padding on mobile data or battery. 2018-11-08 14:50:36 +00:00
akwizgran
4784980e7b No need to broadcast network status at startup. 2018-11-08 14:50:36 +00:00
akwizgran
3bfa5e2081 [android] Move ConversationListener to top level. 2018-11-08 10:27:36 -02:00
akwizgran
f2b09deac4 [android] Remove type parameter from view holders. 2018-11-08 10:27:29 -02:00
Torsten Grote
ad4729b2f9 [android] refactor conversation items and view holders
This is a preparation for image support.
2018-11-08 10:27:29 -02:00
akwizgran
50cc0a6815 Merge branch '1452-websocket-authentication' into 'master'
[headless] change websocket authentication from basic auth to token message

Closes #1452

See merge request briar/briar!986
2018-11-08 12:26:53 +00:00
Torsten Grote
32c8ac6576 [headless] change websocket authentication from basic auth to token message 2018-11-08 10:15:17 -02:00
akwizgran
c12422d949 Merge branch '1434-android-conversation-package' into 'master'
Move conversation classes into their own package

See merge request briar/briar!978
2018-11-08 11:01:36 +00:00
akwizgran
3841713c18 Merge branch 'upgrade_roboletric_to_401' into 'master'
Upgrade robolectric to 4.0.1

See merge request briar/briar!980
2018-11-08 11:00:08 +00:00
akwizgran
79232eb558 Merge branch 'headless-fixes' into 'master'
Headless fixes

See merge request briar/briar!985
2018-11-08 10:55:28 +00:00
Torsten Grote
d02b30e751 Merge branch 'use-transactional-db-api' into 'master'
Use transactional database API in Bramble

See merge request briar/briar!974
2018-11-07 19:06:26 +00:00
akwizgran
043662a092 Code cleanup. 2018-11-07 18:31:07 +00:00
Torsten Grote
efc85fb88f [headless] don't use putAll for a single field 2018-11-07 15:24:20 -03:00
Torsten Grote
8b3983ef9e [headless] only offload to DatabaseExecutor when needed
when receiving a new conversation message
2018-11-07 15:24:20 -03:00
Torsten Grote
6766fb76b2 [headless] upgrade javalin and mockk 2018-11-07 15:18:46 -03:00
Torsten Grote
7f74bd1c38 [headless] Use --user for websocket example request
The authentication token can contain slashes.
When used as part of the URL, the URL becomes invalid.
Therefore, using curl's user parameter is preferrable.
2018-11-07 15:18:46 -03:00
akwizgran
951ee30b95 Update tests. 2018-11-07 18:18:30 +00:00
akwizgran
c386a0f5eb Replace Maybe with nullable transaction method. 2018-11-07 18:18:30 +00:00
akwizgran
52c778dce3 Reformat code. 2018-11-07 18:18:27 +00:00
akwizgran
e846a13f50 Use transactional database API in Bramble. 2018-11-07 18:14:10 +00:00
akwizgran
23e9b119d1 Merge branch '1434-message-attachments' into 'master'
Add attachment API for sending/retreiving private messages

See merge request briar/briar!976
2018-11-07 18:08:36 +00:00
akwizgran
e6f380296f Merge branch '1451-briar-headless-test-other-modules' into 'master'
[headless] Limit tests in Android Studio to headless package

Closes #1451

See merge request briar/briar!983
2018-11-07 17:47:37 +00:00
Torsten Grote
794fb9686b [headless] Limit tests in Android Studio to headless package 2018-11-07 13:46:49 -03:00
Torsten Grote
bb22b9db10 Merge branch 'remove-hamcrest-dependencies' into 'master'
Remove redundant dependency declarations

See merge request briar/briar!981
2018-11-07 16:37:30 +00:00
Julian Dehm
d4f015d054 Upgrade robolectric to 4.0.1 2018-11-07 17:11:21 +01:00
akwizgran
41e5d8900c Remove redundant dependency declarations. 2018-11-07 16:10:39 +00:00
Torsten Grote
c3cb966009 [android] move conversation classes into their own package 2018-11-07 11:48:20 -03:00
Torsten Grote
f964d1ef07 Fix receivers of ConversationMessageReceivedEvent
These were only listening to private message events, ignoring all others
2018-11-07 11:34:11 -03:00
Torsten Grote
cccaeeda6c [core] Add API to add messages with attachments 2018-11-07 11:34:11 -03:00
Torsten Grote
483106e00c [core] Add MessagingManager#getAttachment() 2018-11-07 11:34:11 -03:00
Torsten Grote
934f14ef31 [core] Add attachment support to private messages 2018-11-07 11:34:09 -03:00
Torsten Grote
e3abff5ad8 Refactor PrivateMessageHeader to ConversationMessageHeader base-class
This is preparation for adding attachments to private messages
2018-11-07 11:33:37 -03:00
Torsten Grote
391732b239 Merge branch 'change-contact-name' into 'master'
Change button text to match name of action

See merge request briar/briar!979
2018-11-07 12:11:22 +00:00
akwizgran
4738bfdd85 Ignore missing translations. 2018-11-07 10:43:13 +00:00
akwizgran
be1ca89309 Change button text to match name of action. 2018-11-07 10:40:59 +00:00
Torsten Grote
866be99179 Merge branch '41-alias-frontend' into 'master'
Add UI for changing contact aliases

Closes #41

See merge request briar/briar!965
2018-11-06 18:09:47 +00:00
akwizgran
48822e2133 Merge branch '1381-introduction-test-fails' into 'master'
Fix non-determinism of Introduction integration tests

Closes #1381

See merge request briar/briar!970
2018-11-06 18:00:48 +00:00
Torsten Grote
6883c5caa9 [android] address last contact aliases review issues 2018-11-06 14:57:39 -03:00
Torsten Grote
8b709969ab [android] pass ContactId via ViewModel to AliasDialogFragment 2018-11-06 13:42:51 -03:00
Torsten Grote
fe94b65b3b [android] Fix double loading of conversation messages when rotating screen 2018-11-06 13:42:51 -03:00
akwizgran
f54df1d787 Reduce visibility, remove unnecessary rethrow. 2018-11-06 13:42:51 -03:00
akwizgran
a7e826ccf5 Remove qualification from java.lang.Runnable. 2018-11-06 13:42:51 -03:00
akwizgran
845eb3262b Use expression lambda. 2018-11-06 13:42:51 -03:00
akwizgran
0a46ad439f Check whether activity is null. 2018-11-06 13:42:51 -03:00
akwizgran
d14d93ea35 Require observed data to be non-null. 2018-11-06 13:42:51 -03:00
akwizgran
12a1cf8f8b Reuse Observer interface. 2018-11-06 13:42:51 -03:00
akwizgran
fb2ab861db Fix some lint warnings. 2018-11-06 13:42:51 -03:00
Torsten Grote
aa15b68d24 [android] Reload conversation when contact name changes 2018-11-06 13:42:51 -03:00
Torsten Grote
7059f376f1 [android] Add UI for changing contact alias
This introduces the first ViewModel to share state between the
ConversationActivity and the AliasDialogFragment.
2018-11-06 13:42:51 -03:00
akwizgran
9313c191c1 Merge branch 'ui-fixes' into 'master'
Small UI fixes

See merge request briar/briar!975
2018-11-05 10:40:09 +00:00
akwizgran
7746364ae9 Merge branch '1437-reversed-emoji' into 'master'
[android] Add new emojis to the beginning of the list of recently used ones

Closes #1437

See merge request briar/briar!977
2018-11-05 10:27:03 +00:00
Torsten Grote
7429857b28 [android] Add new emojis to the beginning of the list of recently used ones
Otherwise the list will be reversed with most recently used at the end.
2018-11-04 11:08:05 -03:00
Torsten Grote
4db64f51a8 [android] Use same color for all messages in private groups 2018-11-02 15:59:49 -03:00
Torsten Grote
78172038ef [android] Always center selectable contacts vertically 2018-11-02 15:38:01 -03:00
Torsten Grote
7d0c418877 [android] Align short incoming messages on the left 2018-11-02 15:37:16 -03:00
Torsten Grote
5ae4f8f6cb [core] Fix non-determism in GroupInvitationIntegrationTest 2018-11-02 14:08:42 -03:00
Torsten Grote
45dd10db9d [core] Fix non-determinism in introduction integration tests 2018-11-02 14:08:42 -03:00
Torsten Grote
5cc8c268ca [core] Re-add message counter and put debug output behind flag 2018-11-02 14:08:42 -03:00
akwizgran
93a6bf2f52 Add logging to debug test failures. 2018-11-02 12:48:23 -03:00
akwizgran
852dd46a1b Utility class for converting BDF to strings.
(cherry picked from commit 9e94917)
2018-11-02 12:48:23 -03:00
Torsten Grote
4a42e767d3 [core] Add a detector for message delivery non-determinism 2018-11-02 12:48:13 -03:00
akwizgran
8547b4dc91 Merge branch 'upgrade-dagger' into 'master'
Upgrade dagger

See merge request briar/briar!973
2018-11-01 14:17:35 +00:00
akwizgran
f6c8a8cec7 Move dagger.gradle to project root. 2018-11-01 14:05:46 +00:00
Torsten Grote
db8796049e gradle: Factor out dagger apt code into its own file 2018-11-01 10:45:59 -03:00
Torsten Grote
e1f31ad381 Remove gradle-apt-plugin since it isn't stricly needed anymore
Reference: 6b2ee87fbf/README.md
2018-10-31 16:01:57 -03:00
Torsten Grote
3a15e47ddd Upgrade Dagger to latest version 2018-10-31 15:57:21 -03:00
Torsten Grote
cf616905d6 Merge branch 'introduction-manager-skip-session-parsing' into 'master'
Avoid some unnecessary session parsing when retrieving introduction messages

See merge request briar/briar!972
2018-10-31 16:36:59 +00:00
akwizgran
d3f774f339 Avoid some unnecessary session parsing. 2018-10-31 16:18:33 +00:00
akwizgran
6c7c488892 Merge branch '41-alias-frontend-base' into 'master'
[android] Show contact aliases in UI

See merge request briar/briar!971
2018-10-31 16:16:38 +00:00
Torsten Grote
3fe7aae97e Contact aliases: address review comments 2018-10-31 13:06:19 -03:00
Torsten Grote
ecf417c93b [android] Show contact alias in remaining places 2018-10-31 13:06:19 -03:00
Torsten Grote
c1785c5b13 [android] Show contact alias in contact lists 2018-10-31 13:06:19 -03:00
Torsten Grote
fb2c321a3d [android] Show contact alias inside private groups and their memberlist 2018-10-31 13:06:19 -03:00
Torsten Grote
6e3adc0874 Show alias for introduction notices in private conversation 2018-10-31 13:06:19 -03:00
Torsten Grote
cdbe2a00f5 [android] Show alias for creator of private group in list of private groups 2018-10-31 11:40:17 -03:00
Torsten Grote
a51dc7e0d5 [android] Show Author alias in AuthorView 2018-10-31 11:40:15 -03:00
Torsten Grote
0ee7465429 Merge branch '41-alias-author-info' into 'master'
Refactor Author.Status into dedicated AuthorInfo class and add alias

See merge request briar/briar!968
2018-10-30 19:33:39 +00:00
Torsten Grote
7c202189a2 [bramble] Implement equals() and hashCode() for AuthorView 2018-10-30 15:21:09 -03:00
akwizgran
da3b2c1591 Merge branch '41-alias-backend' into 'master'
Add backend support for contact aliases

See merge request briar/briar!963
2018-10-30 16:43:52 +00:00
Torsten Grote
6c5e8ce4cf Rename remaining occurrences of status to authorInfo 2018-10-30 13:40:04 -03:00
Torsten Grote
ca700d8d23 [bramble] address review comments 2018-10-30 13:32:56 -03:00
akwizgran
db11dad61e Merge branch 'clean-tor-binaries' into 'master'
Delete Tor binaries when cleaning

See merge request briar/briar!969
2018-10-30 13:59:21 +00:00
akwizgran
69e7366226 Merge branch '1433-illegal-characters' into 'master'
Handle illegal byte sequences safely in BdfReaderImpl

Closes #1433

See merge request briar/briar!967
2018-10-30 13:58:36 +00:00
akwizgran
90b7b4e67f Merge branch '1416-obfs4' into 'master'
Add obfs4proxy and switch to obfs4 bridges

Closes #1417

See merge request briar/briar!964
2018-10-30 13:58:13 +00:00
akwizgran
d29812a42b Delete Tor binaries when cleaning. 2018-10-30 13:06:06 +00: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
akwizgran
2db2a1a208 Replace a slow bridge with a faster one. 2018-10-29 17:25:12 +00:00
akwizgran
0d7e4feaf2 Throw AssertionError to make intent clearer. 2018-10-29 17:02:07 +00:00
akwizgran
eb3983f6b2 Use safe ASCII decoding in ModemImpl. 2018-10-29 16:48:18 +00:00
akwizgran
e2ce49c30e Use safe UTF-8 decoding in BdfReaderImpl. 2018-10-29 16:47:55 +00:00
akwizgran
adc6fb2fd5 Add fuzzing test for illegal UTF-8 byte sequences. 2018-10-29 16:44:02 +00: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
Torsten Grote
ca6dc33cdd Add obfs4 proxy and switch to obfs4 bridges 2018-10-25 09:38:44 -03:00
685 changed files with 14463 additions and 6976 deletions

View File

@@ -3,7 +3,7 @@
<module name="briar-headless" /> <module name="briar-headless" />
<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="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />

View File

@@ -1,3 +1,5 @@
import com.android.build.gradle.tasks.MergeResources
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
@@ -9,8 +11,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10104 versionCode 10105
versionName "1.1.4" versionName "1.1.5"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -29,8 +31,9 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.4.8@zip' tor 'org.briarproject:tor-android:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -39,13 +42,29 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
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-core:1.3"
} }
project.afterEvaluate { def torBinariesDir = 'src/main/res/raw'
copy {
from configurations.tor.collect { zipTree(it) } task cleanTorBinaries {
into 'src/main/res/raw' doLast {
delete fileTree(torBinariesDir) { include '*.zip' }
} }
} }
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
public interface BrambleAndroidEagerSingletons {
void inject(AndroidBatteryModule.EagerSingletons init);
void inject(AndroidNetworkModule.EagerSingletons init);
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule; import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule; import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidSystemModule;
@@ -7,10 +8,15 @@ import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module; import dagger.Module;
@Module(includes = { @Module(includes = {
AndroidBatteryModule.class,
AndroidNetworkModule.class, AndroidNetworkModule.class,
AndroidSystemModule.class, AndroidSystemModule.class,
CircumventionModule.class CircumventionModule.class
}) })
public class BrambleAndroidModule { public class BrambleAndroidModule {
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
c.inject(new AndroidBatteryModule.EagerSingletons());
c.inject(new AndroidNetworkModule.EagerSingletons());
}
} }

View File

@@ -9,19 +9,22 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.util.IoUtils;
import java.io.File; import java.io.File;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
class AndroidAccountManager extends AccountManagerImpl class AndroidAccountManager extends AccountManagerImpl
implements AccountManager { implements AccountManager {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidAccountManager.class.getName()); getLogger(AndroidAccountManager.class.getName());
private static final String PREF_DB_KEY = "key"; private static final String PREF_DB_KEY = "key";
@@ -37,7 +40,7 @@ class AndroidAccountManager extends AccountManagerImpl
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
@Override @Override
@Nullable @Nullable
protected String loadEncryptedDatabaseKey() { protected String loadEncryptedDatabaseKey() {
@@ -47,7 +50,7 @@ class AndroidAccountManager extends AccountManagerImpl
return key; return key;
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
@Nullable @Nullable
private String getDatabaseKeyFromPreferences() { private String getDatabaseKeyFromPreferences() {
String key = prefs.getString(PREF_DB_KEY, null); String key = prefs.getString(PREF_DB_KEY, null);
@@ -56,7 +59,7 @@ class AndroidAccountManager extends AccountManagerImpl
return key; return key;
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
private void migrateDatabaseKeyToFile(String key) { private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) { if (storeEncryptedDatabaseKey(key)) {
if (prefs.edit().remove(PREF_DB_KEY).commit()) if (prefs.edit().remove(PREF_DB_KEY).commit())
@@ -81,7 +84,7 @@ class AndroidAccountManager extends AccountManagerImpl
return PreferenceManager.getDefaultSharedPreferences(appContext); return PreferenceManager.getDefaultSharedPreferences(appContext);
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
private void deleteAppData(SharedPreferences... clear) { private void deleteAppData(SharedPreferences... clear) {
// Clear and commit shared preferences // Clear and commit shared preferences
for (SharedPreferences prefs : clear) { for (SharedPreferences prefs : clear) {
@@ -97,7 +100,7 @@ class AndroidAccountManager extends AccountManagerImpl
for (File child : children) { for (File child : children) {
String name = child.getName(); String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) { if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child); deleteFileOrDir(child);
} }
} }
} }

View File

@@ -0,0 +1,81 @@
package org.briarproject.bramble.battery;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
class AndroidBatteryManager implements BatteryManager, Service {
private static final Logger LOG =
getLogger(AndroidBatteryManager.class.getName());
private final Context appContext;
private final EventBus eventBus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver batteryReceiver = null;
@Inject
AndroidBatteryManager(Application app, EventBus eventBus) {
this.appContext = app.getApplicationContext();
this.eventBus = eventBus;
}
@Override
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_PLUGGED, 0);
return status != 0;
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
batteryReceiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
appContext.registerReceiver(batteryReceiver, filter);
}
@Override
public void stopService() {
if (batteryReceiver != null)
appContext.unregisterReceiver(batteryReceiver);
}
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
if (ACTION_POWER_CONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(true));
else if (ACTION_POWER_DISCONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(false));
}
}
}

View File

@@ -0,0 +1,27 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidBatteryModule {
public static class EagerSingletons {
@Inject
BatteryManager batteryManager;
}
@Provides
@Singleton
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
AndroidBatteryManager batteryManager) {
lifecycleManager.registerService(batteryManager);
return batteryManager;
}
}

View File

@@ -13,8 +13,7 @@ import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus; import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent; import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.Scheduler; import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@@ -34,16 +33,17 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault @NotNullByDefault
@ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service { class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidNetworkManager.class.getName()); getLogger(AndroidNetworkManager.class.getName());
// See android.net.wifi.WifiManager // See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION = private static final String WIFI_AP_STATE_CHANGED_ACTION =
@@ -56,6 +56,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
new AtomicReference<>(); new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false); private final AtomicBoolean used = new AtomicBoolean(false);
@Nullable
private volatile BroadcastReceiver networkStateReceiver = null; private volatile BroadcastReceiver networkStateReceiver = null;
@Inject @Inject
@@ -89,9 +90,8 @@ class AndroidNetworkManager implements NetworkManager, Service {
@Override @Override
public NetworkStatus getNetworkStatus() { public NetworkStatus getNetworkStatus() {
ConnectivityManager cm = (ConnectivityManager) ConnectivityManager cm = (ConnectivityManager) requireNonNull(
appContext.getSystemService(CONNECTIVITY_SERVICE); appContext.getSystemService(CONNECTIVITY_SERVICE));
if (cm == null) throw new AssertionError();
NetworkInfo net = cm.getActiveNetworkInfo(); NetworkInfo net = cm.getActiveNetworkInfo();
boolean connected = net != null && net.isConnected(); boolean connected = net != null && net.isConnected();
boolean wifi = connected && net.getType() == TYPE_WIFI; boolean wifi = connected && net.getType() == TYPE_WIFI;

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
@@ -11,6 +12,11 @@ import dagger.Provides;
@Module @Module
public class AndroidNetworkModule { public class AndroidNetworkModule {
public static class EagerSingletons {
@Inject
NetworkManager networkManager;
}
@Provides @Provides
@Singleton @Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager, NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,

View File

@@ -18,13 +18,12 @@ 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.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
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.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
@@ -48,10 +47,11 @@ 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.ACTION_FOUND;
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE; import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.Collections.shuffle;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
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 java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -59,7 +59,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> { class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidBluetoothPlugin.class.getName()); getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000; private static final int MAX_DISCOVERY_MS = 10_000;
@@ -161,11 +161,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
@Override @Override
void tryToClose(@Nullable BluetoothServerSocket ss) { void tryToClose(@Nullable BluetoothServerSocket ss) {
try { IoUtils.tryToClose(ss, LOG, WARNING);
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
} }
@Override @Override
@@ -195,7 +191,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
s.connect(); s.connect();
return wrapSocket(s); return wrapSocket(s);
} catch (IOException e) { } catch (IOException e) {
tryToClose(s); IoUtils.tryToClose(s, LOG, WARNING);
throw e; throw e;
} }
} }
@@ -264,18 +260,10 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
appContext.unregisterReceiver(receiver); appContext.unregisterReceiver(receiver);
} }
// Shuffle the addresses so we don't always try the same one first // Shuffle the addresses so we don't always try the same one first
Collections.shuffle(addresses); shuffle(addresses);
return addresses; return addresses;
} }
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private class BluetoothStateReceiver extends BroadcastReceiver { private class BluetoothStateReceiver extends BroadcastReceiver {
@Override @Override

View File

@@ -32,17 +32,19 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault @NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private static final Logger LOG =
getLogger(AndroidLanTcpPlugin.class.getName());
private static final byte[] WIFI_AP_ADDRESS_BYTES = private static final byte[] WIFI_AP_ADDRESS_BYTES =
{(byte) 192, (byte) 168, 43, 1}; {(byte) 192, (byte) 168, 43, 1};
private static final InetAddress WIFI_AP_ADDRESS; private static final InetAddress WIFI_AP_ADDRESS;
private static final Logger LOG =
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
static { static {
try { try {
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES); WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
@@ -66,10 +68,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
// Don't execute more than one connection status check at a time // Don't execute more than one connection status check at a time
connectionStatusExecutor = connectionStatusExecutor =
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1); new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
ConnectivityManager connectivityManager = (ConnectivityManager) connectivityManager = (ConnectivityManager) requireNonNull(
appContext.getSystemService(CONNECTIVITY_SERVICE); appContext.getSystemService(CONNECTIVITY_SERVICE));
if (connectivityManager == null) throw new AssertionError();
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext() wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE); .getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault(); socketFactory = SocketFactory.getDefault();

View File

@@ -6,9 +6,9 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager; import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
@@ -25,10 +25,10 @@ import javax.net.SocketFactory;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE; import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
@MethodsNotNullByDefault @NotNullByDefault
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin { class AndroidTorPlugin extends TorPlugin {
// This tag may prevent Huawei's power manager from killing us // This tag may prevent Huawei's power manager from killing us
@@ -41,17 +41,17 @@ class AndroidTorPlugin extends TorPlugin {
Context appContext, NetworkManager networkManager, Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory, LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider, Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Backoff backoff, CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency, DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) { int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory, super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff, clock, resourceProvider, circumventionProvider, batteryManager,
callback, architecture, maxLatency, maxIdleTime, backoff, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE)); appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext; this.appContext = appContext;
PowerManager pm = (PowerManager) PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE); requireNonNull(appContext.getSystemService(POWER_SERVICE));
assert pm != null;
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES); WAKE_LOCK_TAG, 1, MINUTES);
} }

View File

@@ -1,8 +1,8 @@
package org.briarproject.bramble.plugin.tor; package org.briarproject.bramble.plugin.tor;
import android.content.Context; import android.content.Context;
import android.os.Build;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -25,12 +25,15 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.logging.Logger.getLogger;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class AndroidTorPluginFactory implements DuplexPluginFactory { public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidTorPluginFactory.class.getName()); getLogger(AndroidTorPluginFactory.class.getName());
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
@@ -48,6 +51,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock; private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor, public AndroidTorPluginFactory(Executor ioExecutor,
@@ -55,7 +59,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils, NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory, EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider, BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Clock clock) { CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.scheduler = scheduler; this.scheduler = scheduler;
this.appContext = appContext; this.appContext = appContext;
@@ -66,6 +71,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock; this.clock = clock;
} }
@@ -98,14 +104,14 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
return null; return null;
} }
// Use position-independent executable for SDK >= 16 // Use position-independent executable for SDK >= 16
if (Build.VERSION.SDK_INT >= 16) architecture += "_pie"; if (SDK_INT >= 16) architecture += "_pie";
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory, appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff, clock, resourceProvider, circumventionProvider, batteryManager,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME); backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -15,12 +15,13 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static android.content.Context.TELEPHONY_SERVICE; import static android.content.Context.TELEPHONY_SERVICE;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault @NotNullByDefault
class AndroidLocationUtils implements LocationUtils { class AndroidLocationUtils implements LocationUtils {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidLocationUtils.class.getName()); getLogger(AndroidLocationUtils.class.getName());
private final Context appContext; private final Context appContext;
@@ -59,14 +60,14 @@ class AndroidLocationUtils implements LocationUtils {
} }
private String getCountryFromPhoneNetwork() { private String getCountryFromPhoneNetwork() {
Object o = appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager)
TelephonyManager tm = (TelephonyManager) o; appContext.getSystemService(TELEPHONY_SERVICE);
return tm.getNetworkCountryIso(); return tm == null ? "" : tm.getNetworkCountryIso();
} }
private String getCountryFromSimCard() { private String getCountryFromSimCard() {
Object o = appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager)
TelephonyManager tm = (TelephonyManager) o; appContext.getSystemService(TELEPHONY_SERVICE);
return tm.getSimCountryIso(); return tm == null ? "" : tm.getSimCountryIso();
} }
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.system; package org.briarproject.bramble.system;
import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
@@ -7,7 +8,6 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.StrictMode; import android.os.StrictMode;
import android.provider.Settings; import android.provider.Settings;
@@ -22,11 +22,14 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static android.content.Context.WIFI_SERVICE; import static android.content.Context.WIFI_SERVICE;
import static android.os.Build.FINGERPRINT;
import static android.os.Build.SERIAL;
import static android.os.Build.VERSION.SDK_INT;
import static android.provider.Settings.Secure.ANDROID_ID; import static android.provider.Settings.Secure.ANDROID_ID;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider { class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
private static final int SEED_LENGTH = 32; private static final int SEED_LENGTH = 32;
@@ -37,24 +40,27 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
@SuppressLint("HardwareIds")
@Override @Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException { protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out); super.writeToEntropyPool(out);
out.writeInt(android.os.Process.myPid()); out.writeInt(android.os.Process.myPid());
out.writeInt(android.os.Process.myTid()); out.writeInt(android.os.Process.myTid());
out.writeInt(android.os.Process.myUid()); out.writeInt(android.os.Process.myUid());
if (Build.FINGERPRINT != null) out.writeUTF(Build.FINGERPRINT); if (FINGERPRINT != null) out.writeUTF(FINGERPRINT);
if (Build.SERIAL != null) out.writeUTF(Build.SERIAL); if (SERIAL != null) out.writeUTF(SERIAL);
ContentResolver contentResolver = appContext.getContentResolver(); ContentResolver contentResolver = appContext.getContentResolver();
String id = Settings.Secure.getString(contentResolver, ANDROID_ID); String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id); if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
WifiManager wm = WifiManager wm = (WifiManager) appContext.getApplicationContext()
(WifiManager) appContext.getSystemService(WIFI_SERVICE); .getSystemService(WIFI_SERVICE);
List<WifiConfiguration> configs = wm.getConfiguredNetworks(); if (wm != null) {
if (configs != null) { List<WifiConfiguration> configs = wm.getConfiguredNetworks();
for (WifiConfiguration config : configs) if (configs != null) {
parcel.writeParcelable(config, 0); for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
} }
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) { if (bt != null) {
@@ -70,20 +76,18 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
// Silence strict mode // Silence strict mode
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites(); StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
super.writeSeed(); super.writeSeed();
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18) if (SDK_INT >= 16 && SDK_INT <= 18) applyOpenSslFix();
applyOpenSslFix();
StrictMode.setThreadPolicy(tp); StrictMode.setThreadPolicy(tp);
} }
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html // Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private void applyOpenSslFix() { private void applyOpenSslFix() {
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed( byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(SEED_LENGTH);
SEED_LENGTH);
try { try {
// Seed the OpenSSL PRNG // Seed the OpenSSL PRNG
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class) .getMethod("RAND_seed", byte[].class)
.invoke(null, seed); .invoke(null, (Object) seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG // Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName( int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto") "org.apache.harmony.xnet.provider.jsse.NativeCrypto")

View File

@@ -3,36 +3,35 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.CPU_ABI;
import static android.os.Build.CPU_ABI2;
import static android.os.Build.SUPPORTED_ABIS;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
public class AndroidUtils { public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
private static final String STORED_REPORTS = "dev-reports"; private static final String STORED_REPORTS = "dev-reports";
@SuppressWarnings("deprecation")
public static Collection<String> getSupportedArchitectures() { public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>(); List<String> abis = new ArrayList<>();
if (Build.VERSION.SDK_INT >= 21) { if (SDK_INT >= 21) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS)); abis.addAll(asList(SUPPORTED_ABIS));
} else { } else {
abis.add(Build.CPU_ABI); abis.add(CPU_ABI);
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2); if (CPU_ABI2 != null) abis.add(CPU_ABI2);
} }
return abis; return abis;
} }
@@ -52,7 +51,7 @@ public class AndroidUtils {
} }
private static boolean isValidBluetoothAddress(String address) { private static boolean isValidBluetoothAddress(String address) {
return !StringUtils.isNullOrEmpty(address) return !isNullOrEmpty(address)
&& BluetoothAdapter.checkBluetoothAddress(address) && BluetoothAdapter.checkBluetoothAddress(address)
&& !address.equals(FAKE_BLUETOOTH_ADDRESS); && !address.equals(FAKE_BLUETOOTH_ADDRESS);
} }

View File

@@ -10,17 +10,19 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
public class RenewableWakeLock { public class RenewableWakeLock {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(RenewableWakeLock.class.getName()); getLogger(RenewableWakeLock.class.getName());
/** /**
* Automatically release the lock this many milliseconds after it's due * Automatically release the lock this many milliseconds after it's due
@@ -36,10 +38,12 @@ public class RenewableWakeLock {
private final Runnable renewTask; private final Runnable renewTask;
private final Object lock = new Object(); private final Object lock = new Object();
@GuardedBy("lock")
@Nullable @Nullable
private PowerManager.WakeLock wakeLock; // Locking: lock private PowerManager.WakeLock wakeLock;
@GuardedBy("lock")
@Nullable @Nullable
private ScheduledFuture future; // Locking: lock private ScheduledFuture future;
public RenewableWakeLock(PowerManager powerManager, public RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduler, int levelAndFlags, String tag, ScheduledExecutorService scheduler, int levelAndFlags, String tag,

View File

@@ -31,16 +31,21 @@ dependencyVerification {
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45', 'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
'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.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825', '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.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b', 'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9', 'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'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.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596', 'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
'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',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439', 'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0', 'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.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',
@@ -63,7 +68,9 @@ dependencyVerification {
'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:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926', 'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'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',

View File

@@ -7,15 +7,13 @@ apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
dependencies { dependencies {
implementation "com.google.dagger:dagger:2.0.2" implementation "com.google.dagger:dagger:2.19"
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
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-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -1,13 +1,14 @@
package org.briarproject.bramble.api; package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import static org.briarproject.bramble.util.StringUtils.toHexString;
/** /**
* A wrapper around a byte array, to allow it to be stored in maps etc. * A wrapper around a byte array, to allow it to be stored in maps etc.
*/ */
@@ -56,8 +57,7 @@ public class Bytes implements Comparable<Bytes> {
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + return getClass().getSimpleName() + "(" + toHexString(getBytes()) + ")";
"(" + StringUtils.toHexString(getBytes()) + ")";
} }
public static class BytesComparator implements Comparator<Bytes> { public static class BytesComparator implements Comparator<Bytes> {

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -10,6 +9,8 @@ import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Collections.unmodifiableSet;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
public class Multiset<T> { public class Multiset<T> {
@@ -96,6 +97,6 @@ public class Multiset<T> {
* is unmodifiable. * is unmodifiable.
*/ */
public Set<T> keySet() { public Set<T> keySet() {
return Collections.unmodifiableSet(map.keySet()); return unmodifiableSet(map.keySet());
} }
} }

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.battery;
public interface BatteryManager {
boolean isCharging();
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.bramble.api.battery.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the device starts or stops charging.
*/
public class BatteryEvent extends Event {
private final boolean charging;
public BatteryEvent(boolean charging) {
this.charging = charging;
}
public boolean isCharging() {
return charging;
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.briar.client; package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.data.MetadataParser;
@@ -12,7 +11,7 @@ import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
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.ValidationManager.IncomingMessageHook; import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -62,5 +61,4 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
throw new InvalidMessageException(e); throw new InvalidMessageException(e);
} }
} }
} }

View File

@@ -5,10 +5,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.Collections.emptyList;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class BdfMessageContext { public class BdfMessageContext {
@@ -23,7 +24,7 @@ public class BdfMessageContext {
} }
public BdfMessageContext(BdfDictionary dictionary) { public BdfMessageContext(BdfDictionary dictionary) {
this(dictionary, Collections.emptyList()); this(dictionary, emptyList());
} }
public BdfDictionary getDictionary() { public BdfDictionary getDictionary() {

View File

@@ -9,13 +9,14 @@ 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.ValidationManager.MessageValidator; import org.briarproject.bramble.api.sync.validation.MessageValidator;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable @Immutable
@@ -23,7 +24,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
public abstract class BdfMessageValidator implements MessageValidator { public abstract class BdfMessageValidator implements MessageValidator {
protected static final Logger LOG = protected static final Logger LOG =
Logger.getLogger(BdfMessageValidator.class.getName()); getLogger(BdfMessageValidator.class.getName());
protected final ClientHelper clientHelper; protected final ClientHelper clientHelper;
protected final MetadataEncoder metadataEncoder; protected final MetadataEncoder metadataEncoder;

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,16 @@ 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;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED;
@NotNullByDefault @NotNullByDefault
public interface ContactManager { public interface ContactManager {
@@ -49,6 +54,35 @@ public interface ContactManager {
long timestamp, boolean alice, boolean verified, boolean active) long timestamp, boolean alice, boolean verified, boolean active)
throws DbException; throws DbException;
/**
* Returns the static link that needs to be sent to the contact to be added.
*/
String getRemoteContactLink();
/**
* Returns true if the given link is syntactically valid.
*/
boolean isValidRemoteContactLink(String link);
/**
* Requests a new contact to be added via the given {@code link}.
*
* @param link The link received from the contact we want to add.
* @param alias The alias the user has given this contact.
* @return A PendingContact representing the contact to be added.
*/
PendingContact addRemoteContactRequest(String link, String alias);
/**
* Returns a list of {@link PendingContact}s.
*/
Collection<PendingContact> getPendingContacts();
/**
* Removes a {@link PendingContact} that is in state {@link FAILED}.
*/
void removePendingContact(PendingContact pendingContact);
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.
*/ */
@@ -93,6 +127,18 @@ 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(Transaction txn, ContactId c, @Nullable String alias)
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 +151,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

@@ -0,0 +1,54 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class PendingContact {
public enum PendingContactState {
WAITING_FOR_CONNECTION,
CONNECTED,
ADDING_CONTACT,
FAILED
}
private final PendingContactId id;
private final String alias;
private final PendingContactState state;
private final long timestamp;
public PendingContact(PendingContactId id, String alias,
PendingContactState state, long timestamp) {
this.id = id;
this.alias = alias;
this.state = state;
this.timestamp = timestamp;
}
public String getAlias() {
return alias;
}
public PendingContactState getState() {
return state;
}
public long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof PendingContact &&
id.equals(((PendingContact) o).id);
}
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId;
public class PendingContactId extends UniqueId {
public PendingContactId(byte[] id) {
super(id);
}
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact.PendingContactState;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact's state is changed.
*/
@Immutable
@NotNullByDefault
public class PendingContactStateChangedEvent extends Event {
private final PendingContactId id;
private final PendingContactState state;
public PendingContactStateChangedEvent(PendingContactId id,
PendingContactState state) {
this.id = id;
this.state = state;
}
public PendingContactId getId() {
return id;
}
public PendingContactState getPendingContactState() {
return state;
}
}

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap; import java.util.TreeMap;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -24,9 +23,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
* ); * );
* </pre> * </pre>
*/ */
public static BdfDictionary of(Entry<String, ?>... entries) { public static BdfDictionary of(BdfEntry... entries) {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
for (Entry<String, ?> e : entries) d.put(e.getKey(), e.getValue()); for (BdfEntry e : entries) d.put(e.getKey(), e.getValue());
return d; return d;
} }

View File

@@ -4,12 +4,12 @@ import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
@NotThreadSafe @NotThreadSafe
@@ -22,7 +22,7 @@ public class BdfList extends ArrayList<Object> {
* </pre> * </pre>
*/ */
public static BdfList of(Object... items) { public static BdfList of(Object... items) {
return new BdfList(Arrays.asList(items)); return new BdfList(asList(items));
} }
public BdfList() { public BdfList() {
@@ -33,6 +33,7 @@ public class BdfList extends ArrayList<Object> {
super(items); super(items);
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isInRange(int index) { private boolean isInRange(int index) {
return index >= 0 && index < size(); return index >= 0 && index < size();
} }

View File

@@ -0,0 +1,71 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public class BdfStringUtils {
public static String toString(@Nullable Object o) throws FormatException {
return toString(o, 0);
}
private static String toString(@Nullable Object o, int indent)
throws FormatException {
if (o == null || o == NULL_VALUE) return "null";
if (o instanceof Boolean) return o.toString();
if (o instanceof Number) return o.toString();
if (o instanceof String) return "\"" + o + "\"";
if (o instanceof Bytes)
return "x" + toHexString(((Bytes) o).getBytes());
if (o instanceof byte[])
return "x" + toHexString((byte[]) o);
if (o instanceof List) {
List<?> list = (List) o;
StringBuilder sb = new StringBuilder();
sb.append("[\n");
int i = 0, size = list.size();
for (Object e : list) {
indent(sb, indent + 1);
sb.append(toString(e, indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append(']');
return sb.toString();
}
if (o instanceof Map) {
Map<?, ?> map = (Map) o;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
int i = 0, size = map.size();
for (Entry e : map.entrySet()) {
indent(sb, indent + 1);
sb.append(toString(e.getKey(), indent + 1));
sb.append(": ");
sb.append(toString(e.getValue(), indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append('}');
return sb.toString();
}
throw new FormatException();
}
private static void indent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) sb.append('\t');
}
}

View File

@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
@@ -28,8 +29,6 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/** /**
* Encapsulates the database implementation and exposes high-level operations * Encapsulates the database implementation and exposes high-level operations
* to other components. * to other components.
@@ -89,6 +88,14 @@ public interface DatabaseComponent {
<R, E extends Exception> R transactionWithResult(boolean readOnly, <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E; DbCallable<R, E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task, which may be null.
*/
@Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
NullableDbCallable<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.
@@ -366,12 +373,12 @@ public interface DatabaseComponent {
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state * For missing dependencies and dependencies in other groups, the state
* {@link State UNKNOWN} is returned. * {@link MessageState UNKNOWN} is returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m) Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
throws DbException; MessageId m) throws DbException;
/** /**
* Returns the IDs and states of all dependents of the given message. * Returns the IDs and states of all dependents of the given message.
@@ -380,15 +387,16 @@ public interface DatabaseComponent {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m) Map<MessageId, MessageState> getMessageDependents(Transaction txn,
throws DbException; MessageId m) throws DbException;
/** /**
* Gets the validation and delivery state of the given message. * Gets the validation and delivery state of the given message.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
State getMessageState(Transaction txn, MessageId m) throws DbException; MessageState getMessageState(Transaction txn, MessageId m)
throws DbException;
/** /**
* Returns the status of the given delivered message with respect to the * Returns the status of the given delivered message with respect to the
@@ -515,6 +523,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.
*/ */
@@ -529,7 +543,7 @@ public interface DatabaseComponent {
/** /**
* Sets the validation and delivery state of the given message. * Sets the validation and delivery state of the given message.
*/ */
void setMessageState(Transaction txn, MessageId m, State state) void setMessageState(Transaction txn, MessageId m, MessageState state)
throws DbException; throws DbException;
/** /**

View File

@@ -1,5 +1,8 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbCallable<R, E extends Exception> { public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E; R call(Transaction txn) throws DbException, E;

View File

@@ -1,5 +1,8 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbRunnable<E extends Exception> { public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E; void run(Transaction txn) throws DbException, E;

View File

@@ -0,0 +1,12 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface NullableDbCallable<R, E extends Exception> {
@Nullable
R call(Transaction txn) throws DbException, E;
}

View File

@@ -3,11 +3,12 @@ package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Collections.emptyList;
/** /**
* A wrapper around a database transaction. Transactions are not thread-safe. * A wrapper around a database transaction. Transactions are not thread-safe.
*/ */
@@ -53,7 +54,7 @@ public class Transaction {
* Returns any events attached to the transaction. * Returns any events attached to the transaction.
*/ */
public List<Event> getEvents() { public List<Event> getEvents() {
if (events == null) return Collections.emptyList(); if (events == null) return emptyList();
return events; return events;
} }

View File

@@ -2,12 +2,12 @@ package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.Nameable; 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 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.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;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
/** /**
* A pseudonym for a user. * A pseudonym for a user.
@@ -16,10 +16,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
@NotNullByDefault @NotNullByDefault
public class Author implements Nameable { 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.
*/ */
@@ -32,7 +28,7 @@ public class Author implements Nameable {
public Author(AuthorId id, int formatVersion, String name, public Author(AuthorId id, int formatVersion, String name,
byte[] publicKey) { byte[] publicKey) {
int nameLength = StringUtils.toUtf8(name).length; int nameLength = toUtf8(name).length;
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH) if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH) if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)

View File

@@ -0,0 +1,56 @@
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;
}
@Override
public int hashCode() {
int hashCode = status.ordinal();
if (alias != null) hashCode += alias.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
(alias == null ? info.alias == null : alias.equals(info.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

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.nullsafety;
import javax.annotation.Nullable;
@NotNullByDefault
public class NullSafety {
/**
* Stand-in for `Objects.requireNonNull()`.
*/
public static <T> T requireNonNull(@Nullable T t) {
if (t == null) throw new NullPointerException();
return t;
}
}

View File

@@ -16,6 +16,7 @@ public interface TorConstants {
String PREF_TOR_NETWORK = "network2"; String PREF_TOR_NETWORK = "network2";
String PREF_TOR_PORT = "port"; String PREF_TOR_PORT = "port";
String PREF_TOR_MOBILE = "useMobileData"; String PREF_TOR_MOBILE = "useMobileData";
String PREF_TOR_ONLY_WHEN_CHARGING = "onlyWhenCharging";
int PREF_TOR_NETWORK_AUTOMATIC = 0; int PREF_TOR_NETWORK_AUTOMATIC = 0;
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1; int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.api.plugin; package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.util.StringUtils; import static org.briarproject.bramble.util.StringUtils.toUtf8;
/** /**
* Type-safe wrapper for a namespaced string that uniquely identifies a * Type-safe wrapper for a namespaced string that uniquely identifies a
@@ -11,12 +11,12 @@ public class TransportId {
/** /**
* The maximum length of a transport identifier in UTF-8 bytes. * The maximum length of a transport identifier in UTF-8 bytes.
*/ */
public static int MAX_TRANSPORT_ID_LENGTH = 100; public static final int MAX_TRANSPORT_ID_LENGTH = 100;
private final String id; private final String id;
public TransportId(String id) { public TransportId(String id) {
int length = StringUtils.toUtf8(id).length; int length = toUtf8(id).length;
if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH) if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.id = id; this.id = id;

View File

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

View File

@@ -4,10 +4,11 @@ import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.Collections.emptyList;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class MessageContext { public class MessageContext {
@@ -22,7 +23,7 @@ public class MessageContext {
} }
public MessageContext(Metadata metadata) { public MessageContext(Metadata metadata) {
this(metadata, Collections.emptyList()); this(metadata, emptyList());
} }
public Metadata getMetadata() { public Metadata getMetadata() {

View File

@@ -1,87 +0,0 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
enum State {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
State(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static State fromValue(int value) {
for (State s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}
/**
* Registers the message validator for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the incoming message hook for the given client. The hook will
* be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}
interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}
}

View File

@@ -3,11 +3,10 @@ package org.briarproject.bramble.api.sync.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.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.validation.MessageState;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/** /**
* An event that is broadcast when a message state changed. * An event that is broadcast when a message state changed.
*/ */
@@ -17,10 +16,10 @@ public class MessageStateChangedEvent extends Event {
private final MessageId messageId; private final MessageId messageId;
private final boolean local; private final boolean local;
private final State state; private final MessageState state;
public MessageStateChangedEvent(MessageId messageId, boolean local, public MessageStateChangedEvent(MessageId messageId, boolean local,
State state) { MessageState state) {
this.messageId = messageId; this.messageId = messageId;
this.local = local; this.local = local;
this.state = state; this.state = state;
@@ -34,7 +33,7 @@ public class MessageStateChangedEvent extends Event {
return local; return local;
} }
public State getState() { public MessageState getState() {
return state; return state;
} }

View File

@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
public interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.bramble.api.sync.validation;
public enum MessageState {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
MessageState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MessageState fromValue(int value) {
for (MessageState s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
public interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
/**
* Registers the {@link MessageValidator} for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the {@link IncomingMessageHook} for the given client. The hook
* will be called once for each incoming message that passes validation.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
}

View File

@@ -38,6 +38,13 @@ public interface ClientVersioningManager {
Visibility getClientVisibility(Transaction txn, ContactId contactId, Visibility getClientVisibility(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException; ClientId clientId, int majorVersion) throws DbException;
/**
* Returns the minor version of the given client that is supported by the
* given contact, or -1 if the contact does not support the client.
*/
int getClientMinorVersion(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException;
interface ClientVersioningHook { interface ClientVersioningHook {
void onClientVisibilityChanging(Transaction txn, Contact c, void onClientVisibilityChanging(Transaction txn, Contact c,

View File

@@ -8,17 +8,21 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault @NotNullByDefault
public class IoUtils { public class IoUtils {
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName()); private static final Logger LOG = getLogger(IoUtils.class.getName());
public static void deleteFileOrDir(File f) { public static void deleteFileOrDir(File f) {
if (f.isFile()) { if (f.isFile()) {
@@ -54,16 +58,35 @@ public class IoUtils {
out.flush(); out.flush();
out.close(); out.close();
} catch (IOException e) { } catch (IOException e) {
tryToClose(in); tryToClose(in, LOG, WARNING);
tryToClose(out); tryToClose(out, LOG, WARNING);
} }
} }
private static void tryToClose(@Nullable Closeable c) { public static void tryToClose(@Nullable Closeable c, Logger logger,
Level level) {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
// We did our best logException(logger, level, e);
}
}
public static void tryToClose(@Nullable Socket s, Logger logger,
Level level) {
try {
if (s != null) s.close();
} catch (IOException e) {
logException(logger, level, e);
}
}
public static void tryToClose(@Nullable ServerSocket ss, Logger logger,
Level level) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(logger, level, e);
} }
} }

View File

@@ -10,8 +10,6 @@ public class OsUtils {
@Nullable @Nullable
private static final String os = System.getProperty("os.name"); private static final String os = System.getProperty("os.name");
@Nullable @Nullable
private static final String version = System.getProperty("os.version");
@Nullable
private static final String vendor = System.getProperty("java.vendor"); private static final String vendor = System.getProperty("java.vendor");
public static boolean isWindows() { public static boolean isWindows() {

View File

@@ -47,7 +47,7 @@ public class StringUtils {
try { try {
return s.getBytes("UTF-8"); return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new AssertionError(e);
} }
} }
@@ -63,7 +63,7 @@ public class StringUtils {
try { try {
return decoder.decode(buffer).toString(); return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) { } catch (CharacterCodingException e) {
throw new RuntimeException(e); throw new AssertionError(e);
} }
} }

View File

@@ -7,13 +7,15 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@NotNullByDefault @NotNullByDefault
public class ValidationUtils { public class ValidationUtils {
public static void checkLength(@Nullable String s, int minLength, public static void checkLength(@Nullable String s, int minLength,
int maxLength) throws FormatException { int maxLength) throws FormatException {
if (s != null) { if (s != null) {
int length = StringUtils.toUtf8(s).length; int length = toUtf8(s).length;
if (length < minLength) throw new FormatException(); if (length < minLength) throw new FormatException();
if (length > maxLength) throw new FormatException(); if (length > maxLength) throw new FormatException();
} }
@@ -21,7 +23,7 @@ public class ValidationUtils {
public static void checkLength(@Nullable String s, int length) public static void checkLength(@Nullable String s, int length)
throws FormatException { throws FormatException {
if (s != null && StringUtils.toUtf8(s).length != length) if (s != null && toUtf8(s).length != length)
throw new FormatException(); throw new FormatException();
} }

View File

@@ -8,6 +8,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -19,15 +20,15 @@ public class BdfDictionaryTest extends BrambleTestCase {
public void testConstructors() { public void testConstructors() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
new BdfDictionary()); new BdfDictionary());
assertEquals(Collections.singletonMap("foo", NULL_VALUE), assertEquals(singletonMap("foo", NULL_VALUE),
new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE))); new BdfDictionary(singletonMap("foo", NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
BdfDictionary.of()); BdfDictionary.of());
assertEquals(Collections.singletonMap("foo", NULL_VALUE), assertEquals(singletonMap("foo", NULL_VALUE),
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE))); BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
} }
@@ -67,7 +68,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testKeySetIteratorIsOrderedByKeys() throws Exception { public void testKeySetIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -86,7 +87,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testValuesIteratorIsOrderedByKeys() throws Exception { public void testValuesIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -105,7 +106,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testEntrySetIteratorIsOrderedByKeys() throws Exception { public void testEntrySetIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);

View File

@@ -5,26 +5,31 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays; import java.util.Random;
import java.util.Collections;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
public class BdfListTest extends BrambleTestCase { public class BdfListTest extends BrambleTestCase {
private final Random random = new Random();
@Test @Test
public void testConstructors() { public void testConstructors() {
assertEquals(Collections.emptyList(), new BdfList()); assertEquals(emptyList(), new BdfList());
assertEquals(Arrays.asList(1, 2, NULL_VALUE), assertEquals(asList(1, 2, NULL_VALUE),
new BdfList(Arrays.asList(1, 2, NULL_VALUE))); new BdfList(asList(1, 2, NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(Collections.emptyList(), BdfList.of()); assertEquals(emptyList(), BdfList.of());
assertEquals(Arrays.asList(1, 2, NULL_VALUE), assertEquals(asList(1, 2, NULL_VALUE),
BdfList.of(1, 2, NULL_VALUE)); BdfList.of(1, 2, NULL_VALUE));
} }
@@ -64,22 +69,21 @@ public class BdfListTest extends BrambleTestCase {
} }
@Test @Test
@SuppressWarnings("ConstantConditions") public void testIndexOutOfBoundsReturnsDefaultValue() {
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3); BdfList list = BdfList.of(1, 2, 3);
boolean defaultBoolean = true; boolean defaultBoolean = random.nextBoolean();
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean)); assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean)); assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
Long defaultLong = 123L; Long defaultLong = random.nextLong();
assertEquals(defaultLong, list.getLong(-1, defaultLong)); assertEquals(defaultLong, list.getLong(-1, defaultLong));
assertEquals(defaultLong, list.getLong(3, defaultLong)); assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23; Double defaultDouble = random.nextDouble();
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble)); assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
assertEquals(defaultDouble, list.getDouble(3, defaultDouble)); assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
String defaultString = "123"; String defaultString = getRandomString(123);
assertEquals(defaultString, list.getString(-1, defaultString)); assertEquals(defaultString, list.getString(-1, defaultString));
assertEquals(defaultString, list.getString(3, defaultString)); assertEquals(defaultString, list.getString(3, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3}; byte[] defaultBytes = getRandomBytes(123);
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes)); assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes)); assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3); BdfList defaultList = BdfList.of(1, 2, 3);
@@ -95,18 +99,17 @@ public class BdfListTest extends BrambleTestCase {
} }
@Test @Test
@SuppressWarnings("ConstantConditions") public void testWrongTypeReturnsDefaultValue() {
public void testWrongTypeReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3, true); BdfList list = BdfList.of(1, 2, 3, true);
boolean defaultBoolean = true; boolean defaultBoolean = random.nextBoolean();
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean)); assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
Long defaultLong = 123L; Long defaultLong = random.nextLong();
assertEquals(defaultLong, list.getLong(3, defaultLong)); assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23; Double defaultDouble = random.nextDouble();
assertEquals(defaultDouble, list.getDouble(0, defaultDouble)); assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
String defaultString = "123"; String defaultString = getRandomString(123);
assertEquals(defaultString, list.getString(0, defaultString)); assertEquals(defaultString, list.getString(0, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3}; byte[] defaultBytes = getRandomBytes(123);
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes)); assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3); BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(0, defaultList)); assertEquals(defaultList, list.getList(0, defaultList));

View File

@@ -0,0 +1,42 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class AuthorInfoTest extends BrambleTestCase {
@Test
public void testEquals() {
assertEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, null)
);
assertEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(VERIFIED)
);
assertNotEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE)
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE, "a"),
new AuthorInfo(NONE, "b")
);
}
}

View File

@@ -12,12 +12,10 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.util.IoUtils;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -25,6 +23,7 @@ import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.sort;
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;
@@ -33,6 +32,7 @@ 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.util.IoUtils.deleteFileOrDir;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
public class TestUtils { public class TestUtils {
@@ -48,8 +48,10 @@ public class TestUtils {
} }
public static void deleteTestDirectory(File testDir) { public static void deleteTestDirectory(File testDir) {
IoUtils.deleteFileOrDir(testDir); deleteFileOrDir(testDir);
testDir.getParentFile().delete(); // Delete if empty // Delete parent directory only if it's empty
//noinspection ResultOfMethodCallIgnored
testDir.getParentFile().delete();
} }
public static byte[] getRandomBytes(int length) { public static byte[] getRandomBytes(int length) {
@@ -145,7 +147,7 @@ public class TestUtils {
if (size == 0) throw new IllegalArgumentException(); if (size == 0) throw new IllegalArgumentException();
List<Double> sorted = new ArrayList<>(size); List<Double> sorted = new ArrayList<>(size);
for (Number n : samples) sorted.add(n.doubleValue()); for (Number n : samples) sorted.add(n.doubleValue());
Collections.sort(sorted); sort(sorted);
if (size % 2 == 1) return sorted.get(size / 2); if (size % 2 == 1) return sorted.get(size / 2);
double low = sorted.get(size / 2 - 1), high = sorted.get(size / 2); double low = sorted.get(size / 2 - 1), high = sorted.get(size / 2);
return (low + high) / 2; return (low + high) / 2;

View File

@@ -2,7 +2,7 @@ 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.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9', 'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',

View File

@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer' apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
apply from: '../dagger.gradle'
dependencies { dependencies {
implementation project(path: ':bramble-api', configuration: 'default') implementation project(path: ':bramble-api', configuration: 'default')
@@ -17,7 +17,7 @@ dependencies {
implementation 'org.whispersystems:curve25519-java:0.5.0' 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' annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6 testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
@@ -25,10 +25,8 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
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-core:1.3"
testApt 'com.google.dagger:dagger-compiler:2.0.2' testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19'
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
import org.briarproject.bramble.plugin.PluginModule; import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule; import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.reporting.ReportingModule; import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule; import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule; import org.briarproject.bramble.versioning.VersioningModule;
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
void inject(ReportingModule.EagerSingletons init); void inject(ReportingModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init); void inject(SystemModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init); void inject(TransportModule.EagerSingletons init);
void inject(ValidationModule.EagerSingletons init);
void inject(VersioningModule.EagerSingletons init); void inject(VersioningModule.EagerSingletons init);
} }

View File

@@ -19,6 +19,7 @@ import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.settings.SettingsModule; import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.socks.SocksModule; import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule; import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule; import org.briarproject.bramble.versioning.VersioningModule;
@@ -47,6 +48,7 @@ import dagger.Module;
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
TransportModule.class, TransportModule.class,
ValidationModule.class,
VersioningModule.class VersioningModule.class
}) })
public class BrambleCoreModule { public class BrambleCoreModule {
@@ -60,9 +62,9 @@ public class BrambleCoreModule {
c.inject(new PluginModule.EagerSingletons()); c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons()); c.inject(new PropertiesModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons()); c.inject(new ReportingModule.EagerSingletons());
c.inject(new SyncModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons()); c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons()); c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons()); c.inject(new VersioningModule.EagerSingletons());
} }
} }

View File

@@ -10,6 +10,7 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
/** /**
@@ -42,7 +43,7 @@ public class PoliteExecutor implements Executor {
int maxConcurrentTasks) { int maxConcurrentTasks) {
this.delegate = delegate; this.delegate = delegate;
this.maxConcurrentTasks = maxConcurrentTasks; this.maxConcurrentTasks = maxConcurrentTasks;
log = Logger.getLogger(tag); log = getLogger(tag);
} }
@Override @Override

View File

@@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
@@ -22,7 +23,7 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
RejectedExecutionHandler handler) { RejectedExecutionHandler handler) {
super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue,
handler); handler);
log = Logger.getLogger(tag); log = getLogger(tag);
} }
@Override @Override

View File

@@ -6,9 +6,7 @@ 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.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.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.util.IoUtils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@@ -19,19 +17,21 @@ import java.io.InputStreamReader;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.fromHexString; import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString; import static org.briarproject.bramble.util.StringUtils.toHexString;
@MethodsNotNullByDefault @NotNullByDefault
@ParametersNotNullByDefault
class AccountManagerImpl implements AccountManager { class AccountManagerImpl implements AccountManager {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AccountManagerImpl.class.getName()); getLogger(AccountManagerImpl.class.getName());
private static final String DB_KEY_FILENAME = "db.key"; private static final String DB_KEY_FILENAME = "db.key";
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak"; private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
@@ -68,7 +68,7 @@ class AccountManagerImpl implements AccountManager {
return databaseKey; return databaseKey;
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
@Nullable @Nullable
protected String loadEncryptedDatabaseKey() { protected String loadEncryptedDatabaseKey() {
String key = readDbKeyFromFile(dbKeyFile); String key = readDbKeyFromFile(dbKeyFile);
@@ -83,7 +83,7 @@ class AccountManagerImpl implements AccountManager {
return key; return key;
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
@Nullable @Nullable
private String readDbKeyFromFile(File f) { private String readDbKeyFromFile(File f) {
if (!f.exists()) { if (!f.exists()) {
@@ -102,8 +102,8 @@ class AccountManagerImpl implements AccountManager {
} }
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
protected boolean storeEncryptedDatabaseKey(String hex) { boolean storeEncryptedDatabaseKey(String hex) {
LOG.info("Storing database key in file"); LOG.info("Storing database key in file");
// Create the directory if necessary // Create the directory if necessary
if (databaseConfig.getDatabaseKeyDirectory().mkdirs()) if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
@@ -140,7 +140,7 @@ class AccountManagerImpl implements AccountManager {
} }
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
private void writeDbKeyToFile(String key, File f) throws IOException { private void writeDbKeyToFile(String key, File f) throws IOException {
FileOutputStream out = new FileOutputStream(f); FileOutputStream out = new FileOutputStream(f);
out.write(key.getBytes("UTF-8")); out.write(key.getBytes("UTF-8"));
@@ -170,7 +170,7 @@ class AccountManagerImpl implements AccountManager {
} }
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) { private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
byte[] plaintext = key.getBytes(); byte[] plaintext = key.getBytes();
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password); byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
@@ -181,8 +181,8 @@ class AccountManagerImpl implements AccountManager {
public void deleteAccount() { public void deleteAccount() {
synchronized (stateChangeLock) { synchronized (stateChangeLock) {
LOG.info("Deleting account"); LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); deleteFileOrDir(databaseConfig.getDatabaseDirectory());
databaseKey = null; databaseKey = null;
} }
} }
@@ -197,7 +197,7 @@ class AccountManagerImpl implements AccountManager {
} }
} }
// Locking: stateChangeLock @GuardedBy("stateChangeLock")
@Nullable @Nullable
private SecretKey loadAndDecryptDatabaseKey(String password) { private SecretKey loadAndDecryptDatabaseKey(String password) {
String hex = loadEncryptedDatabaseKey(); String hex = loadEncryptedDatabaseKey();

View File

@@ -0,0 +1,19 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import dagger.Module;
import dagger.Provides;
/**
* Provides a default implementation of {@link BatteryManager} for systems
* without batteries.
*/
@Module
public class DefaultBatteryManagerModule {
@Provides
BatteryManager provideBatteryManager() {
return () -> false;
}
}

View File

@@ -82,13 +82,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void addLocalMessage(Message m, BdfDictionary metadata, public void addLocalMessage(Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException { boolean shared) throws DbException, FormatException {
Transaction txn = db.startTransaction(false); db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared));
try {
addLocalMessage(txn, m, metadata, shared);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -113,15 +107,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Message getMessage(MessageId m) throws DbException { public Message getMessage(MessageId m) throws DbException {
Message message; return db.transactionWithResult(true, txn -> getMessage(txn, m));
Transaction txn = db.startTransaction(true);
try {
message = getMessage(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return message;
} }
@Override @Override
@@ -132,15 +118,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(MessageId m) throws DbException, public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException { FormatException {
BdfList list; return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
Transaction txn = db.startTransaction(true);
try {
list = getMessageAsList(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return list;
} }
@Override @Override
@@ -152,15 +130,8 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getGroupMetadataAsDictionary(GroupId g) public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException { throws DbException, FormatException {
BdfDictionary dictionary; return db.transactionWithResult(true, txn ->
Transaction txn = db.startTransaction(true); getGroupMetadataAsDictionary(txn, g));
try {
dictionary = getGroupMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -173,15 +144,8 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m) public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
BdfDictionary dictionary; return db.transactionWithResult(true, txn ->
Transaction txn = db.startTransaction(true); getMessageMetadataAsDictionary(txn, m));
try {
dictionary = getMessageMetadataAsDictionary(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -194,15 +158,8 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g) throws DbException, FormatException { GroupId g) throws DbException, FormatException {
Map<MessageId, BdfDictionary> map; return db.transactionWithResult(true, txn ->
Transaction txn = db.startTransaction(true); getMessageMetadataAsDictionary(txn, g));
try {
map = getMessageMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -219,15 +176,8 @@ class ClientHelperImpl implements ClientHelper {
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g, BdfDictionary query) throws DbException, GroupId g, BdfDictionary query) throws DbException,
FormatException { FormatException {
Map<MessageId, BdfDictionary> map; return db.transactionWithResult(true, txn ->
Transaction txn = db.startTransaction(true); getMessageMetadataAsDictionary(txn, g, query));
try {
map = getMessageMetadataAsDictionary(txn, g, query);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -245,13 +195,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata) public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
Transaction txn = db.startTransaction(false); db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata));
try {
mergeGroupMetadata(txn, g, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -263,13 +207,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata) public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
Transaction txn = db.startTransaction(false); db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata));
try {
mergeMessageMetadata(txn, m, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override

View File

@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
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.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -44,6 +43,7 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO; import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
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.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@@ -55,7 +55,7 @@ import static org.briarproject.bramble.util.ValidationUtils.checkSize;
class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ContactExchangeTaskImpl.class.getName()); getLogger(ContactExchangeTaskImpl.class.getName());
private static final String SIGNING_LABEL_EXCHANGE = private static final String SIGNING_LABEL_EXCHANGE =
"org.briarproject.briar.contact/EXCHANGE"; "org.briarproject.briar.contact/EXCHANGE";
@@ -158,7 +158,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
streamWriterFactory.createContactExchangeStreamWriter(out, streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey); alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter = RecordWriter recordWriter =
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream()); recordWriterFactory
.createRecordWriter(streamWriter.getOutputStream());
// Derive the nonces to be signed // Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -190,6 +191,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
streamWriter.sendEndOfStream(); streamWriter.sendEndOfStream();
// Skip any remaining records from the incoming stream // Skip any remaining records from the incoming stream
try { try {
//noinspection InfiniteLoopStatement
while (true) recordReader.readRecord(); while (true) recordReader.readRecord();
} catch (EOFException expected) { } catch (EOFException expected) {
LOG.info("End of stream"); LOG.info("End of stream");
@@ -287,19 +289,14 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private ContactId addContact(Author remoteAuthor, long timestamp, private ContactId addContact(Author remoteAuthor, long timestamp,
Map<TransportId, TransportProperties> remoteProperties) Map<TransportId, TransportProperties> remoteProperties)
throws DbException { throws DbException {
ContactId contactId; return db.transactionWithResult(false, txn -> {
Transaction txn = db.startTransaction(false); ContactId contactId = contactManager.addContact(txn, remoteAuthor,
try {
contactId = contactManager.addContact(txn, remoteAuthor,
localAuthor.getId(), masterSecret, timestamp, alice, localAuthor.getId(), masterSecret, timestamp, alice,
true, true); true, true);
transportPropertyManager.addRemoteProperties(txn, contactId, transportPropertyManager.addRemoteProperties(txn, contactId,
remoteProperties); remoteProperties);
db.commitTransaction(txn); return contactId;
} finally { });
db.endTransaction(txn);
}
return contactId;
} }
private void tryToClose(DuplexTransportConnection conn) { private void tryToClose(DuplexTransportConnection conn) {

View File

@@ -3,6 +3,8 @@ package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
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.DbException;
@@ -10,29 +12,53 @@ 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;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION;
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 static final int LINK_LENGTH = 64;
private static final String REMOTE_CONTACT_LINK =
"briar://" + getRandomBase32String(LINK_LENGTH);
private static final Pattern LINK_REGEX =
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
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<>();
} }
@@ -65,42 +91,63 @@ class ContactManagerImpl implements ContactManager {
public ContactId addContact(Author remote, AuthorId local, SecretKey master, public ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active) long timestamp, boolean alice, boolean verified, boolean active)
throws DbException { throws DbException {
ContactId c; return db.transactionWithResult(false, txn ->
Transaction txn = db.startTransaction(false); addContact(txn, remote, local, master, timestamp, alice,
try { verified, active));
c = addContact(txn, remote, local, master, timestamp, alice, }
verified, active);
db.commitTransaction(txn); @Override
} finally { public String getRemoteContactLink() {
db.endTransaction(txn); // TODO replace with real implementation
return REMOTE_CONTACT_LINK;
}
@SuppressWarnings("SameParameterValue")
private static String getRandomBase32String(int length) {
Random random = new Random();
char[] c = new char[length];
for (int i = 0; i < length; i++) {
int character = random.nextInt(32);
if (character < 26) c[i] = (char) ('a' + character);
else c[i] = (char) ('2' + (character - 26));
} }
return c; return new String(c);
}
@Override
public boolean isValidRemoteContactLink(String link) {
return LINK_REGEX.matcher(link).matches();
}
@Override
public PendingContact addRemoteContactRequest(String link, String alias) {
// TODO replace with real implementation
PendingContactId id = new PendingContactId(link.getBytes());
return new PendingContact(id, alias, WAITING_FOR_CONNECTION,
System.currentTimeMillis());
}
@Override
public Collection<PendingContact> getPendingContacts() {
// TODO replace with real implementation
return emptyList();
}
@Override
public void removePendingContact(PendingContact pendingContact) {
// TODO replace with real implementation
} }
@Override @Override
public Contact getContact(ContactId c) throws DbException { public Contact getContact(ContactId c) throws DbException {
Contact contact; return db.transactionWithResult(true, txn -> db.getContact(txn, c));
Transaction txn = db.startTransaction(true);
try {
contact = db.getContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contact;
} }
@Override @Override
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId) public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException { throws DbException {
Transaction txn = db.startTransaction(true); return db.transactionWithResult(true, txn ->
try { getContact(txn, remoteAuthorId, localAuthorId));
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
return c;
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -118,14 +165,8 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public Collection<Contact> getActiveContacts() throws DbException { public Collection<Contact> getActiveContacts() throws DbException {
Collection<Contact> contacts; Collection<Contact> contacts =
Transaction txn = db.startTransaction(true); db.transactionWithResult(true, db::getContacts);
try {
contacts = db.getContacts(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
List<Contact> active = new ArrayList<>(contacts.size()); List<Contact> active = new ArrayList<>(contacts.size());
for (Contact c : contacts) if (c.isActive()) active.add(c); for (Contact c : contacts) if (c.isActive()) active.add(c);
return active; return active;
@@ -133,13 +174,7 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public void removeContact(ContactId c) throws DbException { public void removeContact(ContactId c) throws DbException {
Transaction txn = db.startTransaction(false); db.transaction(false, txn -> removeContact(txn, c));
try {
removeContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -148,6 +183,23 @@ class ContactManagerImpl implements ContactManager {
db.setContactActive(txn, c, active); db.setContactActive(txn, c, active);
} }
@Override
public void setContactAlias(Transaction txn, 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.setContactAlias(txn, c, alias);
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
db.transaction(false, txn -> 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 {
@@ -157,15 +209,8 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public boolean contactExists(AuthorId remoteAuthorId, public boolean contactExists(AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException { AuthorId localAuthorId) throws DbException {
boolean exists; return db.transactionWithResult(true, txn ->
Transaction txn = db.startTransaction(true); contactExists(txn, remoteAuthorId, localAuthorId));
try {
exists = contactExists(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return exists;
} }
@Override @Override
@@ -176,4 +221,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

@@ -2,18 +2,20 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault @NotNullByDefault
class AsciiArmour { class AsciiArmour {
static String wrap(byte[] b, int lineLength) { static String wrap(byte[] b, int lineLength) {
String wrapped = StringUtils.toHexString(b); String wrapped = toHexString(b);
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
int length = wrapped.length(); int length = wrapped.length();
for (int i = 0; i < length; i += lineLength) { for (int i = 0; i < length; i += lineLength) {
int end = Math.min(i + lineLength, length); int end = Math.min(i + lineLength, length);
s.append(wrapped.substring(i, end)); s.append(wrapped, i, end);
s.append("\r\n"); s.append("\r\n");
} }
return s.toString(); return s.toString();
@@ -21,7 +23,7 @@ class AsciiArmour {
static byte[] unwrap(String s) throws FormatException { static byte[] unwrap(String s) throws FormatException {
try { try {
return StringUtils.fromHexString(s.replaceAll("[^0-9a-fA-F]", "")); return fromHexString(s.replaceAll("[^0-9a-fA-F]", ""));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new FormatException(); throw new FormatException();
} }

View File

@@ -12,8 +12,6 @@ import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.SecureRandomProvider; import org.briarproject.bramble.api.system.SecureRandomProvider;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.crypto.CryptoException; import org.spongycastle.crypto.CryptoException;
import org.spongycastle.crypto.Digest; import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.Blake2bDigest; import org.spongycastle.crypto.digests.Blake2bDigest;
@@ -30,16 +28,21 @@ import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.System.arraycopy;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
import static org.briarproject.bramble.util.ByteUtils.readUint32;
import static org.briarproject.bramble.util.ByteUtils.writeUint32;
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;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@NotNullByDefault @NotNullByDefault
class CryptoComponentImpl implements CryptoComponent { class CryptoComponentImpl implements CryptoComponent {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(CryptoComponentImpl.class.getName()); getLogger(CryptoComponentImpl.class.getName());
private static final int SIGNATURE_KEY_PAIR_BITS = 256; private static final int SIGNATURE_KEY_PAIR_BITS = 256;
private static final int STORAGE_IV_BYTES = 24; // 196 bits private static final int STORAGE_IV_BYTES = 24; // 196 bits
@@ -188,7 +191,7 @@ class CryptoComponentImpl implements CryptoComponent {
PrivateKey ourPriv = ourKeyPair.getPrivate(); PrivateKey ourPriv = ourKeyPair.getPrivate();
byte[][] hashInputs = new byte[inputs.length + 1][]; byte[][] hashInputs = new byte[inputs.length + 1][];
hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey); hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey);
System.arraycopy(inputs, 0, hashInputs, 1, inputs.length); arraycopy(inputs, 0, hashInputs, 1, inputs.length);
byte[] hash = hash(label, hashInputs); byte[] hash = hash(label, hashInputs);
if (hash.length != SecretKey.LENGTH) throw new IllegalStateException(); if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
return new SecretKey(hash); return new SecretKey(hash);
@@ -216,26 +219,26 @@ class CryptoComponentImpl implements CryptoComponent {
private void updateSignature(Signature signature, String label, private void updateSignature(Signature signature, String label,
byte[] toSign) throws GeneralSecurityException { byte[] toSign) throws GeneralSecurityException {
byte[] labelBytes = StringUtils.toUtf8(label); byte[] labelBytes = toUtf8(label);
byte[] length = new byte[INT_32_BYTES]; byte[] length = new byte[INT_32_BYTES];
ByteUtils.writeUint32(labelBytes.length, length, 0); writeUint32(labelBytes.length, length, 0);
signature.update(length); signature.update(length);
signature.update(labelBytes); signature.update(labelBytes);
ByteUtils.writeUint32(toSign.length, length, 0); writeUint32(toSign.length, length, 0);
signature.update(length); signature.update(length);
signature.update(toSign); signature.update(toSign);
} }
@Override @Override
public byte[] hash(String label, byte[]... inputs) { public byte[] hash(String label, byte[]... inputs) {
byte[] labelBytes = StringUtils.toUtf8(label); byte[] labelBytes = toUtf8(label);
Digest digest = new Blake2bDigest(256); Digest digest = new Blake2bDigest(256);
byte[] length = new byte[INT_32_BYTES]; byte[] length = new byte[INT_32_BYTES];
ByteUtils.writeUint32(labelBytes.length, length, 0); writeUint32(labelBytes.length, length, 0);
digest.update(length, 0, length.length); digest.update(length, 0, length.length);
digest.update(labelBytes, 0, labelBytes.length); digest.update(labelBytes, 0, labelBytes.length);
for (byte[] input : inputs) { for (byte[] input : inputs) {
ByteUtils.writeUint32(input.length, length, 0); writeUint32(input.length, length, 0);
digest.update(length, 0, length.length); digest.update(length, 0, length.length);
digest.update(input, 0, input.length); digest.update(input, 0, input.length);
} }
@@ -246,14 +249,14 @@ class CryptoComponentImpl implements CryptoComponent {
@Override @Override
public byte[] mac(String label, SecretKey macKey, byte[]... inputs) { public byte[] mac(String label, SecretKey macKey, byte[]... inputs) {
byte[] labelBytes = StringUtils.toUtf8(label); byte[] labelBytes = toUtf8(label);
Digest mac = new Blake2bDigest(macKey.getBytes(), 32, null, null); Digest mac = new Blake2bDigest(macKey.getBytes(), 32, null, null);
byte[] length = new byte[INT_32_BYTES]; byte[] length = new byte[INT_32_BYTES];
ByteUtils.writeUint32(labelBytes.length, length, 0); writeUint32(labelBytes.length, length, 0);
mac.update(length, 0, length.length); mac.update(length, 0, length.length);
mac.update(labelBytes, 0, labelBytes.length); mac.update(labelBytes, 0, labelBytes.length);
for (byte[] input : inputs) { for (byte[] input : inputs) {
ByteUtils.writeUint32(input.length, length, 0); writeUint32(input.length, length, 0);
mac.update(length, 0, length.length); mac.update(length, 0, length.length);
mac.update(input, 0, input.length); mac.update(input, 0, input.length);
} }
@@ -297,13 +300,13 @@ class CryptoComponentImpl implements CryptoComponent {
output[outputOff] = PBKDF_FORMAT_SCRYPT; output[outputOff] = PBKDF_FORMAT_SCRYPT;
outputOff++; outputOff++;
// Salt // Salt
System.arraycopy(salt, 0, output, outputOff, salt.length); arraycopy(salt, 0, output, outputOff, salt.length);
outputOff += salt.length; outputOff += salt.length;
// Cost parameter // Cost parameter
ByteUtils.writeUint32(cost, output, outputOff); writeUint32(cost, output, outputOff);
outputOff += INT_32_BYTES; outputOff += INT_32_BYTES;
// IV // IV
System.arraycopy(iv, 0, output, outputOff, iv.length); arraycopy(iv, 0, output, outputOff, iv.length);
outputOff += iv.length; outputOff += iv.length;
// Initialise the cipher and encrypt the plaintext // Initialise the cipher and encrypt the plaintext
try { try {
@@ -333,16 +336,16 @@ class CryptoComponentImpl implements CryptoComponent {
return null; // Unknown format return null; // Unknown format
// Salt // Salt
byte[] salt = new byte[PBKDF_SALT_BYTES]; byte[] salt = new byte[PBKDF_SALT_BYTES];
System.arraycopy(input, inputOff, salt, 0, salt.length); arraycopy(input, inputOff, salt, 0, salt.length);
inputOff += salt.length; inputOff += salt.length;
// Cost parameter // Cost parameter
long cost = ByteUtils.readUint32(input, inputOff); long cost = readUint32(input, inputOff);
inputOff += INT_32_BYTES; inputOff += INT_32_BYTES;
if (cost < 2 || cost > Integer.MAX_VALUE) if (cost < 2 || cost > Integer.MAX_VALUE)
return null; // Invalid cost parameter return null; // Invalid cost parameter
// IV // IV
byte[] iv = new byte[STORAGE_IV_BYTES]; byte[] iv = new byte[STORAGE_IV_BYTES];
System.arraycopy(input, inputOff, iv, 0, iv.length); arraycopy(input, inputOff, iv, 0, iv.length);
inputOff += iv.length; inputOff += iv.length;
// Derive the key from the password // Derive the key from the password
SecretKey key = passwordBasedKdf.deriveKey(password, salt, (int) cost); SecretKey key = passwordBasedKdf.deriveKey(password, salt, (int) cost);

View File

@@ -7,6 +7,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import static java.lang.System.arraycopy;
@NotNullByDefault @NotNullByDefault
class Curve25519KeyParser implements KeyParser { class Curve25519KeyParser implements KeyParser {
@@ -26,7 +28,7 @@ class Curve25519KeyParser implements KeyParser {
static byte[] clamp(byte[] b) { static byte[] clamp(byte[] b) {
byte[] clamped = new byte[32]; byte[] clamped = new byte[32];
System.arraycopy(b, 0, clamped, 0, 32); arraycopy(b, 0, clamped, 0, 32);
clamped[0] &= 248; clamped[0] &= 248;
clamped[31] &= 127; clamped[31] &= 127;
clamped[31] |= 64; clamped[31] |= 64;

View File

@@ -1,13 +1,15 @@
package org.briarproject.bramble.crypto; package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.ByteUtils;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
import static org.briarproject.bramble.util.ByteUtils.readUint16;
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
@NotNullByDefault @NotNullByDefault
class FrameEncoder { class FrameEncoder {
@@ -16,7 +18,7 @@ class FrameEncoder {
if (dest.length < FRAME_NONCE_LENGTH) if (dest.length < FRAME_NONCE_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (frameNumber < 0) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IllegalArgumentException();
ByteUtils.writeUint64(frameNumber, dest, 0); writeUint64(frameNumber, dest, 0);
if (header) dest[0] |= 0x80; if (header) dest[0] |= 0x80;
for (int i = INT_64_BYTES; i < FRAME_NONCE_LENGTH; i++) dest[i] = 0; for (int i = INT_64_BYTES; i < FRAME_NONCE_LENGTH; i++) dest[i] = 0;
} }
@@ -29,8 +31,8 @@ class FrameEncoder {
if (paddingLength < 0) throw new IllegalArgumentException(); if (paddingLength < 0) throw new IllegalArgumentException();
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
ByteUtils.writeUint16(payloadLength, dest, 0); writeUint16(payloadLength, dest, 0);
ByteUtils.writeUint16(paddingLength, dest, INT_16_BYTES); writeUint16(paddingLength, dest, INT_16_BYTES);
if (finalFrame) dest[0] |= 0x80; if (finalFrame) dest[0] |= 0x80;
} }
@@ -43,12 +45,12 @@ class FrameEncoder {
static int getPayloadLength(byte[] header) { static int getPayloadLength(byte[] header) {
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH) if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
return ByteUtils.readUint16(header, 0) & 0x7FFF; return readUint16(header, 0) & 0x7FFF;
} }
static int getPaddingLength(byte[] header) { static int getPaddingLength(byte[] header) {
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH) if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
return ByteUtils.readUint16(header, INT_16_BYTES); return readUint16(header, INT_16_BYTES);
} }
} }

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.System.arraycopy;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
class KeyAgreementCryptoImpl implements KeyAgreementCrypto { class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
@@ -24,7 +25,7 @@ class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
byte[] hash = crypto.hash(COMMIT_LABEL, publicKey.getEncoded()); byte[] hash = crypto.hash(COMMIT_LABEL, publicKey.getEncoded());
// The output is the first COMMIT_LENGTH bytes of the hash // The output is the first COMMIT_LENGTH bytes of the hash
byte[] commitment = new byte[COMMIT_LENGTH]; byte[] commitment = new byte[COMMIT_LENGTH];
System.arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH); arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
return commitment; return commitment;
} }

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.crypto.KeyParser;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves; import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.asn1.x9.X9ECParameters; import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.AsymmetricCipherKeyPair; import org.spongycastle.crypto.AsymmetricCipherKeyPair;
@@ -45,6 +44,9 @@ import java.util.Scanner;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class MessageEncrypter { public class MessageEncrypter {
@@ -157,6 +159,7 @@ public class MessageEncrypter {
printUsage(); printUsage();
System.exit(1); System.exit(1);
} }
//noinspection IfCanBeSwitch
if (args[0].equals("generate")) { if (args[0].equals("generate")) {
if (args.length != 3) { if (args.length != 3) {
printUsage(); printUsage();
@@ -210,11 +213,11 @@ public class MessageEncrypter {
MessageEncrypter encrypter = new MessageEncrypter(random); MessageEncrypter encrypter = new MessageEncrypter(random);
KeyPair keyPair = encrypter.generateKeyPair(); KeyPair keyPair = encrypter.generateKeyPair();
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile)); PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
out.print(StringUtils.toHexString(keyPair.getPublic().getEncoded())); out.print(toHexString(keyPair.getPublic().getEncoded()));
out.flush(); out.flush();
out.close(); out.close();
out = new PrintStream(new FileOutputStream(privateKeyFile)); out = new PrintStream(new FileOutputStream(privateKeyFile));
out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded())); out.print(toHexString(keyPair.getPrivate().getEncoded()));
out.flush(); out.flush();
out.close(); out.close();
} }
@@ -223,7 +226,7 @@ public class MessageEncrypter {
SecureRandom random = new SecureRandom(); SecureRandom random = new SecureRandom();
MessageEncrypter encrypter = new MessageEncrypter(random); MessageEncrypter encrypter = new MessageEncrypter(random);
InputStream in = new FileInputStream(publicKeyFile); InputStream in = new FileInputStream(publicKeyFile);
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim()); byte[] keyBytes = fromHexString(readFully(in).trim());
PublicKey publicKey = PublicKey publicKey =
encrypter.getKeyParser().parsePublicKey(keyBytes); encrypter.getKeyParser().parsePublicKey(keyBytes);
String message = readFully(System.in); String message = readFully(System.in);
@@ -236,7 +239,7 @@ public class MessageEncrypter {
SecureRandom random = new SecureRandom(); SecureRandom random = new SecureRandom();
MessageEncrypter encrypter = new MessageEncrypter(random); MessageEncrypter encrypter = new MessageEncrypter(random);
InputStream in = new FileInputStream(privateKeyFile); InputStream in = new FileInputStream(privateKeyFile);
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim()); byte[] keyBytes = fromHexString(readFully(in).trim());
PrivateKey privateKey = PrivateKey privateKey =
encrypter.getKeyParser().parsePrivateKey(keyBytes); encrypter.getKeyParser().parsePrivateKey(keyBytes);
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in)); byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.crypto.generators.SCrypt; import org.spongycastle.crypto.generators.SCrypt;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -10,13 +9,14 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
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;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
class ScryptKdf implements PasswordBasedKdf { class ScryptKdf implements PasswordBasedKdf {
private static final Logger LOG = private static final Logger LOG = getLogger(ScryptKdf.class.getName());
Logger.getLogger(ScryptKdf.class.getName());
private static final int MIN_COST = 256; // Min parameter N private static final int MIN_COST = 256; // Min parameter N
private static final int MAX_COST = 1024 * 1024; // Max parameter N private static final int MAX_COST = 1024 * 1024; // Max parameter N
@@ -53,7 +53,7 @@ class ScryptKdf implements PasswordBasedKdf {
@Override @Override
public SecretKey deriveKey(String password, byte[] salt, int cost) { public SecretKey deriveKey(String password, byte[] salt, int cost) {
long start = now(); long start = now();
byte[] passwordBytes = StringUtils.toUtf8(password); byte[] passwordBytes = toUtf8(password);
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost, SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH)); BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
logDuration(LOG, "Deriving key from password", start); logDuration(LOG, "Deriving key from password", start);

View File

@@ -16,6 +16,8 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.lang.System.arraycopy;
import static java.util.logging.Logger.getLogger;
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;
@@ -28,8 +30,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
class Sec1KeyParser implements KeyParser { class Sec1KeyParser implements KeyParser {
private static final Logger LOG = private static final Logger LOG = getLogger(Sec1KeyParser.class.getName());
Logger.getLogger(Sec1KeyParser.class.getName());
private final ECDomainParameters params; private final ECDomainParameters params;
private final BigInteger modulus; private final BigInteger modulus;
@@ -56,12 +57,12 @@ class Sec1KeyParser implements KeyParser {
if (encodedKey[0] != 4) throw new GeneralSecurityException(); if (encodedKey[0] != 4) throw new GeneralSecurityException();
// The x co-ordinate must be >= 0 and < p // The x co-ordinate must be >= 0 and < p
byte[] xBytes = new byte[bytesPerInt]; byte[] xBytes = new byte[bytesPerInt];
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt); arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
BigInteger x = new BigInteger(1, xBytes); // Positive signum BigInteger x = new BigInteger(1, xBytes); // Positive signum
if (x.compareTo(modulus) >= 0) throw new GeneralSecurityException(); if (x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
// The y co-ordinate must be >= 0 and < p // The y co-ordinate must be >= 0 and < p
byte[] yBytes = new byte[bytesPerInt]; byte[] yBytes = new byte[bytesPerInt];
System.arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt); arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt);
BigInteger y = new BigInteger(1, yBytes); // Positive signum BigInteger y = new BigInteger(1, yBytes); // Positive signum
if (y.compareTo(modulus) >= 0) throw new GeneralSecurityException(); if (y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
// Verify that y^2 == x^3 + ax + b (mod p) // Verify that y^2 == x^3 + ax + b (mod p)

View File

@@ -2,6 +2,8 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import static java.lang.System.arraycopy;
@NotNullByDefault @NotNullByDefault
class Sec1Utils { class Sec1Utils {
@@ -10,10 +12,10 @@ class Sec1Utils {
if (src.length < destLen) { if (src.length < destLen) {
int padding = destLen - src.length; int padding = destLen - src.length;
for (int i = destOff; i < destOff + padding; i++) dest[i] = 0; for (int i = destOff; i < destOff + padding; i++) dest[i] = 0;
System.arraycopy(src, 0, dest, destOff + padding, src.length); arraycopy(src, 0, dest, destOff + padding, src.length);
} else { } else {
int srcOff = src.length - destLen; int srcOff = src.length - destLen;
System.arraycopy(src, srcOff, dest, destOff, destLen); arraycopy(src, srcOff, dest, destOff, destLen);
} }
} }
} }

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.StreamDecrypter; import org.briarproject.bramble.api.crypto.StreamDecrypter;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.ByteUtils;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
@@ -14,6 +13,7 @@ import java.security.GeneralSecurityException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.lang.System.arraycopy;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
@@ -26,6 +26,8 @@ import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_H
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
import static org.briarproject.bramble.util.ByteUtils.readUint16;
import static org.briarproject.bramble.util.ByteUtils.readUint64;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
@@ -130,7 +132,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
} }
// Extract the nonce // Extract the nonce
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH]; byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0, arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0,
STREAM_HEADER_NONCE_LENGTH); STREAM_HEADER_NONCE_LENGTH);
// Decrypt and authenticate the stream header // Decrypt and authenticate the stream header
try { try {
@@ -145,17 +147,16 @@ class StreamDecrypterImpl implements StreamDecrypter {
throw new FormatException(); throw new FormatException();
} }
// Check the protocol version // Check the protocol version
int receivedProtocolVersion = int receivedProtocolVersion = readUint16(streamHeaderPlaintext, 0);
ByteUtils.readUint16(streamHeaderPlaintext, 0);
if (receivedProtocolVersion != PROTOCOL_VERSION) if (receivedProtocolVersion != PROTOCOL_VERSION)
throw new FormatException(); throw new FormatException();
// Check the stream number // Check the stream number
long receivedStreamNumber = ByteUtils.readUint64(streamHeaderPlaintext, long receivedStreamNumber = readUint64(streamHeaderPlaintext,
INT_16_BYTES); INT_16_BYTES);
if (receivedStreamNumber != streamNumber) throw new FormatException(); if (receivedStreamNumber != streamNumber) throw new FormatException();
// Extract the frame key // Extract the frame key
byte[] frameKeyBytes = new byte[SecretKey.LENGTH]; byte[] frameKeyBytes = new byte[SecretKey.LENGTH];
System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES, arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
frameKeyBytes, 0, SecretKey.LENGTH); frameKeyBytes, 0, SecretKey.LENGTH);
frameKey = new SecretKey(frameKeyBytes); frameKey = new SecretKey(frameKeyBytes);
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.StreamEncrypter; import org.briarproject.bramble.api.crypto.StreamEncrypter;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.ByteUtils;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -12,6 +11,7 @@ import java.security.GeneralSecurityException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.lang.System.arraycopy;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
@@ -24,6 +24,8 @@ import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_H
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
@@ -88,7 +90,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
throw new RuntimeException(badCipher); throw new RuntimeException(badCipher);
} }
// Combine the payload and padding // Combine the payload and padding
System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); arraycopy(payload, 0, framePlaintext, 0, payloadLength);
for (int i = 0; i < paddingLength; i++) for (int i = 0; i < paddingLength; i++)
framePlaintext[payloadLength + i] = 0; framePlaintext[payloadLength + i] = 0;
// Encrypt and authenticate the payload and padding // Encrypt and authenticate the payload and padding
@@ -118,13 +120,12 @@ class StreamEncrypterImpl implements StreamEncrypter {
private void writeStreamHeader() throws IOException { private void writeStreamHeader() throws IOException {
// The header contains the protocol version, stream number and frame key // The header contains the protocol version, stream number and frame key
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH]; byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0); writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext, writeUint64(streamNumber, streamHeaderPlaintext, INT_16_BYTES);
INT_16_BYTES); arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH); INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH);
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH]; byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
System.arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0, arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0,
STREAM_HEADER_NONCE_LENGTH); STREAM_HEADER_NONCE_LENGTH);
// Encrypt and authenticate the stream header key // Encrypt and authenticate the stream header key
try { try {

View File

@@ -7,13 +7,12 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.crypto.Digest; import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.Blake2bDigest; import org.spongycastle.crypto.digests.Blake2bDigest;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.System.arraycopy;
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL;
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL; import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
@@ -24,6 +23,9 @@ import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED; import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED; import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
class TransportCryptoImpl implements TransportCrypto { class TransportCryptoImpl implements TransportCrypto {
@@ -91,21 +93,21 @@ class TransportCryptoImpl implements TransportCrypto {
private SecretKey rotateKey(SecretKey k, long rotationPeriod) { private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
byte[] period = new byte[INT_64_BYTES]; byte[] period = new byte[INT_64_BYTES];
ByteUtils.writeUint64(rotationPeriod, period, 0); writeUint64(rotationPeriod, period, 0);
return crypto.deriveKey(ROTATE_LABEL, k, period); return crypto.deriveKey(ROTATE_LABEL, k, period);
} }
private SecretKey deriveTagKey(SecretKey master, TransportId t, private SecretKey deriveTagKey(SecretKey master, TransportId t,
boolean alice) { boolean alice) {
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL; String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
byte[] id = StringUtils.toUtf8(t.getString()); byte[] id = toUtf8(t.getString());
return crypto.deriveKey(label, master, id); return crypto.deriveKey(label, master, id);
} }
private SecretKey deriveHeaderKey(SecretKey master, TransportId t, private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
boolean alice) { boolean alice) {
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL; String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
byte[] id = StringUtils.toUtf8(t.getString()); byte[] id = toUtf8(t.getString());
return crypto.deriveKey(label, master, id); return crypto.deriveKey(label, master, id);
} }
@@ -125,14 +127,14 @@ class TransportCryptoImpl implements TransportCrypto {
// The input is the protocol version as a 16-bit integer, followed by // The input is the protocol version as a 16-bit integer, followed by
// the stream number as a 64-bit integer // the stream number as a 64-bit integer
byte[] protocolVersionBytes = new byte[INT_16_BYTES]; byte[] protocolVersionBytes = new byte[INT_16_BYTES];
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0); writeUint16(protocolVersion, protocolVersionBytes, 0);
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length); prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
byte[] streamNumberBytes = new byte[INT_64_BYTES]; byte[] streamNumberBytes = new byte[INT_64_BYTES];
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0); writeUint64(streamNumber, streamNumberBytes, 0);
prf.update(streamNumberBytes, 0, streamNumberBytes.length); prf.update(streamNumberBytes, 0, streamNumberBytes.length);
byte[] mac = new byte[macLength]; byte[] mac = new byte[macLength];
prf.doFinal(mac, 0); prf.doFinal(mac, 0);
// The output is the first TAG_LENGTH bytes of the MAC // The output is the first TAG_LENGTH bytes of the MAC
System.arraycopy(mac, 0, tag, 0, TAG_LENGTH); arraycopy(mac, 0, tag, 0, TAG_LENGTH);
} }
} }

View File

@@ -29,6 +29,7 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32; import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8; import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE; import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
@@ -253,7 +254,7 @@ class BdfReaderImpl implements BdfReader {
if (length < 0 || length > maxBufferSize) throw new FormatException(); if (length < 0 || length > maxBufferSize) throw new FormatException();
if (length == 0) return ""; if (length == 0) return "";
readIntoBuffer(length); readIntoBuffer(length);
return new String(buf, 0, length, "UTF-8"); return fromUtf8(buf, 0, length);
} }
private int readStringLength() throws IOException { private int readStringLength() throws IOException {

View File

@@ -22,7 +22,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
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.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
@@ -106,7 +106,7 @@ interface Database<T> {
* @param sender the contact from whom the message was received, or null * @param sender the contact from whom the message was received, or null
* if the message was created locally. * if the message was created locally.
*/ */
void addMessage(T txn, Message m, State state, boolean shared, void addMessage(T txn, Message m, MessageState state, boolean shared,
@Nullable ContactId sender) throws DbException; @Nullable ContactId sender) throws DbException;
/** /**
@@ -114,7 +114,7 @@ interface Database<T> {
* in the given state. * in the given state.
*/ */
void addMessageDependency(T txn, Message dependent, MessageId dependency, void addMessageDependency(T txn, Message dependent, MessageId dependency,
State dependentState) throws DbException; MessageState dependentState) throws DbException;
/** /**
* Records that a message has been offered by the given contact. * Records that a message has been offered by the given contact.
@@ -242,7 +242,7 @@ interface Database<T> {
* bytes. This is based on the minimum of the space available on the device * bytes. This is based on the minimum of the space available on the device
* where the database is stored and the database's configured size. * where the database is stored and the database's configured size.
*/ */
long getFreeSpace() throws DbException; long getFreeSpace();
/** /**
* Returns the group with the given ID. * Returns the group with the given ID.
@@ -310,11 +310,11 @@ interface Database<T> {
/** /**
* 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
* {@link State UNKNOWN} is returned. * {@link MessageState UNKNOWN} is returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, State> getMessageDependencies(T txn, MessageId m) Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m)
throws DbException; throws DbException;
/** /**
@@ -324,7 +324,7 @@ interface Database<T> {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, State> getMessageDependents(T txn, MessageId m) Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m)
throws DbException; throws DbException;
/** /**
@@ -383,7 +383,7 @@ interface Database<T> {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
State getMessageState(T txn, MessageId m) throws DbException; MessageState getMessageState(T txn, MessageId m) throws DbException;
/** /**
* Returns the status of all delivered messages in the given group with * Returns the status of all delivered messages in the given group with
@@ -616,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}.
@@ -631,7 +637,8 @@ interface Database<T> {
/** /**
* Sets the validation and delivery state of the given message. * Sets the validation and delivery state of the given message.
*/ */
void setMessageState(T txn, MessageId m, State state) throws DbException; void setMessageState(T txn, MessageId m, MessageState state)
throws DbException;
/** /**
* Sets the reordering window for the given key set and transport in the * Sets the reordering window for the given key set and transport in the

View File

@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException; import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchMessageException; import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchTransportException; import org.briarproject.bramble.api.db.NoSuchTransportException;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -42,7 +43,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.GroupAddedEvent; import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent; import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
@@ -54,13 +54,13 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -71,11 +71,13 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.Collections.singletonList;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
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.ValidationManager.State.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN; import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES; import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@@ -86,7 +88,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
class DatabaseComponentImpl<T> implements DatabaseComponent { class DatabaseComponentImpl<T> implements DatabaseComponent {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(DatabaseComponentImpl.class.getName()); getLogger(DatabaseComponentImpl.class.getName());
private final Database<T> db; private final Database<T> db;
private final Class<T> txnClass; private final Class<T> txnClass;
@@ -193,6 +195,20 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
@Override
public <R, E extends Exception> R transactionWithNullableResult(
boolean readOnly, NullableDbCallable<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());
@@ -564,7 +580,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public State getMessageState(Transaction transaction, MessageId m) public MessageState getMessageState(Transaction transaction, MessageId m)
throws DbException { throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
@@ -604,8 +620,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public Map<MessageId, State> getMessageDependencies(Transaction transaction, public Map<MessageId, MessageState> getMessageDependencies(
MessageId m) throws DbException { Transaction transaction, MessageId m) throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
@@ -613,8 +629,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public Map<MessageId, State> getMessageDependents(Transaction transaction, public Map<MessageId, MessageState> getMessageDependents(
MessageId m) throws DbException { Transaction transaction, MessageId m) throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
@@ -859,6 +875,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,
@Nullable 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 {
@@ -873,7 +899,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (old == INVISIBLE) db.addGroupVisibility(txn, c, g, v == SHARED); if (old == INVISIBLE) db.addGroupVisibility(txn, c, g, v == SHARED);
else if (v == INVISIBLE) db.removeGroupVisibility(txn, c, g); else if (v == INVISIBLE) db.removeGroupVisibility(txn, c, g);
else db.setGroupVisibility(txn, c, g, v == SHARED); else db.setGroupVisibility(txn, c, g, v == SHARED);
List<ContactId> affected = Collections.singletonList(c); List<ContactId> affected = singletonList(c);
transaction.attach(new GroupVisibilityUpdatedEvent(affected)); transaction.attach(new GroupVisibilityUpdatedEvent(affected));
} }
@@ -893,7 +919,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override @Override
public void setMessageState(Transaction transaction, MessageId m, public void setMessageState(Transaction transaction, MessageId m,
State state) throws DbException { MessageState state) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
@@ -910,10 +936,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, dependent.getId())) if (!db.containsMessage(txn, dependent.getId()))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
State dependentState = db.getMessageState(txn, dependent.getId()); MessageState dependentState =
db.getMessageState(txn, dependent.getId());
for (MessageId dependency : dependencies) { for (MessageId dependency : dependencies) {
db.addMessageDependency(txn, dependent, dependency, db.addMessageDependency(txn, dependent, dependency, dependentState);
dependentState);
} }
} }

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

@@ -7,7 +7,6 @@ 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.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
import java.io.File; import java.io.File;
import java.sql.Connection; import java.sql.Connection;
@@ -15,21 +14,31 @@ import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
import static org.briarproject.bramble.util.StringUtils.toHexString;
/** /**
* Contains all the H2-specific code for the database. * Contains all the H2-specific code for the database.
*/ */
@NotNullByDefault @NotNullByDefault
class H2Database extends JdbcDatabase { class H2Database extends JdbcDatabase {
private static final Logger LOG = getLogger(H2Database.class.getName());
private static final String HASH_TYPE = "BINARY(32)"; private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)"; private static final String SECRET_TYPE = "BINARY(32)";
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;
@@ -40,8 +49,7 @@ class H2Database extends JdbcDatabase {
@Inject @Inject
H2Database(DatabaseConfig config, MessageFactory messageFactory, H2Database(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) { Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, super(dbTypes, messageFactory, clock);
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();
@@ -99,7 +107,7 @@ class H2Database extends JdbcDatabase {
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("user", "user"); props.setProperty("user", "user");
// Separate the file password from the user password with a space // Separate the file password from the user password with a space
String hex = StringUtils.toHexString(key.getBytes()); String hex = toHexString(key.getBytes());
props.put("password", hex + " password"); props.put("password", hex + " password");
return DriverManager.getConnection(getUrl(), props); return DriverManager.getConnection(getUrl(), props);
} }
@@ -120,8 +128,8 @@ class H2Database extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s, LOG, WARNING);
tryToClose(c); tryToClose(c, LOG, WARNING);
throw new DbException(e); throw new DbException(e);
} }
} }

View File

@@ -7,29 +7,39 @@ 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.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
import java.io.File; 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.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
import static org.briarproject.bramble.util.StringUtils.toHexString;
/** /**
* Contains all the HSQLDB-specific code for the database. * Contains all the HSQLDB-specific code for the database.
*/ */
@NotNullByDefault @NotNullByDefault
class HyperSqlDatabase extends JdbcDatabase { class HyperSqlDatabase extends JdbcDatabase {
private static final Logger LOG =
getLogger(HyperSqlDatabase.class.getName());
private static final String HASH_TYPE = "BINARY(32)"; private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)"; private static final String SECRET_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY"; private static final String BINARY_TYPE = "BINARY";
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;
@@ -40,8 +50,7 @@ class HyperSqlDatabase extends JdbcDatabase {
@Inject @Inject
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory, HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) { Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, super(dbTypes, messageFactory, clock);
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();
@@ -71,14 +80,14 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s, LOG, WARNING);
tryToClose(c); tryToClose(c, LOG, WARNING);
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();
@@ -105,7 +114,7 @@ class HyperSqlDatabase extends JdbcDatabase {
protected Connection createConnection() throws SQLException { protected Connection createConnection() throws SQLException {
SecretKey key = this.key; SecretKey key = this.key;
if (key == null) throw new IllegalStateException(); if (key == null) throw new IllegalStateException();
String hex = StringUtils.toHexString(key.getBytes()); String hex = toHexString(key.getBytes());
return DriverManager.getConnection(url + ";crypt_key=" + hex); return DriverManager.getConnection(url + ";crypt_key=" + hex);
} }
@@ -121,8 +130,8 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s, LOG, WARNING);
tryToClose(c); tryToClose(c, LOG, WARNING);
throw new DbException(e); throw new DbException(e);
} }
} }

View File

@@ -0,0 +1,42 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class JdbcUtils {
static void tryToClose(@Nullable ResultSet rs, Logger logger, Level level) {
try {
if (rs != null) rs.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Statement s, Logger logger, Level level) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Connection c, Logger logger, Level level) {
try {
if (c != null) c.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
}

View File

@@ -7,15 +7,13 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration38_39 implements Migration<Connection> { class Migration38_39 implements Migration<Connection> {
private static final Logger LOG = private static final Logger LOG = getLogger(Migration38_39.class.getName());
Logger.getLogger(Migration38_39.class.getName());
@Override @Override
public int getStartVersion() { public int getStartVersion() {
@@ -40,16 +38,8 @@ class Migration38_39 implements Migration<Connection> {
+ " ALTER COLUMN contactId" + " ALTER COLUMN contactId"
+ " SET NOT NULL"); + " SET NOT NULL");
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s, LOG, WARNING);
throw new DbException(e); 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

@@ -7,15 +7,13 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration39_40 implements Migration<Connection> { class Migration39_40 implements Migration<Connection> {
private static final Logger LOG = private static final Logger LOG = getLogger(Migration39_40.class.getName());
Logger.getLogger(Migration39_40.class.getName());
@Override @Override
public int getStartVersion() { public int getStartVersion() {
@@ -39,16 +37,8 @@ class Migration39_40 implements Migration<Connection> {
+ " ALTER COLUMN eta" + " ALTER COLUMN eta"
+ " SET NOT NULL"); + " SET NOT NULL");
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s); tryToClose(s, LOG, WARNING);
throw new DbException(e); 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,46 @@
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 static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration40_41 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration40_41.class.getName());
private final DatabaseTypes dbTypes;
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 _STRING"));
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -7,8 +7,6 @@ import org.briarproject.bramble.api.identity.AuthorId;
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 org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.StringUtils;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
@@ -16,6 +14,8 @@ import javax.inject.Inject;
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.AuthorId.LABEL; import static org.briarproject.bramble.api.identity.AuthorId.LABEL;
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
import static org.briarproject.bramble.util.ByteUtils.writeUint32;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
@@ -58,8 +58,8 @@ class AuthorFactoryImpl implements AuthorFactory {
private AuthorId getId(int formatVersion, String name, byte[] publicKey) { private AuthorId getId(int formatVersion, String name, byte[] publicKey) {
byte[] formatVersionBytes = new byte[INT_32_BYTES]; byte[] formatVersionBytes = new byte[INT_32_BYTES];
ByteUtils.writeUint32(formatVersion, formatVersionBytes, 0); writeUint32(formatVersion, formatVersionBytes, 0);
return new AuthorId(crypto.hash(LABEL, formatVersionBytes, return new AuthorId(crypto.hash(LABEL, formatVersionBytes,
StringUtils.toUtf8(name), publicKey)); toUtf8(name), publicKey));
} }
} }

View File

@@ -1,29 +1,22 @@
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 java.util.logging.Logger.getLogger;
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;
@@ -32,7 +25,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
class IdentityManagerImpl implements IdentityManager { class IdentityManagerImpl implements IdentityManager {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(IdentityManagerImpl.class.getName()); getLogger(IdentityManagerImpl.class.getName());
private final DatabaseComponent db; private final DatabaseComponent db;
private final CryptoComponent crypto; private final CryptoComponent crypto;
@@ -75,27 +68,16 @@ class IdentityManagerImpl implements IdentityManager {
LOG.info("No local author to store"); LOG.info("No local author to store");
return; return;
} }
Transaction txn = db.startTransaction(false); db.transaction(false, txn -> db.addLocalAuthor(txn, cached));
try { LOG.info("Local author stored");
db.addLocalAuthor(txn, cached);
db.commitTransaction(txn);
LOG.info("Local author stored");
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
public LocalAuthor getLocalAuthor() throws DbException { public LocalAuthor getLocalAuthor() throws DbException {
if (cachedAuthor == null) { if (cachedAuthor == null) {
Transaction txn = db.startTransaction(true); cachedAuthor =
try { db.transactionWithResult(true, this::loadLocalAuthor);
cachedAuthor = loadLocalAuthor(txn); LOG.info("Local author loaded");
LOG.info("Local author loaded");
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
LocalAuthor cached = cachedAuthor; LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError(); if (cached == null) throw new AssertionError();
@@ -118,26 +100,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

@@ -2,7 +2,7 @@ package org.briarproject.bramble.keyagreement;
class AbortException extends Exception { class AbortException extends Exception {
boolean receivedAbort; final boolean receivedAbort;
AbortException() { AbortException() {
this(false); this(false);

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