Compare commits

..

280 Commits

Author SHA1 Message Date
akwizgran
e1502e6fab Disable image attachments for remote contacts alpha. 2019-06-28 14:22:35 +01:00
akwizgran
d145a082f5 Bump client minor version to avoid triggering crash. 2019-06-28 14:07:28 +01:00
akwizgran
4fd012c31a Merge branch 'compress-images' into 'master'
Compress images

See merge request briar/briar!1147
2019-06-26 14:21:24 +00:00
akwizgran
95d06770bf Rename 'scale' to 'inSampleSize' for clarity. 2019-06-26 14:36:40 +01:00
akwizgran
428247b7b2 Initialise result LiveData before starting task. 2019-06-26 14:31:40 +01:00
akwizgran
a921361a56 Inject ImageSizeCalculator. 2019-06-26 12:40:28 +01:00
akwizgran
fe7dfa721e Compress image attachments. 2019-06-25 16:55:09 +01:00
akwizgran
92eb06a9e9 Refactor attachment creation to use injection. 2019-06-25 16:29:54 +01:00
Torsten Grote
5beed1a748 Merge branch '1594-preview-fails-to-load' into 'master'
Use a fresh LiveData for each attachment creation task

Closes #1594

See merge request briar/briar!1144
2019-06-20 14:05:43 +00:00
Torsten Grote
774047d856 Merge branch '1585-check-attachment-content-type' into 'master'
Improve handling of missing attachments in UI

See merge request briar/briar!1142
2019-06-20 14:04:02 +00:00
Torsten Grote
fc28e7aa88 Merge branch 'nickname-nitpicks' into 'master'
Nickname nitpicks

See merge request briar/briar!1143
2019-06-20 13:41:25 +00:00
Torsten Grote
78459499b2 Merge branch '1593-qr-code-assertion-error' into 'master'
Keep enum methods used by ZXing

Closes #1593

See merge request briar/briar!1146
2019-06-19 23:45:49 +00:00
akwizgran
c2973608d7 Keep enum methods used by ZXing. 2019-06-19 16:36:39 +01:00
akwizgran
be1c33cb42 Use a fresh LiveData for each attachment creation task. 2019-06-19 13:43:04 +01:00
akwizgran
c955466bda Load missing attachments when they arrive. 2019-06-19 12:47:18 +01:00
akwizgran
593a0c4632 Improve handling of missing and invalid attachments. 2019-06-19 11:23:57 +01:00
akwizgran
ed20b2d8d6 Use attachment header to retrieve attachment. 2019-06-19 10:57:13 +01:00
akwizgran
34583e6d2d Merge branch '1054-crash-scroll' into 'master'
Improve crash screen and reporter

Closes #1426, #1061, #1390, #1012, and #1054

See merge request briar/briar!1049
2019-06-18 16:47:02 +00:00
Torsten Grote
ea5a862242 [android] Fix send button in ReportForm's action bar 2019-06-18 13:28:28 -03:00
akwizgran
9ab9e02f8a Trim whitespace from nicknames (useful for auto-complete). 2019-06-18 17:24:08 +01:00
akwizgran
3f70ae3c8c Use same input type for nicknames everywhere. 2019-06-18 17:19:39 +01:00
Torsten Grote
3f60098099 [android] don't cancel crash reports after sending them 2019-06-18 12:21:04 -03:00
Torsten Grote
e965021e3d [android] don't clear task when submitting feedback, only after crash 2019-06-18 12:21:04 -03:00
Torsten Grote
7d9380d3d6 [android] go to homescreen after pressing back in crash reporter
Fixes #1390
2019-06-18 12:21:04 -03:00
Torsten Grote
3c8c0e579e [android] point ACRA to correct BuildConfig class
Fixes #1061
2019-06-18 12:21:03 -03:00
Torsten Grote
bd2bbe9268 [android] don't show JSON in feedback/crash report
use key-value pairs instead

Closes #1426
2019-06-18 12:21:03 -03:00
Torsten Grote
89d24b1753 [android] Make entire report form scrollable, not only the hidden data 2019-06-18 12:21:03 -03:00
Torsten Grote
861dbe20b1 [android] Fix crash screen buttons to the bottom of the screen
and resize crash icon to the available screen space
2019-06-18 12:21:02 -03:00
Torsten Grote
197800de8b [android] split crash report screen into two fragments 2019-06-18 12:21:02 -03:00
Torsten Grote
07e824ad68 [android] Make crash screen scrollable and add icon 2019-06-18 12:21:01 -03:00
Torsten Grote
d210215bd1 Merge branch '1585-new-messaging-client' into 'master'
Add support for image attachments to messaging client

Closes #1585

See merge request briar/briar!1133
2019-06-18 14:55:40 +00:00
akwizgran
00705447ec Use feature flag to decide which version to advertise. 2019-06-18 13:39:01 +01:00
akwizgran
9095ccef85 Filter attachment URIs in controller. 2019-06-18 13:10:52 +01:00
akwizgran
3196204094 Send legacy private messages from headless app. 2019-06-18 13:03:50 +01:00
akwizgran
2bae639105 Upgrade messaging client to support attachments. 2019-06-18 13:03:49 +01:00
akwizgran
f73d298752 Merge branch 'inject-feature-flags' into 'master'
Use injection to provide feature flags

See merge request briar/briar!1140
2019-06-18 11:51:09 +00:00
Torsten Grote
bc3a443276 Merge branch '1590-create-private-messages-on-ui-thread' into 'master'
Move private message creation off the crypto executor

Closes #1590

See merge request briar/briar!1141
2019-06-18 11:22:45 +00:00
akwizgran
2a29d33303 Move private message creation off the crypto executor. 2019-06-18 12:14:10 +01:00
akwizgran
30e0be9f43 Merge branch '1580-show-snackbar' into 'master'
Show snackbar when there is no internet connection

Closes #1580

See merge request briar/briar!1139
2019-06-18 09:54:34 +00:00
akwizgran
3828d16971 Use injection to provide feature flags. 2019-06-18 10:52:21 +01:00
akwizgran
a54eb64eb5 Merge branch '1468-reject-unsupported-images' into 'master'
Reject unsupported images

Closes #1468

See merge request briar/briar!1038
2019-06-17 16:39:26 +00:00
Torsten Grote
ad2d3e70d6 [android] address thread-safety issues of attachment creation 2019-06-17 13:22:38 -03:00
Torsten Grote
1f91842c52 [android] re-use the same LiveData for AttachmentResults 2019-06-17 13:11:16 -03:00
Torsten Grote
c07a0a2fd7 [android] address review comments for rejecting unsupported images 2019-06-17 13:11:16 -03:00
Torsten Grote
4ee4905e06 [android] migrate added conversation header to new LiveEvent 2019-06-17 13:11:16 -03:00
Torsten Grote
67b7517f2b [android] refactor AttachmentCreator to return a single LiveData 2019-06-17 13:11:16 -03:00
Torsten Grote
cd3174a643 [android] Fix view recycling issue of image previews 2019-06-17 13:11:15 -03:00
Torsten Grote
9d9bc4ca84 [android] Let AttachmentCreator return same LiveData after configuration changes 2019-06-17 13:11:15 -03:00
Torsten Grote
7358091699 [android] Address first round of review comments for attachments 2019-06-17 13:11:15 -03:00
Torsten Grote
11eefaedcf Refactor attachment creation 2019-06-17 13:11:14 -03:00
Torsten Grote
bb5a6c0241 [android] Add assertions to TextAttachmentController 2019-06-17 13:11:14 -03:00
Torsten Grote
70d29af2ba [android] Allow sending message with attachments before previews are loaded 2019-06-17 13:11:14 -03:00
Torsten Grote
baedb14e2b [android] allow attaching only of images with supported mime type 2019-06-17 13:11:13 -03:00
Torsten Grote
2796926709 [android] Load image preview from database instead of content Uri 2019-06-17 13:11:13 -03:00
Torsten Grote
fc6275b037 [android] reject invalid mime types for image attachments 2019-06-17 13:11:13 -03:00
Torsten Grote
f76f9be4ed Reject attachments that exceed the allowed size
Closes #1468
2019-06-17 13:11:13 -03:00
Torsten Grote
6167ba5c46 [android] move unsent attachment cache logic into AttachmentController 2019-06-17 13:11:12 -03:00
Torsten Grote
55f4600a69 [android] Create attachments before showing previews 2019-06-17 13:11:12 -03:00
Torsten Grote
c73801c7e8 [android] Show snackbar when there is no internet connection 2019-06-17 10:11:02 -03:00
Torsten Grote
249e1e28fe Merge branch '1580-offline-state' into 'master'
Add offline state for pending contacts

Closes #1580

See merge request briar/briar!1138
2019-06-17 13:10:41 +00:00
akwizgran
f0cea28aeb Don't show a message for the offline state. 2019-06-17 13:45:22 +01:00
Torsten Grote
32e8ea9888 Merge branch '1565-strings-duplicate-handshake-links' into 'master'
Add strings for duplicate pending contacts

See merge request briar/briar!1137
2019-06-17 12:29:22 +00:00
akwizgran
5a1caed89f Rename endpoints field. 2019-06-17 13:22:36 +01:00
akwizgran
22f5c42fc1 Resolve merge conflicts.
# Conflicts:
#   briar-android/src/main/res/values/strings.xml
2019-06-17 12:13:19 +00:00
akwizgran
aab46040a5 Add comments for translators. 2019-06-17 13:12:11 +01:00
akwizgran
18fd238aa1 Merge branch '1580-strings-offline-state' into 'master'
Add string for pending contact offline state

See merge request briar/briar!1136
2019-06-17 11:12:50 +00:00
akwizgran
3a837b3c5a Resolve merge conflicts.
# Conflicts:
#   briar-android/src/main/res/values/strings.xml
2019-06-17 11:04:11 +00:00
akwizgran
ac2597865c Merge branch '1587-version-negotiation' into 'master'
Add version negotiation to sync protocol

Closes #1587

See merge request briar/briar!1134
2019-06-17 10:54:39 +00:00
akwizgran
4a67cf3ce7 Don't cache default state when adding pending contact.
This can overwrite the initial state broadcast by the
rendezvous poller.
2019-06-17 10:22:08 +01:00
Torsten Grote
a5041e651e Merge branch '1230-strings-adding-contact-slow' into 'master'
Add strings for warning when adding a contact is slow

See merge request briar/briar!1135
2019-06-15 13:37:13 +00:00
akwizgran
b0e97d787f Add offline state for pending contacts. 2019-06-15 12:27:24 +01:00
akwizgran
0d8af780a3 Add strings for duplicate pending contacts. 2019-06-15 11:31:18 +01:00
akwizgran
9c20e6b333 Add string for pending contact offline state. 2019-06-15 11:04:22 +01:00
akwizgran
ab14976c96 Add strings for warning when adding a contact is slow. 2019-06-15 11:01:09 +01:00
akwizgran
ec3f821ba6 Update test expectations. 2019-06-13 17:17:50 +01:00
akwizgran
1d546da781 Store sync versions received from contacts. 2019-06-13 17:07:12 +01:00
akwizgran
f2c951b70b Add DB methods for getting and setting sync versions. 2019-06-13 17:06:57 +01:00
akwizgran
1e259c100d Add sync versions column to contacts table. 2019-06-13 16:35:48 +01:00
akwizgran
3636aeba9a Use HyperSQL-compatible syntax in migration. 2019-06-13 16:34:20 +01:00
akwizgran
132e20a6ce Send versions record at start of each session. 2019-06-13 16:16:02 +01:00
akwizgran
c228e5c219 Add versions record to sync protocol. 2019-06-13 16:16:02 +01:00
akwizgran
ae1d1fc5a7 Add thread safety and null safety annotations. 2019-06-13 16:16:01 +01:00
Torsten Grote
37f02a40e9 Merge branch '1585-temporary-messages' into 'master'
Add support for temporary messages

See merge request briar/briar!1132
2019-06-12 15:39:02 +00:00
akwizgran
3c8b8c39e1 Turn commonly used variables into fields. 2019-06-12 16:29:24 +01:00
akwizgran
8f839e2c30 Remove temporary messages at startup. 2019-06-12 15:21:48 +01:00
akwizgran
da4b63f20f Clean up ValidationManagerImplTest. 2019-06-12 15:17:13 +01:00
akwizgran
cd40e771d2 Allow messages to be marked as temporary. 2019-06-12 15:11:10 +01:00
Torsten Grote
dd7accfa95 Merge branch '1576-db-before-signing-in' into 'master'
Retry database tasks after signing in

Closes #1576

See merge request briar/briar!1131
2019-06-10 16:33:47 +00:00
akwizgran
1cf993484d Avoid unnecessary reloads. 2019-06-10 17:24:58 +01:00
akwizgran
e810785fe2 Retry database tasks after signing in. 2019-06-10 15:51:20 +01:00
akwizgran
7ec826ccb7 Merge branch '1562-intent-router' into 'master'
Receive external intents through NavDrawerActivity

Closes #1562

See merge request briar/briar!1128
2019-06-10 14:20:06 +00:00
Torsten Grote
4a4abd7efa Merge branch '1232-polling-events' into 'master'
Show "connecting" state for pending contacts

See merge request briar/briar!1129
2019-06-10 13:11:06 +00:00
Torsten Grote
dc2e42e1f2 [android] don't check getIntent() for null as it should be non-null now 2019-06-10 07:39:49 -03:00
Torsten Grote
1c4d277771 Don't route intents for MANAGE_NETWORK_USAGE settings
This is because we require a special permission to launch this intent
and we prefer requiring this permission to having the NavDrawerActivity
added to the back stack.

This commit also re-adds the deprecated USE_FINGERPRINT permission as
Android Studio would show an error otherwise.
2019-06-10 07:39:48 -03:00
Torsten Grote
fb10ba5855 [android] Receive external intents through NavDrawerActivity
This ensures that our main activity is on the task stack below the
activity opened by an external intent. So when the user navigates back,
they always get back to the main activity.
2019-06-10 07:39:48 -03:00
Torsten Grote
f31b85acdb Merge branch '1564-tor-rendezvous-crypto' into 'master'
Publish hidden service for connecting to pending contact

Closes #1564

See merge request briar/briar!1125
2019-06-09 14:24:40 +00:00
akwizgran
6519706599 Merge branch '1579-remove-pending-contacts-button' into 'master'
Show less obstrusive remove button for pending contacts

Closes #1579

See merge request briar/briar!1130
2019-06-08 09:44:35 +00:00
Torsten Grote
76741bc2ba [android] show less obstrusive remove button for pending contacts
This uses the same button as the RSS feed items
2019-06-07 11:09:34 -03:00
akwizgran
60eefbf3e0 Use named constants. 2019-06-07 11:54:44 +01:00
akwizgran
a4a45efd43 Broadcast event when polling newly added contact. 2019-06-07 11:48:53 +01:00
akwizgran
208ae6a4b6 Show recently polled pending contacts as "connecting". 2019-06-07 11:42:48 +01:00
akwizgran
fe1df6dafa Move pending contact events to rendezvous poller. 2019-06-07 11:42:48 +01:00
akwizgran
15d9ff1ebd Rename "connected" state to "connecting". 2019-06-07 11:42:10 +01:00
akwizgran
dc741e988c Shorter description for "waiting for connection" state. 2019-06-07 11:42:10 +01:00
Torsten Grote
6665235768 Merge branch '1232-pending-contact-states' into 'master'
Add ContactManager support for pending contact states

See merge request briar/briar!1122
2019-06-06 21:31:43 +00:00
akwizgran
ba19716e0f Don't broadcast disabled event whenever we close a socket. 2019-06-06 16:42:26 +01:00
akwizgran
41deff1bf3 Suppress redundant enabled/disabled events. 2019-06-06 16:42:26 +01:00
akwizgran
1ec3fa3ade Implement Tor rendezvous crypto. 2019-06-06 16:42:26 +01:00
akwizgran
64ae99bbce Handle corner cases such as removal during rendezvous. 2019-06-06 16:40:55 +01:00
akwizgran
ed1cefa144 Use concurrent map for pending contact states. 2019-06-06 16:40:54 +01:00
akwizgran
23354d6568 Use predicates to match events. 2019-06-06 16:40:54 +01:00
akwizgran
1aa579a44f Add unit tests for pending contact state. 2019-06-06 16:40:54 +01:00
akwizgran
98191fb059 Add ContactManager support for pending contact states. 2019-06-06 16:40:54 +01:00
Torsten Grote
b9283ea654 Merge branch '1232-rendezvous-poller-expiry' into 'master'
Use periodic poll task for expiry

See merge request briar/briar!1127
2019-06-06 15:12:08 +00:00
akwizgran
71b1f99b56 Use regular poll task for expiry. 2019-06-06 13:45:00 +01:00
Torsten Grote
2982a874d4 Merge branch '1232-rendezvous-poller-cleanup' into 'master'
Small cleanups for rendezvous poller

See merge request briar/briar!1126
2019-06-06 12:04:08 +00:00
akwizgran
ea228164dc Check that poller instance isn't reused. 2019-06-06 12:11:31 +01:00
akwizgran
4b5ad9ace4 Make test expectations modular. 2019-06-06 12:11:31 +01:00
Torsten Grote
a94ffd413c Merge branch '1232-transfer-pending-contact-alias' into 'master'
Transfer pending contact alias to contact

See merge request briar/briar!1124
2019-06-05 17:11:48 +00:00
Torsten Grote
1f921753fd Merge branch '1567-rendezvous-poller' into 'master'
Create poller for rendezvous connections

Closes #1567

See merge request briar/briar!1121
2019-06-05 17:08:31 +00:00
Torsten Grote
157b64e643 Merge branch 'pending-contacts-crash' into 'master'
Don't call setValue() on a background thread

See merge request briar/briar!1123
2019-06-05 16:57:04 +00:00
akwizgran
6f285c5b0a Transfer pending contact alias to contact. 2019-06-05 17:48:02 +01:00
akwizgran
bf39c30d24 Don't call setValue() on a background thread. 2019-06-05 17:45:12 +01:00
akwizgran
7439e5579f Let plugins know if we're Alice or Bob. 2019-06-05 11:23:56 +01:00
akwizgran
4452dacc94 Make RendezvousCrypto package-private. 2019-06-05 11:01:28 +01:00
akwizgran
0579157010 Include protocol version in rendezvous key derivation. 2019-06-05 10:59:21 +01:00
akwizgran
3dbd0b80aa Make rendezvous constants package-private. 2019-06-05 10:58:12 +01:00
akwizgran
3863df3c1f Poll pending contact immediately when added. 2019-06-05 10:44:08 +01:00
akwizgran
08a5b8393f Add unit test for starting rendezvous poller. 2019-06-05 10:44:07 +01:00
akwizgran
92dea21c67 Run commit actions in unit tests. 2019-06-05 10:44:07 +01:00
akwizgran
82a52638cf Derive rendezvous key from static master key. 2019-06-05 10:44:07 +01:00
akwizgran
a38113e862 Add rendezvous poller. 2019-06-05 10:44:07 +01:00
akwizgran
7fd8ad65be Make RendezvousEndpoint closeable. 2019-06-05 10:44:06 +01:00
akwizgran
ce9c7cb32a Add requireNull() utility method. 2019-06-05 10:44:06 +01:00
akwizgran
5d2252ebda Add method for deriving rendezvous key. 2019-06-05 10:44:06 +01:00
akwizgran
3820d7413c Rename rendezvous handler to endpoint. 2019-06-05 10:44:06 +01:00
akwizgran
ab90e1de04 Pass incoming connection handler to plugins. 2019-06-05 10:44:05 +01:00
Torsten Grote
a650d812fa Merge branch '1571-connection-manager-pending-contacts' into 'master'
Add rendezvous connection support to connection manager

Closes #1571

See merge request briar/briar!1120
2019-06-04 14:08:05 +00:00
akwizgran
c536782e01 Remove redundant use of IO executor. 2019-06-04 14:23:47 +01:00
akwizgran
9ffd1ec2c2 Unregister connection if sending stream header fails. 2019-06-04 14:20:57 +01:00
Torsten Grote
1c56068bf1 Merge branch '1232-handshake-manager' into 'master'
Implement handshake protocol

See merge request briar/briar!1118
2019-06-04 11:49:11 +00:00
Torsten Grote
d2290e2037 Merge branch '1560-forum-sharing-integration-test' into 'master'
Fix race conditions in ForumSharingIntegrationTest

Closes #1560

See merge request briar/briar!1119
2019-06-04 11:47:49 +00:00
akwizgran
0951508af7 Define PROOF_BYTES as MAC_BYTES. 2019-06-04 12:38:21 +01:00
akwizgran
34a5b69100 Reuse TransportCrypto#isAlice(). 2019-06-04 12:21:17 +01:00
akwizgran
d939fe80bd Explicitly check length of proof of ownership. 2019-06-04 12:17:10 +01:00
akwizgran
4ea8a4732c Fix race conditions in ForumSharingIntegrationTest. 2019-06-04 11:57:39 +01:00
Torsten Grote
da67cae4ce Merge branch 'test-sync-at-higher-level' into 'master'
Test sync at a higher level

See merge request briar/briar!1116
2019-06-04 10:37:31 +00:00
akwizgran
d3c7ecdef4 Use static comparison method. 2019-06-03 18:02:19 +01:00
akwizgran
4d8e0baeb4 Rewrap a line. 2019-06-03 17:58:31 +01:00
akwizgran
0b764a01dd Use larger buffer in test connections to prevent deadlock. 2019-06-03 17:55:35 +01:00
akwizgran
f95bb9b28e Add integration test for new connection manager methods. 2019-06-03 17:55:35 +01:00
akwizgran
8f21e07840 Add rendezvous connection support to connection manager. 2019-06-03 17:52:43 +01:00
akwizgran
eed8d25120 Decouple HandshakeManager from ContactExchangeManager. 2019-06-03 17:44:38 +01:00
Torsten Grote
265a43f5ff Merge branch 'use-real-executors-in-integration-tests' into 'master'
Use BrambleCoreModule in integration tests

See merge request briar/briar!1115
2019-06-03 14:48:53 +00:00
akwizgran
89cbdc824c Add integration test for handshaking with pending contact. 2019-06-03 15:36:28 +01:00
akwizgran
4640651714 Add integration test for converting pending contacts. 2019-06-03 15:36:27 +01:00
akwizgran
af8b7f1130 Implement getHandshakeLink(). 2019-06-03 15:36:27 +01:00
akwizgran
643270e247 Add integration test for ContactExchangeManager. 2019-06-03 15:36:24 +01:00
akwizgran
24f1b7eeca Implement handshake manager. 2019-06-03 15:35:53 +01:00
akwizgran
60155f146a Add contact exchange method for pending contacts. 2019-06-03 15:35:53 +01:00
akwizgran
7c3f2c0bed Add test implementation of DuplexTransportConnection. 2019-06-03 15:35:00 +01:00
akwizgran
85a1fd2caa Convert BriarIntegrationTest to use test reader and writer. 2019-06-03 15:34:59 +01:00
akwizgran
f8d240a320 Test stream reading and writing at a higher level. 2019-06-03 15:34:59 +01:00
akwizgran
5860c723de Remove unused test module. 2019-06-03 15:34:59 +01:00
akwizgran
33d35148d8 Run briar-headless tests when running all tests. 2019-06-03 15:34:17 +01:00
akwizgran
0e55b06c0a Provide SOCKS module for headless app, remove reporting. 2019-06-03 15:34:17 +01:00
akwizgran
d964f06de1 Use default methods for easier maintenance. 2019-06-03 15:34:16 +01:00
akwizgran
100e17b242 Use BrambleCoreModule in integration tests. 2019-06-03 15:34:16 +01:00
akwizgran
7bf86d9c53 Use real executors in integration tests. 2019-06-03 15:34:16 +01:00
Torsten Grote
8fc5c21354 Merge branch '1570-derive-handshake-root-key' into 'master'
Add contact manager and key manager methods for converting a pending contact

Closes #1570

See merge request briar/briar!1114
2019-06-03 14:33:21 +00:00
akwizgran
fe83a59d2a Add comment about tag reuse. 2019-06-03 12:48:14 +01:00
akwizgran
1b8692a216 Add longer explanation of 'verified' flag. 2019-06-03 12:40:49 +01:00
akwizgran
57a70f411b Update ContactManager javadocs. 2019-05-31 11:59:00 +01:00
akwizgran
b2d2b1765a Fix pending contact flag. Hooray for unit tests. 2019-05-30 17:37:09 +01:00
akwizgran
430b530ca5 Derive handshake root key when converting pending contact. 2019-05-30 17:27:07 +01:00
akwizgran
4a2936c685 Optionally include handshake public key for new contact. 2019-05-30 16:36:25 +01:00
Torsten Grote
d3c7c54797 Merge branch '1561-wait-for-delivery-in-integration-test' into 'master'
Wait for message delivery in integration test

Closes #1561

See merge request briar/briar!1113
2019-05-30 15:25:08 +00:00
akwizgran
83dc52572d Remove keys when pending contacts are removed. 2019-05-30 16:20:57 +01:00
akwizgran
810d45d6b9 Derive handshake root key when adding a pending contact. 2019-05-30 15:48:26 +01:00
akwizgran
9b4f60088f Add methods for deriving static master and root keys. 2019-05-30 14:31:12 +01:00
akwizgran
b222107044 Add static method for comparing byte arrays. 2019-05-30 14:30:16 +01:00
akwizgran
d0495b7c00 Wait for transport properties as well as client versions. 2019-05-30 13:55:16 +01:00
akwizgran
ee874947d0 Wait for message delivery in integration test. 2019-05-30 11:51:16 +01:00
akwizgran
d38176faea Merge branch '1571-connection-manager-cleanup' into 'master'
Clean up connection manager, ready for pending contacts

See merge request briar/briar!1109
2019-05-29 15:16:35 +00:00
Torsten Grote
2a00f94e23 Merge branch '1571-connection-registry-pending-contacts' into 'master'
Add support for pending contacts to connection registry

See merge request briar/briar!1111
2019-05-28 14:36:42 +00:00
akwizgran
8bd4278ae5 Add support for pending contacts to connection registry. 2019-05-28 14:33:03 +01:00
akwizgran
829a6df567 Remove redundant assignment. 2019-05-28 14:15:47 +01:00
akwizgran
aa0c3118a0 Interrupt outgoing session on read error. 2019-05-28 10:45:55 +01:00
Torsten Grote
015f5005d0 Merge branch '1232-get-pending-contact' into 'master'
Add method to get a pending contact

See merge request briar/briar!1110
2019-05-27 17:51:59 +00:00
Torsten Grote
91c5ec6f18 Merge branch '1232-triple-dh' into 'master'
Implement triple Diffie-Hellman key agreement

See merge request briar/briar!1108
2019-05-27 17:49:05 +00:00
Torsten Grote
cd9cc375ff Merge branch '1570-convert-pending-contact' into 'master'
Add database methods for converting a pending contact

Closes #1570

See merge request briar/briar!1107
2019-05-27 17:45:26 +00:00
akwizgran
819deca93c Update javadoc. 2019-05-27 17:54:23 +01:00
akwizgran
79632908d4 Add method to get a pending contact. 2019-05-27 17:44:57 +01:00
akwizgran
f979d44c96 Update REST API docs. 2019-05-27 17:43:23 +01:00
akwizgran
44d2526997 Add triple Diffie-Hellman key agreement. 2019-05-27 15:03:58 +01:00
akwizgran
14e604e21e Add 'verified' flag to ContactAddedEvent. 2019-05-27 11:40:28 +01:00
akwizgran
677728b9ae Add database methods for converting a pending contact. 2019-05-27 11:19:21 +01:00
akwizgran
84060a57da Merge branch 'unsupported-handshake-link' into 'master'
Add error message for unsupported handshake link version

See merge request briar/briar!1091
2019-05-26 14:36:24 +00:00
Torsten Grote
4a92625a7b Merge branch 'contact-exchange-refactoring' into 'master'
Contact exchange refactoring

See merge request briar/briar!1106
2019-05-24 17:33:21 +00:00
Torsten Grote
bea526d64d [android] tweak wording for unsupported link version 2019-05-24 14:31:04 -03:00
akwizgran
717b2d176e Clean up connection manager, ready for pending contacts. 2019-05-24 18:08:06 +01:00
Torsten Grote
cff5e53d09 Merge branch 'record-reader-predicates' into 'master'
Use predicates to specify records to accept or ignore

See merge request briar/briar!1105
2019-05-24 16:16:24 +00:00
akwizgran
221687c9d7 Merge branch 'startup-fix' into 'master'
Show OpenDatabaseFragment right after signing in

See merge request briar/briar!1099
2019-05-24 15:06:41 +00:00
akwizgran
953fccba16 Update PendingContactListener to use PendingContactItem. 2019-05-24 15:57:24 +01:00
akwizgran
eca82e2888 Merge branch '1554-remove-pending-contacts' into 'master'
Allow pending contacts to be removed at any time

Closes #1554

See merge request briar/briar!1098
2019-05-24 14:49:48 +00:00
Torsten Grote
ad93100e99 Merge branch '35-transaction-manager' into 'master'
Extract TransactionManager from DatabaseComponent

See merge request briar/briar!1104
2019-05-24 13:20:35 +00:00
akwizgran
d80c77f466 Try to close connection if contact exchange fails. 2019-05-24 13:14:53 +01:00
akwizgran
a6376af7c2 Extract TransactionManager from DatabaseComponent. 2019-05-24 12:44:23 +01:00
akwizgran
f1e5c2dd66 Return a contact, encapsulate contact exchange crypto. 2019-05-24 11:42:30 +01:00
akwizgran
5be0e928c4 Replace events with return value and exceptions. 2019-05-24 10:53:43 +01:00
akwizgran
bcc899eebf Attach information to ContactExistsException. 2019-05-24 10:53:43 +01:00
akwizgran
9ea91cbb3e Move background work into view model. 2019-05-24 10:51:38 +01:00
akwizgran
da54712ae1 Refactor ContactExchangeTask into reusable manager. 2019-05-24 10:51:38 +01:00
akwizgran
f459115b19 Run contact exchange task on IO executor. 2019-05-24 10:51:38 +01:00
akwizgran
cc49648e37 Use predicates to specify records to accept or ignore. 2019-05-24 10:51:27 +01:00
Torsten Grote
9ce71088e2 Merge branch '1564-rendezvous-plugin-api' into 'master'
Add rendezvous API to transport plugins

See merge request briar/briar!1103
2019-05-22 16:58:31 +00:00
Torsten Grote
0f3e6d9736 Merge branch '1567-remove-pending-contact-state-from-db' into 'master'
Remove pending contact state from DB

See merge request briar/briar!1102
2019-05-22 16:56:59 +00:00
akwizgran
de97cce119 Address review comments. 2019-05-22 17:46:17 +01:00
akwizgran
a82d20564a Update names in RendezvousModule. 2019-05-22 16:13:49 +01:00
akwizgran
967f068637 Add initial API for rendezvous plugins. 2019-05-22 15:26:28 +01:00
akwizgran
90c33133c3 Code cleanup. 2019-05-22 15:22:35 +01:00
akwizgran
01ef367864 Remove pending contact state from the database. 2019-05-22 11:25:05 +01:00
Torsten Grote
da5d442c91 Merge branch '1232-poller-refactoring' into 'master'
Pass a connection handler to plugins when polling

See merge request briar/briar!1101
2019-05-21 13:33:53 +00:00
akwizgran
ead7570ec5 Add javadoc. 2019-05-21 14:27:27 +01:00
akwizgran
43b2f9da1c Static import. 2019-05-17 15:46:37 +01:00
akwizgran
668433dd62 Pass a connection handler to plugins when polling. 2019-05-17 14:07:54 +01:00
akwizgran
a0772852de Decouple poller from plugin manager. 2019-05-17 13:59:30 +01:00
Torsten Grote
f0bd18c4d6 [android] show OpenDatabaseFragment right after signing in 2019-05-16 15:22:56 -03:00
akwizgran
99000d8eab Merge branch 'repro-check-on-success' into 'master'
Only check reproducibility when normal tests pass

See merge request briar/briar!1100
2019-05-16 16:58:33 +00:00
Torsten Grote
0b48afb692 Only check reproducibility when normal tests pass 2019-05-16 13:48:25 -03:00
Torsten Grote
299ad07222 [android] Allow pending contacts to be removed at any time 2019-05-16 12:54:42 -03:00
akwizgran
37d0b61d7b Bump version numbers for 1.1.7 release. 2019-05-16 16:07:15 +01:00
akwizgran
98a1ec89d7 Update translations. 2019-05-16 16:06:29 +01:00
akwizgran
a61860af85 Merge branch '1369-thread-layout' into 'master'
Adapt private group join notices to new threaded layout

Closes #1369

See merge request briar/briar!1097
2019-05-16 14:54:46 +00:00
Torsten Grote
90437f4fa4 [android] use same color for thread dividers than indentation dividers 2019-05-16 11:35:20 -03:00
Torsten Grote
06212453b2 [android] Adapt private group join notices to new threaded layout 2019-05-16 11:12:48 -03:00
akwizgran
ddc9b5b066 Merge branch '1256-adding-contacts-headless' into 'master'
Add a REST endpoint for adding contacts

Closes #1256

See merge request briar/briar!1094
2019-05-16 14:05:48 +00:00
Torsten Grote
0aa6166afa Merge branch 'account-logging' into 'master'
Log contents of account directory for debugging

See merge request briar/briar!1096
2019-05-16 11:51:46 +00:00
akwizgran
60b91bc317 Log contents of account directory for debugging. 2019-05-16 10:06:16 +01:00
akwizgran
20481a3790 Merge branch '1369-thread-layout' into 'master'
Move AuthorView up in threaded conversation

Closes #1369

See merge request briar/briar!1095
2019-05-16 08:46:39 +00:00
Torsten Grote
576934910e Merge branch '1566-equivalent-public-keys' into 'master'
Add tests for equivalent handshake public keys

See merge request briar/briar!1093
2019-05-15 20:02:52 +00:00
Torsten Grote
4abc26093e Merge branch '1556-key-manager-methods-for-pending-contacts' into 'master'
Add key manager methods for pending contacts

Closes #1556

See merge request briar/briar!1089
2019-05-15 19:57:32 +00:00
Torsten Grote
aed63746e7 [android] Move AuthorView up in threaded conversation 2019-05-15 16:33:06 -03:00
Torsten Grote
816598b631 [headless] only include alias in contact's JSON representation if it exists 2019-05-15 16:03:02 -03:00
Torsten Grote
c062c16d27 Merge branch 'merge-handshake-and-transport-keys' into 'master'
Add support for handshake keys to KeyManager

See merge request briar/briar!1088
2019-05-15 16:27:33 +00:00
Torsten Grote
435b43488a [headless] address review comments for remote contact adding 2019-05-15 12:36:33 -03:00
Torsten Grote
faa6a85148 [headless] Add tests to ensure that remote contact adding needs auth token 2019-05-15 11:28:01 -03:00
Torsten Grote
3770a9f217 [headless] make events related to adding contacts available via websocket 2019-05-15 11:28:01 -03:00
Torsten Grote
c6211be488 [bramble-core] Broadcast events when pending contacts are added or removed 2019-05-15 11:27:59 -03:00
Torsten Grote
5a73e50248 [headless] expose ContactManager methods for adding contacts remotely 2019-05-15 11:26:21 -03:00
Torsten Grote
dc6971734a [briar-core] Add a getRealHandshakeLink() method to BriarTestUtils
Also allow testOutput from briar-core to be used in briar-headless
2019-05-15 11:26:20 -03:00
Torsten Grote
69e57bee61 [bramble] Let TestUtils return a PendingContact with random state 2019-05-15 11:26:19 -03:00
Torsten Grote
af8cabbb28 [headless] update dependencies 2019-05-15 11:25:11 -03:00
akwizgran
6f31a3c2ad Merge branch 'key-pair-refactoring' into 'master'
Key pair refactoring

See merge request briar/briar!1083
2019-05-15 14:19:48 +00:00
akwizgran
d3469e3782 Merge branch '1482-startup-activity' into 'master'
Combine Password and OpenDatabase Activity into StartupActivity

Closes #1482

See merge request briar/briar!1087
2019-05-15 09:57:01 +00:00
akwizgran
9d64b186ff Add tests for hashing public keys into shared secret. 2019-05-15 10:18:13 +01:00
akwizgran
ca591b5c7b Add test for equivalent public keys. 2019-05-15 10:18:09 +01:00
akwizgran
2c4188caf5 Use lambdas for tasks requiring a manager lookup. 2019-05-14 17:59:35 +01:00
akwizgran
0b30a0786e Rename key manager methods for clarity. 2019-05-14 17:59:35 +01:00
akwizgran
f9b928c12a Annotate equals() argument as nullable. 2019-05-14 17:59:35 +01:00
akwizgran
afa0b96293 Add utility method for null checks. 2019-05-14 17:59:34 +01:00
akwizgran
dd50f4bcd4 Add key manager methods for pending contacts. 2019-05-14 17:59:34 +01:00
akwizgran
f42fc5213e Add key manager method for contacts with handshake keys. 2019-05-14 17:59:34 +01:00
akwizgran
84e2402404 Update key management terminology. 2019-05-14 17:57:23 +01:00
akwizgran
5adc9d8dbd Add handshake keys to TransportKeyManagerImpl. 2019-05-14 17:57:22 +01:00
akwizgran
3f51ad6c07 Add handshake mode to MutableTransportKeys. 2019-05-14 17:57:22 +01:00
akwizgran
1fd6d7a6d5 Use @GuardedBy annotation. 2019-05-14 17:57:22 +01:00
akwizgran
7dc4dc566f Merge handshake and transport keys. 2019-05-14 17:57:19 +01:00
akwizgran
658c63d94e Rename an argument for clarity. 2019-05-14 17:56:19 +01:00
akwizgran
ee05c32871 Allow pending contact state update not to affect any rows. 2019-05-14 17:55:38 +01:00
akwizgran
d2951eb3cd Rename key parser classes. 2019-05-14 17:26:28 +01:00
akwizgran
de8a60ea21 Use PublicKey and PrivateKey everywhere. 2019-05-14 17:26:26 +01:00
akwizgran
0e77a47cc1 Refactor key handling to use public classes. 2019-05-14 17:24:19 +01:00
Torsten Grote
19ec98b607 [android] use exception instead of string resource in LiveResult 2019-05-13 13:21:58 -03:00
Torsten Grote
ec7fdb3f72 [android] Pass the entire link to the backend, so newer version have a chance to arrive 2019-05-13 12:00:18 -03:00
Torsten Grote
be8aba347d [android] Add error message for unsupported handshake link version 2019-05-13 12:00:18 -03:00
Torsten Grote
22ebdd8e42 [android] Ensure keyboard is shown for entering password
in new StartupActivity and when creating a new account.
2019-05-13 11:58:07 -03:00
Torsten Grote
e37ee7ee04 [android] Use LiveEvent to communicate password validation and account deletion 2019-05-13 08:21:28 -03:00
Torsten Grote
5676e18a22 [android] StartupActivity: Address first round of review comments 2019-05-13 08:21:28 -03:00
Torsten Grote
5ece6505da [android] Combine Password and OpenDatabase Activity into StartupActivity 2019-05-13 08:21:27 -03:00
495 changed files with 15480 additions and 7529 deletions

View File

@@ -1,6 +1,11 @@
image: briar/ci-image-android:latest
stages:
- test
- check_reproducibility
test:
stage: test
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
@@ -21,6 +26,7 @@ test:
test_reproducible:
stage: check_reproducibility
script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only:

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All in briar-headless" type="AndroidJUnit" factoryName="Android JUnit" nameIsGenerated="true">
<module name="briar-headless" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-headless" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

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

View File

@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-headless" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/briar-headless" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -11,8 +11,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10106
versionName "1.1.6"
versionCode 10107
versionName "1.1.7"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

View File

@@ -2,10 +2,13 @@ package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.reporting.ReportingModule;
public interface BrambleAndroidEagerSingletons {
void inject(AndroidBatteryModule.EagerSingletons init);
void inject(AndroidNetworkModule.EagerSingletons init);
void inject(ReportingModule.EagerSingletons init);
}

View File

@@ -3,6 +3,8 @@ package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module;
@@ -11,12 +13,15 @@ import dagger.Module;
AndroidBatteryModule.class,
AndroidNetworkModule.class,
AndroidSystemModule.class,
CircumventionModule.class
CircumventionModule.class,
ReportingModule.class,
SocksModule.class
})
public class BrambleAndroidModule {
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
c.inject(new AndroidBatteryModule.EagerSingletons());
c.inject(new AndroidNetworkModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons());
}
}

View File

@@ -9,7 +9,6 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
import java.util.HashSet;
@@ -20,6 +19,9 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.logging.Level.INFO;
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
import static org.briarproject.bramble.util.LogUtils.logFileOrDir;
class AndroidAccountManager extends AccountManagerImpl
implements AccountManager {
@@ -41,6 +43,16 @@ class AndroidAccountManager extends AccountManagerImpl
appContext = app.getApplicationContext();
}
@Override
public boolean accountExists() {
boolean exists = super.accountExists();
if (!exists && LOG.isLoggable(INFO)) {
LOG.info("Account does not exist. Contents of account directory:");
logFileOrDir(LOG, INFO, getDataDir());
}
return exists;
}
// Locking: stateChangeLock
@Override
@Nullable
@@ -74,9 +86,17 @@ class AndroidAccountManager extends AccountManagerImpl
@Override
public void deleteAccount() {
synchronized (stateChangeLock) {
if (LOG.isLoggable(INFO)) {
LOG.info("Contents of account directory before deleting:");
logFileOrDir(LOG, INFO, getDataDir());
}
super.deleteAccount();
SharedPreferences defaultPrefs = getDefaultSharedPreferences();
deleteAppData(prefs, defaultPrefs);
if (LOG.isLoggable(INFO)) {
LOG.info("Contents of account directory after deleting:");
logFileOrDir(LOG, INFO, getDataDir());
}
}
}
@@ -94,7 +114,7 @@ class AndroidAccountManager extends AccountManagerImpl
}
// Delete files, except lib and shared_prefs directories
Set<File> files = new HashSet<>();
File dataDir = new File(appContext.getApplicationInfo().dataDir);
File dataDir = getDataDir();
@Nullable
File[] fileArray = dataDir.listFiles();
if (fileArray == null) {
@@ -121,13 +141,17 @@ class AndroidAccountManager extends AccountManagerImpl
}
}
for (File file : files) {
IoUtils.deleteFileOrDir(file);
deleteFileOrDir(file);
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdirs())
LOG.warning("Could not recreate cache dir");
}
private File getDataDir() {
return new File(appContext.getApplicationInfo().dataDir);
}
private void addIfNotNull(Set<File> files, @Nullable File file) {
if (file != null) files.add(file);
}

View File

@@ -12,8 +12,8 @@ import android.content.IntentFilter;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
@@ -51,6 +51,7 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@@ -58,7 +59,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG =
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
@@ -75,7 +76,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Clock clock,
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
Backoff backoff, PluginCallback callback, int maxLatency) {
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency);
this.androidExecutor = androidExecutor;

View File

@@ -6,9 +6,9 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
@@ -61,7 +61,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
public DuplexPlugin createPlugin(PluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl();
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,

View File

@@ -13,7 +13,7 @@ import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.PluginCallback;
import java.io.IOException;
import java.net.InetAddress;
@@ -32,17 +32,18 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private static final Logger LOG =
getLogger(AndroidLanTcpPlugin.class.getName());
private static final byte[] WIFI_AP_ADDRESS_BYTES =
{(byte) 192, (byte) 168, 43, 1};
private static final InetAddress WIFI_AP_ADDRESS;
private static final Logger LOG =
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
static {
try {
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
@@ -60,7 +61,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
Backoff backoff, PluginCallback callback, int maxLatency,
int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
// Don't execute more than one connection status check at a time

View File

@@ -6,9 +6,9 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import java.util.concurrent.Executor;
@@ -51,7 +51,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
public DuplexPlugin createPlugin(PluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,

View File

@@ -11,7 +11,7 @@ import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
@@ -41,11 +41,12 @@ class AndroidTorPlugin extends TorPlugin {
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, callback, architecture, maxLatency, maxIdleTime,
backoff, torRendezvousCrypto, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)

View File

@@ -9,10 +9,10 @@ import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
@@ -84,7 +84,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
public DuplexPlugin createPlugin(PluginCallback callback) {
// Check that we have a Tor binary for this architecture
String architecture = null;
@@ -106,10 +106,12 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -128,7 +128,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
oneOf(app).getApplicationInfo();
allowing(app).getApplicationInfo();
will(returnValue(applicationInfo));
oneOf(app).getFilesDir();
will(returnValue(filesDir));

View File

@@ -4,8 +4,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import java.util.Arrays;
import java.util.Comparator;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
@@ -15,8 +15,6 @@ import javax.annotation.concurrent.ThreadSafe;
@NotNullByDefault
public class Bytes implements Comparable<Bytes> {
public static final BytesComparator COMPARATOR = new BytesComparator();
private final byte[] bytes;
private int hashCode = -1;
@@ -38,20 +36,13 @@ public class Bytes implements Comparable<Bytes> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
return o instanceof Bytes && Arrays.equals(bytes, ((Bytes) o).bytes);
}
@Override
public int compareTo(Bytes other) {
byte[] aBytes = bytes, bBytes = other.bytes;
int length = Math.min(aBytes.length, bBytes.length);
for (int i = 0; i < length; i++) {
int aUnsigned = aBytes[i] & 0xFF, bUnsigned = bBytes[i] & 0xFF;
if (aUnsigned < bUnsigned) return -1;
if (aUnsigned > bUnsigned) return 1;
}
return aBytes.length - bBytes.length;
return compare(bytes, other.bytes);
}
@Override
@@ -60,11 +51,13 @@ public class Bytes implements Comparable<Bytes> {
"(" + StringUtils.toHexString(getBytes()) + ")";
}
public static class BytesComparator implements Comparator<Bytes> {
@Override
public int compare(Bytes a, Bytes b) {
return a.compareTo(b);
public static int compare(byte[] a, byte[] b) {
int length = Math.min(a.length, b.length);
for (int i = 0; i < length; i++) {
int aUnsigned = a[i] & 0xFF, bUnsigned = b[i] & 0xFF;
if (aUnsigned < bUnsigned) return -1;
if (aUnsigned > bUnsigned) return 1;
}
return a.length - b.length;
}
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.bramble.api;
/**
* Interface for specifying which features are enabled in a build.
*/
public interface FeatureFlags {
boolean shouldEnableImageAttachments();
boolean shouldEnableRemoteContacts();
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface Predicate<T> {
boolean test(T t);
}

View File

@@ -1,6 +1,8 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.DbException;
@@ -23,7 +25,10 @@ public interface ClientHelper {
throws DbException, FormatException;
void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException;
boolean shared, boolean temporary)
throws DbException, FormatException;
Message createMessage(GroupId g, long timestamp, byte[] body);
Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException;
@@ -96,14 +101,18 @@ public interface ClientHelper {
BdfList toList(Author a);
byte[] sign(String label, BdfList toSign, byte[] privateKey)
byte[] sign(String label, BdfList toSign, PrivateKey privateKey)
throws FormatException, GeneralSecurityException;
void verifySignature(byte[] signature, String label, BdfList signed,
byte[] publicKey) throws FormatException, GeneralSecurityException;
PublicKey publicKey)
throws FormatException, GeneralSecurityException;
Author parseAndValidateAuthor(BdfList author) throws FormatException;
PublicKey parseAndValidateAgreementPublicKey(byte[] publicKeyBytes)
throws FormatException;
TransportProperties parseAndValidateTransportProperties(
BdfDictionary properties) throws FormatException;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -8,7 +9,6 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@Immutable
@@ -21,21 +21,17 @@ public class Contact {
@Nullable
private final String alias;
@Nullable
private final byte[] handshakePublicKey;
private final PublicKey handshakePublicKey;
private final boolean verified;
public Contact(ContactId id, Author author, AuthorId localAuthorId,
@Nullable String alias, @Nullable byte[] handshakePublicKey,
@Nullable String alias, @Nullable PublicKey handshakePublicKey,
boolean verified) {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
if (handshakePublicKey != null && (handshakePublicKey.length == 0 ||
handshakePublicKey.length > MAX_PUBLIC_KEY_LENGTH)) {
throw new IllegalArgumentException();
}
this.id = id;
this.author = author;
this.localAuthorId = localAuthorId;
@@ -62,7 +58,7 @@ public class Contact {
}
@Nullable
public byte[] getHandshakePublicKey() {
public PublicKey getHandshakePublicKey() {
return handshakePublicKey;
}

View File

@@ -0,0 +1,37 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
@NotNullByDefault
public interface ContactExchangeManager {
/**
* Exchanges contact information with a remote peer and adds the peer
* as a contact.
*
* @param alice Whether the local peer takes the role of Alice
* @return The newly added contact
* @throws ContactExistsException If the contact already exists
*/
Contact exchangeContacts(DuplexTransportConnection conn,
SecretKey masterKey, boolean alice, boolean verified)
throws IOException, DbException;
/**
* Exchanges contact information with a remote peer and adds the peer
* as a contact, replacing the given pending contact.
*
* @param alice Whether the local peer takes the role of Alice
* @return The newly added contact
* @throws ContactExistsException If the contact already exists
*/
Contact exchangeContacts(PendingContactId p, DuplexTransportConnection conn,
SecretKey masterKey, boolean alice, boolean verified)
throws IOException, DbException;
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
@@ -28,7 +29,7 @@ public class ContactId {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
return o instanceof ContactId && id == ((ContactId) o).id;
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
@@ -12,6 +13,7 @@ import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException;
import java.util.Collection;
import javax.annotation.Nullable;
@@ -28,28 +30,71 @@ public interface ContactManager {
/**
* Stores a contact associated with the given local and remote pseudonyms,
* derives and stores transport keys for each transport, and returns an ID
* for the contact.
* derives and stores rotation mode transport keys for each transport, and
* returns an ID for the contact.
*
* @param alice true if the local party is Alice
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
SecretKey rootKey, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* replacing the given pending contact, derives and stores handshake mode
* and rotation mode transport keys for each transport, and returns an ID
* for the contact.
*
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
* @throws GeneralSecurityException If the pending contact's handshake
* public key is invalid
*/
ContactId addContact(Transaction txn, PendingContactId p, Author remote,
AuthorId local, SecretKey rootKey, long timestamp, boolean alice,
boolean verified, boolean active)
throws DbException, GeneralSecurityException;
/**
* Stores a contact associated with the given local and remote pseudonyms
* and returns an ID for the contact.
*
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
boolean verified) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* derives and stores transport keys for each transport, and returns an ID
* for the contact.
* derives and stores rotation mode transport keys for each transport, and
* returns an ID for the contact.
*
* @param alice true if the local party is Alice
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
*/
ContactId addContact(Author remote, AuthorId local, SecretKey rootKey,
long timestamp, boolean alice, boolean verified, boolean active)
@@ -65,20 +110,29 @@ public interface ContactManager {
* Creates a {@link PendingContact} from the given handshake link and
* alias, adds it to the database and returns it.
*
* @param link The handshake 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
* @param link The handshake link received from the pending contact
* @param alias The alias the user has given this pending contact
* @throws UnsupportedVersionException If the link uses a format version
* that is not supported
* @throws FormatException If the link is invalid
* @throws GeneralSecurityException If the pending contact's handshake
* public key is invalid
*/
PendingContact addPendingContact(String link, String alias)
throws DbException, FormatException;
throws DbException, FormatException, GeneralSecurityException;
/**
* Returns a list of {@link PendingContact}s.
* Returns the pending contact with the given ID.
*/
Collection<PendingContact> getPendingContacts() throws DbException;
PendingContact getPendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Returns a list of {@link PendingContact PendingContacts} and their
* {@link PendingContactState states}.
*/
Collection<Pair<PendingContact, PendingContactState>> getPendingContacts()
throws DbException;
/**
* Removes a {@link PendingContact}.
@@ -91,8 +145,13 @@ public interface ContactManager {
Contact getContact(ContactId c) throws DbException;
/**
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
* Returns the contact with the given ID.
*/
Contact getContact(Transaction txn, ContactId c) throws DbException;
/**
* Returns the contact with the given {@code remoteAuthorId}
* that belongs to the local pseudonym with the given {@code localAuthorId}.
*
* @throws NoSuchContactException If the contact is not in the database
*/
@@ -100,8 +159,8 @@ public interface ContactManager {
throws DbException;
/**
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
* Returns the contact with the given {@code remoteAuthorId}
* that belongs to the local pseudonym with the given {@code localAuthorId}.
*
* @throws NoSuchContactException If the contact is not in the database
*/
@@ -109,7 +168,7 @@ public interface ContactManager {
AuthorId localAuthorId) throws DbException;
/**
* Returns all active contacts.
* Returns all contacts.
*/
Collection<Contact> getContacts() throws DbException;
@@ -124,25 +183,27 @@ public interface ContactManager {
void removeContact(Transaction txn, ContactId c) throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
* Sets an alias for the contact or unsets it if {@code 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.
* Sets an alias for the contact or unsets it if {@code 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
* Returns true if a contact with this {@code remoteAuthorId} belongs to
* the local pseudonym with this {@code localAuthorId}.
*/
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException;
/**
* Return true if a contact with this name and public key already exists
* Returns true if a contact with this {@code remoteAuthorId} belongs to
* the local pseudonym with this {@code localAuthorId}.
*/
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;

View File

@@ -0,0 +1,45 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
import java.io.InputStream;
@NotNullByDefault
public interface HandshakeManager {
/**
* Handshakes with the given pending contact. Returns an ephemeral master
* key authenticated with both parties' handshake key pairs and a flag
* indicating whether the local peer is Alice or Bob.
*
* @param in An incoming stream for the handshake, which must be secured in
* handshake mode
* @param out An outgoing stream for the handshake, which must be secured
* in handshake mode
*/
HandshakeResult handshake(PendingContactId p, InputStream in,
StreamWriter out) throws DbException, IOException;
class HandshakeResult {
private final SecretKey masterKey;
private final boolean alice;
public HandshakeResult(SecretKey masterKey, boolean alice) {
this.masterKey = masterKey;
this.alice = alice;
}
public SecretKey getMasterKey() {
return masterKey;
}
public boolean isAlice() {
return alice;
}
}
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@@ -9,17 +10,15 @@ import javax.annotation.concurrent.Immutable;
public class PendingContact {
private final PendingContactId id;
private final byte[] publicKey;
private final PublicKey publicKey;
private final String alias;
private final PendingContactState state;
private final long timestamp;
public PendingContact(PendingContactId id, byte[] publicKey,
String alias, PendingContactState state, long timestamp) {
public PendingContact(PendingContactId id, PublicKey publicKey,
String alias, long timestamp) {
this.id = id;
this.publicKey = publicKey;
this.alias = alias;
this.state = state;
this.timestamp = timestamp;
}
@@ -27,7 +26,7 @@ public class PendingContact {
return id;
}
public byte[] getPublicKey() {
public PublicKey getPublicKey() {
return publicKey;
}
@@ -35,10 +34,6 @@ public class PendingContact {
return alias;
}
public PendingContactState getState() {
return state;
}
public long getTimestamp() {
return timestamp;
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
@@ -17,9 +18,8 @@ public class PendingContactId extends UniqueId {
super(id);
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
return o instanceof PendingContactId && super.equals(o);
}
}

View File

@@ -1,30 +1,10 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public enum PendingContactState {
WAITING_FOR_CONNECTION(0),
CONNECTED(1),
ADDING_CONTACT(2),
FAILED(3);
private final int value;
PendingContactState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static PendingContactState fromValue(int value) {
for (PendingContactState s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
WAITING_FOR_CONNECTION,
OFFLINE,
CONNECTING,
ADDING_CONTACT,
FAILED
}

View File

@@ -14,12 +14,18 @@ import javax.annotation.concurrent.Immutable;
public class ContactAddedEvent extends Event {
private final ContactId contactId;
private final boolean verified;
public ContactAddedEvent(ContactId contactId) {
public ContactAddedEvent(ContactId contactId, boolean verified) {
this.contactId = contactId;
this.verified = verified;
}
public ContactId getContactId() {
return contactId;
}
public boolean isVerified() {
return verified;
}
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class ContactAddedRemotelyEvent extends Event {
private final Contact contact;
public ContactAddedRemotelyEvent(Contact contact) {
this.contact = contact;
}
public Contact getContact() {
return contact;
}
}

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public class ContactExchangeFailedEvent extends Event {
@Nullable
private final Author duplicateRemoteAuthor;
public ContactExchangeFailedEvent(@Nullable Author duplicateRemoteAuthor) {
this.duplicateRemoteAuthor = duplicateRemoteAuthor;
}
public ContactExchangeFailedEvent() {
this(null);
}
@Nullable
public Author getDuplicateRemoteAuthor() {
return duplicateRemoteAuthor;
}
public boolean wasDuplicateContact() {
return duplicateRemoteAuthor != null;
}
}

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public class ContactExchangeSucceededEvent extends Event {
private final Author remoteAuthor;
public ContactExchangeSucceededEvent(Author remoteAuthor) {
this.remoteAuthor = remoteAuthor;
}
public Author getRemoteAuthor() {
return remoteAuthor;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact;
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 is added.
*/
@Immutable
@NotNullByDefault
public class PendingContactAddedEvent extends Event {
private final PendingContact pendingContact;
public PendingContactAddedEvent(PendingContact pendingContact) {
this.pendingContact = pendingContact;
}
public PendingContact getPendingContact() {
return pendingContact;
}
}

View File

@@ -0,0 +1,30 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
/**
* Type-safe wrapper for a private key used for key agreement.
*/
@Immutable
@NotNullByDefault
public class AgreementPrivateKey extends Bytes implements PrivateKey {
public AgreementPrivateKey(byte[] encoded) {
super(encoded);
}
@Override
public String getKeyType() {
return KEY_TYPE_AGREEMENT;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -0,0 +1,35 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
/**
* Type-safe wrapper for a public key used for key agreement.
*/
@Immutable
@NotNullByDefault
public class AgreementPublicKey extends Bytes implements PublicKey {
public AgreementPublicKey(byte[] encoded) {
super(encoded);
if (encoded.length == 0 ||
encoded.length > MAX_AGREEMENT_PUBLIC_KEY_BYTES) {
throw new IllegalArgumentException();
}
}
@Override
public String getKeyType() {
return KEY_TYPE_AGREEMENT;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -27,54 +27,78 @@ public interface CryptoComponent {
/**
* Derives another secret key from the given secret key.
*
* @param label a namespaced label indicating the purpose of the derived
* @param label A namespaced label indicating the purpose of the derived
* key, to prevent it from being repurposed or colliding with a key derived
* for another purpose
* @param inputs Additional inputs that will be included in the derivation
* of the key
*/
SecretKey deriveKey(String label, SecretKey k, byte[]... inputs);
/**
* Derives a common shared secret from two public keys and one of the
* corresponding private keys.
* Derives a shared secret from two key pairs.
*
* @param label a namespaced label indicating the purpose of this shared
* @param label A namespaced label indicating the purpose of this shared
* secret, to prevent it from being repurposed or colliding with a shared
* secret derived for another purpose
* @param theirPublicKey the public key of the remote party
* @param ourKeyPair the key pair of the local party
* @return the shared secret
* @param theirPublicKey The public key of the remote party
* @param ourKeyPair The key pair of the local party
* @param inputs Additional inputs that will be included in the derivation
* of the shared secret
* @return The shared secret
*/
SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
KeyPair ourKeyPair, byte[]... inputs)
throws GeneralSecurityException;
/**
* Derives a shared secret from two static and two ephemeral key pairs.
*
* @param label A namespaced label indicating the purpose of this shared
* secret, to prevent it from being repurposed or colliding with a shared
* secret derived for another purpose
* @param theirStaticPublicKey The static public key of the remote party
* @param theirEphemeralPublicKey The ephemeral public key of the remote
* party
* @param ourStaticKeyPair The static key pair of the local party
* @param ourEphemeralKeyPair The ephemeral key pair of the local party
* @param alice True if the local party is Alice
* @param inputs Additional inputs that will be included in the
* derivation of the shared secret
* @return The shared secret
*/
SecretKey deriveSharedSecret(String label, PublicKey theirStaticPublicKey,
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
KeyPair ourEphemeralKeyPair, boolean alice, byte[]... inputs)
throws GeneralSecurityException;
/**
* Signs the given byte[] with the given private key.
*
* @param label a namespaced label indicating the purpose of this
* @param label A namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* signature created for another purpose
*/
byte[] sign(String label, byte[] toSign, byte[] privateKey)
byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signed data
* and the given public key.
*
* @param label a namespaced label indicating the purpose of this
* @param label A namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* signature created for another purpose
* @return true if the signature was valid, false otherwise.
* @return True if the signature was valid, false otherwise.
*/
boolean verifySignature(byte[] signature, String label, byte[] signed,
byte[] publicKey) throws GeneralSecurityException;
PublicKey publicKey) throws GeneralSecurityException;
/**
* Returns the hash of the given inputs. The inputs are unambiguously
* combined by prefixing each input with its length.
*
* @param label a namespaced label indicating the purpose of this hash, to
* @param label A namespaced label indicating the purpose of this hash, to
* prevent it from being repurposed or colliding with a hash created for
* another purpose
*/
@@ -85,7 +109,7 @@ public interface CryptoComponent {
* given inputs. The inputs are unambiguously combined by prefixing each
* input with its length.
*
* @param label a namespaced label indicating the purpose of this MAC, to
* @param label A namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
*/
@@ -95,10 +119,10 @@ public interface CryptoComponent {
* Verifies that the given message authentication code is valid for the
* given secret key and inputs.
*
* @param label a namespaced label indicating the purpose of this MAC, to
* @param label A namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
* @return true if the MAC was valid, false otherwise.
* @return True if the MAC was valid, false otherwise.
*/
boolean verifyMac(byte[] mac, String label, SecretKey macKey,
byte[]... inputs);

View File

@@ -7,11 +7,21 @@ public interface CryptoConstants {
*/
int MAX_AGREEMENT_PUBLIC_KEY_BYTES = 32;
/**
* The key type for agreement key pairs.
*/
String KEY_TYPE_AGREEMENT = "Curve25519";
/**
* The maximum length of a signature public key in bytes.
*/
int MAX_SIGNATURE_PUBLIC_KEY_BYTES = 32;
/**
* The key type for signature key pairs.
*/
String KEY_TYPE_SIGNATURE = "Ed25519";
/**
* The maximum length of a signature in bytes.
*/

View File

@@ -15,6 +15,8 @@ public class KeyPair {
private final PrivateKey privateKey;
public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
if (!publicKey.getKeyType().equals(privateKey.getKeyType()))
throw new IllegalArgumentException();
this.publicKey = publicKey;
this.privateKey = privateKey;
}

View File

@@ -8,6 +8,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface PrivateKey {
/**
* Returns the type of this key pair.
*/
String getKeyType();
/**
* Returns the encoded representation of this key.
*/

View File

@@ -8,6 +8,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface PublicKey {
/**
* Returns the type of this key pair.
*/
String getKeyType();
/**
* Returns the encoded representation of this key.
*/

View File

@@ -0,0 +1,30 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
/**
* Type-safe wrapper for a public key used for signing.
*/
@Immutable
@NotNullByDefault
public class SignaturePrivateKey extends Bytes implements PrivateKey {
public SignaturePrivateKey(byte[] bytes) {
super(bytes);
}
@Override
public String getKeyType() {
return KEY_TYPE_SIGNATURE;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -0,0 +1,35 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_PUBLIC_KEY_BYTES;
/**
* Type-safe wrapper for a public key used for verifying signatures.
*/
@Immutable
@NotNullByDefault
public class SignaturePublicKey extends Bytes implements PublicKey {
public SignaturePublicKey(byte[] encoded) {
super(encoded);
if (encoded.length == 0 ||
encoded.length > MAX_SIGNATURE_PUBLIC_KEY_BYTES) {
throw new IllegalArgumentException();
}
}
@Override
public String getKeyType() {
return KEY_TYPE_SIGNATURE;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -1,9 +1,10 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.security.GeneralSecurityException;
/**
* Crypto operations for the transport security protocol - see
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BTP.md
@@ -11,35 +12,52 @@ import org.briarproject.bramble.api.transport.TransportKeys;
public interface TransportCrypto {
/**
* Derives initial transport keys for the given transport in the given
* time period from the given root key.
*
* @param alice whether the keys are for use by Alice or Bob.
* @param active whether the keys are usable for outgoing streams.
* Returns true if the local peer is Alice.
*/
TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean alice, boolean active);
boolean isAlice(PublicKey theirHandshakePublicKey,
KeyPair ourHandshakeKeyPair);
/**
* Rotates the given transport keys to the given time period. If the keys
* are for the given period or any later period they are not rotated.
* Derives the static master key shared with a contact or pending contact.
*/
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
SecretKey deriveStaticMasterKey(PublicKey theirHandshakePublicKey,
KeyPair ourHandshakeKeyPair) throws GeneralSecurityException;
/**
* Derives the handshake mode root key from the static master key. To
* prevent tag reuse, separate root keys are derived for contacts and
* pending contacts.
*
* @param pendingContact Whether the static master key is shared with a
* pending contact or a contact
*/
SecretKey deriveHandshakeRootKey(SecretKey staticMasterKey,
boolean pendingContact);
/**
* Derives initial rotation mode transport keys for the given transport in
* the given time period from the given root key.
*
* @param alice Whether the keys are for use by Alice or Bob
* @param active Whether the keys are usable for outgoing streams
*/
TransportKeys deriveRotationKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean alice, boolean active);
/**
* Derives handshake keys for the given transport in the given time period
* from the given root key.
*
* @param alice whether the keys are for use by Alice or Bob.
* @param alice Whether the keys are for use by Alice or Bob
*/
HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
TransportKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean alice);
/**
* Updates the given handshake keys to the given time period. If the keys
* Updates the given transport keys to the given time period. If the keys
* are for the given period or any later period they are not updated.
*/
HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod);
TransportKeys updateTransportKeys(TransportKeys k, long timePeriod);
/**
* Encodes the pseudo-random tag that is used to recognise a stream.

View File

@@ -1,8 +1,27 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
/**
* Thrown when a duplicate contact is added to the database. This exception may
* occur due to concurrent updates and does not indicate a database error.
*/
public class ContactExistsException extends DbException {
private final AuthorId local;
private final Author remote;
public ContactExistsException(AuthorId local, Author remote) {
this.local = local;
this.remote = remote;
}
public AuthorId getLocalAuthorId() {
return local;
}
public Author getRemoteAuthor() {
return remote;
}
}

View File

@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
@@ -22,14 +24,12 @@ import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.HandshakeKeySet;
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
import org.briarproject.bramble.api.transport.HandshakeKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeySet;
import org.briarproject.bramble.api.transport.TransportKeySetId;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -39,7 +39,7 @@ import javax.annotation.Nullable;
* to other components.
*/
@NotNullByDefault
public interface DatabaseComponent {
public interface DatabaseComponent extends TransactionManager {
/**
* Opens the database and returns true if the database already existed.
@@ -57,76 +57,18 @@ public interface DatabaseComponent {
*/
void close() throws DbException;
/**
* Starts a new transaction and returns an object representing it.
* <p/>
* This method acquires locks, so it must not be called while holding a
* lock.
*
* @param readOnly true if the transaction will only be used for reading.
*/
Transaction startTransaction(boolean readOnly) throws DbException;
/**
* Commits a transaction to the database.
*/
void commitTransaction(Transaction txn) throws DbException;
/**
* Ends a transaction. If the transaction has not been committed,
* it will be aborted. If the transaction has been committed,
* any events attached to the transaction are broadcast.
* The database lock will be released in either case.
*/
void endTransaction(Transaction txn);
/**
* Runs the given task within a transaction.
*/
<E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task.
*/
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/**
* 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,
* and returns an ID for the contact.
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
boolean verified) throws DbException;
@Nullable PublicKey handshake, boolean verified) throws DbException;
/**
* Stores a group.
*/
void addGroup(Transaction txn, Group g) throws DbException;
/**
* Stores the given handshake keys for the given contact and returns a
* key set ID.
*/
HandshakeKeySetId addHandshakeKeys(Transaction txn, ContactId c,
HandshakeKeys k) throws DbException;
/**
* Stores the given handshake keys for the given pending contact and
* returns a key set ID.
*/
HandshakeKeySetId addHandshakeKeys(Transaction txn, PendingContactId p,
HandshakeKeys k) throws DbException;
/**
* Stores an identity.
*/
@@ -136,7 +78,7 @@ public interface DatabaseComponent {
* Stores a local message.
*/
void addLocalMessage(Transaction txn, Message m, Metadata meta,
boolean shared) throws DbException;
boolean shared, boolean temporary) throws DbException;
/**
* Stores a pending contact.
@@ -154,7 +96,14 @@ public interface DatabaseComponent {
* Stores the given transport keys for the given contact and returns a
* key set ID.
*/
TransportKeySetId addTransportKeys(Transaction txn, ContactId c,
KeySetId addTransportKeys(Transaction txn, ContactId c, TransportKeys k)
throws DbException;
/**
* Stores the given transport keys for the given pending contact and
* returns a key set ID.
*/
KeySetId addTransportKeys(Transaction txn, PendingContactId p,
TransportKeys k) throws DbException;
/**
@@ -274,7 +223,7 @@ public interface DatabaseComponent {
* <p/>
* Read-only.
*/
Collection<ContactId> getContacts(Transaction txn, AuthorId a)
Collection<ContactId> getContacts(Transaction txn, AuthorId local)
throws DbException;
/**
@@ -308,14 +257,6 @@ public interface DatabaseComponent {
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
throws DbException;
/**
* Returns all handshake keys for the given transport.
* <p/>
* Read-only.
*/
Collection<HandshakeKeySet> getHandshakeKeys(Transaction txn, TransportId t)
throws DbException;
/**
* Returns the identity for the local pseudonym with the given ID.
* <p/>
@@ -464,6 +405,14 @@ public interface DatabaseComponent {
*/
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
/**
* Returns the pending contact with the given ID.
* <p/>
* Read-only.
*/
PendingContact getPendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Returns all pending contacts.
* <p/>
@@ -479,6 +428,13 @@ public interface DatabaseComponent {
*/
Settings getSettings(Transaction txn, String namespace) throws DbException;
/**
* Returns the versions of the sync protocol supported by the given contact.
* <p/>
* Read-only.
*/
List<Byte> getSyncVersions(Transaction txn, ContactId c) throws DbException;
/**
* Returns all transport keys for the given transport.
* <p/>
@@ -487,17 +443,11 @@ public interface DatabaseComponent {
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
throws DbException;
/**
* Increments the outgoing stream counter for the given handshake keys.
*/
void incrementStreamCounter(Transaction txn, TransportId t,
HandshakeKeySetId k) throws DbException;
/**
* Increments the outgoing stream counter for the given transport keys.
*/
void incrementStreamCounter(Transaction txn, TransportId t,
TransportKeySetId k) throws DbException;
void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* Merges the given metadata with the existing metadata for the given
@@ -552,12 +502,6 @@ public interface DatabaseComponent {
*/
void removeGroup(Transaction txn, Group g) throws DbException;
/**
* Removes the given handshake keys from the database.
*/
void removeHandshakeKeys(Transaction txn, TransportId t,
HandshakeKeySetId k) throws DbException;
/**
* Removes an identity (and all associated state) from the database.
*/
@@ -574,6 +518,12 @@ public interface DatabaseComponent {
void removePendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Removes all temporary messages (and all associated state) from the
* database.
*/
void removeTemporaryMessages(Transaction txn) throws DbException;
/**
* Removes a transport (and all associated state) from the database.
*/
@@ -582,8 +532,8 @@ public interface DatabaseComponent {
/**
* Removes the given transport keys from the database.
*/
void removeTransportKeys(Transaction txn, TransportId t,
TransportKeySetId k) throws DbException;
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**
* Marks the given contact as verified.
@@ -602,6 +552,11 @@ public interface DatabaseComponent {
void setGroupVisibility(Transaction txn, ContactId c, GroupId g,
Visibility v) throws DbException;
/**
* Marks the given message as permanent, i.e. not temporary.
*/
void setMessagePermanent(Transaction txn, MessageId m) throws DbException;
/**
* Marks the given message as shared.
*/
@@ -622,35 +577,26 @@ public interface DatabaseComponent {
/**
* Sets the handshake key pair for the identity with the given ID.
*/
void setHandshakeKeyPair(Transaction txn, AuthorId local, byte[] publicKey,
byte[] privateKey) throws DbException;
void setHandshakeKeyPair(Transaction txn, AuthorId local,
PublicKey publicKey, PrivateKey privateKey) throws DbException;
/**
* Sets the reordering window for the given transport key set in the given
* Sets the reordering window for the given transport keys in the given
* time period.
*/
void setReorderingWindow(Transaction txn, TransportKeySetId k,
TransportId t, long timePeriod, long base, byte[] bitmap)
throws DbException;
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
long timePeriod, long base, byte[] bitmap) throws DbException;
/**
* Sets the reordering window for the given handshake key set in the given
* time period.
* Sets the versions of the sync protocol supported by the given contact.
*/
void setReorderingWindow(Transaction txn, HandshakeKeySetId k,
TransportId t, long timePeriod, long base, byte[] bitmap)
void setSyncVersions(Transaction txn, ContactId c, List<Byte> supported)
throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
void setTransportKeysActive(Transaction txn, TransportId t,
TransportKeySetId k) throws DbException;
/**
* Stores the given handshake keys, deleting any keys they have replaced.
*/
void updateHandshakeKeys(Transaction txn, Collection<HandshakeKeySet> keys)
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
throws DbException;
/**

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface TransactionManager {
/**
* Starts a new transaction and returns an object representing it.
* <p/>
* This method acquires locks, so it must not be called while holding a
* lock.
*
* @param readOnly true if the transaction will only be used for reading.
*/
Transaction startTransaction(boolean readOnly) throws DbException;
/**
* Commits a transaction to the database.
*/
void commitTransaction(Transaction txn) throws DbException;
/**
* Ends a transaction. If the transaction has not been committed,
* it will be aborted. If the transaction has been committed,
* any events attached to the transaction are broadcast.
* The database lock will be released in either case.
*/
void endTransaction(Transaction txn);
/**
* Runs the given task within a transaction.
*/
<E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task.
*/
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/**
* 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;
}

View File

@@ -1,13 +1,14 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.Nameable;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
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.util.StringUtils.toUtf8;
/**
* A pseudonym for a user.
@@ -24,14 +25,14 @@ public class Author implements Nameable {
private final AuthorId id;
private final int formatVersion;
private final String name;
private final byte[] publicKey;
private final PublicKey publicKey;
public Author(AuthorId id, int formatVersion, String name,
byte[] publicKey) {
int nameLength = StringUtils.toUtf8(name).length;
PublicKey publicKey) {
int nameLength = toUtf8(name).length;
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)
if (!publicKey.getKeyType().equals(KEY_TYPE_SIGNATURE))
throw new IllegalArgumentException();
this.id = id;
this.formatVersion = formatVersion;
@@ -63,7 +64,7 @@ public class Author implements Nameable {
/**
* Returns the public key used to verify the pseudonym's signatures.
*/
public byte[] getPublicKey() {
public PublicKey getPublicKey() {
return publicKey;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
@@ -9,12 +10,12 @@ public interface AuthorFactory {
* Creates an author with the current format version and the given name and
* public key.
*/
Author createAuthor(String name, byte[] publicKey);
Author createAuthor(String name, PublicKey publicKey);
/**
* Creates an author with the given format version, name and public key.
*/
Author createAuthor(int formatVersion, String name, byte[] publicKey);
Author createAuthor(int formatVersion, String name, PublicKey publicKey);
/**
* Creates a local author with the current format version and the given

View File

@@ -1,13 +1,13 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Arrays;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
@Immutable
@NotNullByDefault
@@ -15,15 +15,24 @@ public class Identity {
private final LocalAuthor localAuthor;
@Nullable
private final byte[] handshakePublicKey, handshakePrivateKey;
private final PublicKey handshakePublicKey;
@Nullable
private final PrivateKey handshakePrivateKey;
private final long created;
public Identity(LocalAuthor localAuthor,
@Nullable byte[] handshakePublicKey,
@Nullable byte[] handshakePrivateKey, long created) {
@Nullable PublicKey handshakePublicKey,
@Nullable PrivateKey handshakePrivateKey, long created) {
if (handshakePublicKey != null) {
int keyLength = handshakePublicKey.length;
if (keyLength == 0 || keyLength > MAX_AGREEMENT_PUBLIC_KEY_BYTES)
if (handshakePrivateKey == null)
throw new IllegalArgumentException();
if (!handshakePublicKey.getKeyType().equals(KEY_TYPE_AGREEMENT))
throw new IllegalArgumentException();
}
if (handshakePrivateKey != null) {
if (handshakePublicKey == null)
throw new IllegalArgumentException();
if (!handshakePrivateKey.getKeyType().equals(KEY_TYPE_AGREEMENT))
throw new IllegalArgumentException();
}
this.localAuthor = localAuthor;
@@ -57,7 +66,7 @@ public class Identity {
* Returns the public key used for handshaking, or null if no key exists.
*/
@Nullable
public byte[] getHandshakePublicKey() {
public PublicKey getHandshakePublicKey() {
return handshakePublicKey;
}
@@ -65,7 +74,7 @@ public class Identity {
* Returns the private key used for handshaking, or null if no key exists.
*/
@Nullable
public byte[] getHandshakePrivateKey() {
public PrivateKey getHandshakePrivateKey() {
return handshakePrivateKey;
}
@@ -76,21 +85,4 @@ public class Identity {
public long getTimeCreated() {
return created;
}
@Override
public int hashCode() {
return localAuthor.getId().hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof Identity) {
Identity i = (Identity) o;
return created == i.created &&
localAuthor.equals(i.localAuthor) &&
Arrays.equals(handshakePublicKey, i.handshakePublicKey) &&
Arrays.equals(handshakePrivateKey, i.handshakePrivateKey);
}
return false;
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
@@ -41,9 +42,6 @@ public interface IdentityManager {
* Returns the cached handshake keys or loads them from the database.
* <p/>
* Read-only.
*
* @return A two-element array containing the public key in the first
* element and the private key in the second
*/
byte[][] getHandshakeKeys(Transaction txn) throws DbException;
KeyPair getHandshakeKeys(Transaction txn) throws DbException;
}

View File

@@ -1,9 +1,13 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
/**
* A pseudonym for the local user.
*/
@@ -11,18 +15,20 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault
public class LocalAuthor extends Author {
private final byte[] privateKey;
private final PrivateKey privateKey;
public LocalAuthor(AuthorId id, int formatVersion, String name,
byte[] publicKey, byte[] privateKey) {
PublicKey publicKey, PrivateKey privateKey) {
super(id, formatVersion, name, publicKey);
if (!privateKey.getKeyType().equals(KEY_TYPE_SIGNATURE))
throw new IllegalArgumentException();
this.privateKey = privateKey;
}
/**
* Returns the private key used to generate the pseudonym's signatures.
*/
public byte[] getPrivateKey() {
public PrivateKey getPrivateKey() {
return privateKey;
}
}

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.data.BdfList;
import java.io.IOException;
/**
* An class for managing a particular key agreement listener.
* Accepts key agreement connections over a given transport.
*/
public abstract class KeyAgreementListener {

View File

@@ -6,10 +6,27 @@ import javax.annotation.Nullable;
public class NullSafety {
/**
* Stand-in for `Objects.requireNonNull()`.
* Stand-in for {@code Objects.requireNonNull()}.
*/
public static <T> T requireNonNull(@Nullable T t) {
if (t == null) throw new NullPointerException();
return t;
}
/**
* Checks that exactly one of the arguments is null.
*
* @throws AssertionError If both or neither of the arguments are null
*/
public static void requireExactlyOneNull(@Nullable Object a,
@Nullable Object b) {
if ((a == null) == (b == null)) throw new AssertionError();
}
/**
* Checks that the argument is null.
*/
public static void requireNull(@Nullable Object o) {
if (o != null) throw new AssertionError();
}
}

View File

@@ -0,0 +1,28 @@
package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
/**
* An interface for handling connections created by transport plugins.
*/
@NotNullByDefault
public interface ConnectionHandler {
/**
* Handles a connection created by a {@link DuplexPlugin}.
*/
void handleConnection(DuplexTransportConnection c);
/**
* Handles a reader created by a {@link SimplexPlugin}.
*/
void handleReader(TransportConnectionReader r);
/**
* Handles a writer created by a {@link SimplexPlugin}.
*/
void handleWriter(TransportConnectionWriter w);
}

View File

@@ -1,17 +1,46 @@
package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
@NotNullByDefault
public interface ConnectionManager {
/**
* Manages an incoming connection from a contact over a simplex transport.
*/
void manageIncomingConnection(TransportId t, TransportConnectionReader r);
/**
* Manages an incoming connection from a contact over a duplex transport.
*/
void manageIncomingConnection(TransportId t, DuplexTransportConnection d);
/**
* Manages an incoming handshake connection from a pending contact over a
* duplex transport.
*/
void manageIncomingConnection(PendingContactId p, TransportId t,
DuplexTransportConnection d);
/**
* Manages an outgoing connection to a contact over a simplex transport.
*/
void manageOutgoingConnection(ContactId c, TransportId t,
TransportConnectionWriter w);
/**
* Manages an outgoing connection to a contact over a duplex transport.
*/
void manageOutgoingConnection(ContactId c, TransportId t,
DuplexTransportConnection d);
/**
* Manages an outgoing handshake connection to a pending contact over a
* duplex transport.
*/
void manageOutgoingConnection(PendingContactId p, TransportId t,
DuplexTransportConnection d);
}

View File

@@ -1,7 +1,14 @@
package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import java.util.Collection;
@@ -11,13 +18,50 @@ import java.util.Collection;
@NotNullByDefault
public interface ConnectionRegistry {
/**
* Registers a connection with the given contact over the given transport.
* Broadcasts {@link ConnectionOpenedEvent}. Also broadcasts
* {@link ContactConnectedEvent} if this is the only connection with the
* contact.
*/
void registerConnection(ContactId c, TransportId t, boolean incoming);
/**
* Unregisters a connection with the given contact over the given transport.
* Broadcasts {@link ConnectionClosedEvent}. Also broadcasts
* {@link ContactDisconnectedEvent} if this is the only connection with
* the contact.
*/
void unregisterConnection(ContactId c, TransportId t, boolean incoming);
/**
* Returns any contacts that are connected via the given transport.
*/
Collection<ContactId> getConnectedContacts(TransportId t);
/**
* Returns true if the given contact is connected via the given transport.
*/
boolean isConnected(ContactId c, TransportId t);
/**
* Returns true if the given contact is connected via any transport.
*/
boolean isConnected(ContactId c);
/**
* Registers a connection with the given pending contact. Broadcasts
* {@link RendezvousConnectionOpenedEvent} if this is the only connection
* with the pending contact.
*
* @return True if this is the only connection with the pending contact,
* false if it is redundant and should be closed
*/
boolean registerConnection(PendingContactId p);
/**
* Unregisters a connection with the given pending contact. Broadcasts
* {@link RendezvousConnectionClosedEvent}.
*/
void unregisterConnection(PendingContactId p, boolean success);
}

View File

@@ -1,10 +1,10 @@
package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.util.Map;
import java.util.Collection;
@NotNullByDefault
public interface Plugin {
@@ -51,8 +51,9 @@ public interface Plugin {
int getPollingInterval();
/**
* Attempts to establish connections to the given contacts, passing any
* created connections to the callback.
* Attempts to create connections using the given transport properties,
* passing any created connections to the corresponding handlers.
*/
void poll(Map<ContactId, TransportProperties> contacts);
void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties);
}

View File

@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.settings.Settings;
* the application.
*/
@NotNullByDefault
public interface PluginCallback {
public interface PluginCallback extends ConnectionHandler {
/**
* Returns the plugin's settings

View File

@@ -36,4 +36,9 @@ public interface PluginManager {
* Returns any duplex plugins that support key agreement.
*/
Collection<DuplexPlugin> getKeyAgreementPlugins();
/**
* Returns any duplex plugins that support rendezvous.
*/
Collection<DuplexPlugin> getRendezvousPlugins();
}

View File

@@ -3,8 +3,11 @@ package org.briarproject.bramble.api.plugin.duplex;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.ConnectionHandler;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import javax.annotation.Nullable;
@@ -40,4 +43,19 @@ public interface DuplexPlugin extends Plugin {
@Nullable
DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, BdfList descriptor);
/**
* Returns true if the plugin supports rendezvous connections.
*/
boolean supportsRendezvous();
/**
* Creates and returns an endpoint that uses the given key material to
* rendezvous with a pending contact, and the given connection handler to
* handle incoming connections. Returns null if an endpoint cannot be
* created.
*/
@Nullable
RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
boolean alice, ConnectionHandler incoming);
}

View File

@@ -1,17 +0,0 @@
package org.briarproject.bramble.api.plugin.duplex;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
/**
* An interface through which a duplex plugin interacts with the rest of the
* application.
*/
@NotNullByDefault
public interface DuplexPluginCallback extends PluginCallback {
void incomingConnectionCreated(DuplexTransportConnection d);
void outgoingConnectionCreated(ContactId c, DuplexTransportConnection d);
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.plugin.duplex;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.Nullable;
@@ -25,5 +26,5 @@ public interface DuplexPluginFactory {
* Creates and returns a plugin, or null if no plugin can be created.
*/
@Nullable
DuplexPlugin createPlugin(DuplexPluginCallback callback);
DuplexPlugin createPlugin(PluginCallback callback);
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.plugin.simplex;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
/**
* An interface through which a simplex plugin interacts with the rest of the
* application.
*/
@NotNullByDefault
public interface SimplexPluginCallback extends PluginCallback {
void readerCreated(TransportConnectionReader r);
void writerCreated(ContactId c, TransportConnectionWriter w);
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.plugin.simplex;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.Nullable;
@@ -25,5 +26,5 @@ public interface SimplexPluginFactory {
* Creates and returns a plugin, or null if no plugin can be created.
*/
@Nullable
SimplexPlugin createPlugin(SimplexPluginCallback callback);
SimplexPlugin createPlugin(PluginCallback callback);
}

View File

@@ -1,10 +1,14 @@
package org.briarproject.bramble.api.record;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Predicate;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.EOFException;
import java.io.IOException;
import javax.annotation.Nullable;
@NotNullByDefault
public interface RecordReader {
@@ -16,5 +20,20 @@ public interface RecordReader {
*/
Record readRecord() throws IOException;
/**
* Reads and returns the next record matching the 'accept' predicate,
* skipping any records that match the 'ignore' predicate. Returns null if
* no record matching the 'accept' predicate is found before the end of the
* stream.
*
* @throws EOFException If the end of the stream is reached without
* reading a complete record
* @throws FormatException If a record is read that does not match the
* 'accept' or 'ignore' predicates
*/
@Nullable
Record readRecord(Predicate<Record> accept, Predicate<Record> ignore)
throws IOException;
void close() throws IOException;
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.rendezvous;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* A source of key material for use in making rendezvous connections.
*/
@NotNullByDefault
public interface KeyMaterialSource {
/**
* Returns the requested amount of key material.
*/
byte[] getKeyMaterial(int length);
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api.rendezvous;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.io.Closeable;
import java.io.IOException;
/**
* An interface for making and accepting rendezvous connections with a pending
* contact over a given transport.
*/
public interface RendezvousEndpoint extends Closeable {
/**
* Returns a set of transport properties for connecting to the pending
* contact.
*/
TransportProperties getRemoteTransportProperties();
/**
* Closes the handler and releases any resources held by it, such as
* network sockets.
*/
@Override
void close() throws IOException;
}

View File

@@ -0,0 +1,12 @@
package org.briarproject.bramble.api.rendezvous;
import org.briarproject.bramble.api.contact.PendingContactId;
/**
* Interface for the poller that makes rendezvous connections to pending
* contacts.
*/
public interface RendezvousPoller {
long getLastPollTime(PendingContactId p);
}

View File

@@ -0,0 +1,32 @@
package org.briarproject.bramble.api.rendezvous.event;
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 rendezvous connection is closed.
*/
@Immutable
@NotNullByDefault
public class RendezvousConnectionClosedEvent extends Event {
private final PendingContactId pendingContactId;
private final boolean success;
public RendezvousConnectionClosedEvent(PendingContactId pendingContactId,
boolean success) {
this.pendingContactId = pendingContactId;
this.success = success;
}
public PendingContactId getPendingContactId() {
return pendingContactId;
}
public boolean isSuccess() {
return success;
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.rendezvous.event;
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 rendezvous connection is opened.
*/
@Immutable
@NotNullByDefault
public class RendezvousConnectionOpenedEvent extends Event {
private final PendingContactId pendingContactId;
public RendezvousConnectionOpenedEvent(PendingContactId pendingContactId) {
this.pendingContactId = pendingContactId;
}
public PendingContactId getPendingContactId() {
return pendingContactId;
}
}

View File

@@ -0,0 +1,36 @@
package org.briarproject.bramble.api.rendezvous.event;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a transport plugin is polled for connections
* to one or more pending contacts.
*/
@Immutable
@NotNullByDefault
public class RendezvousPollEvent extends Event {
private final TransportId transportId;
private final Collection<PendingContactId> pendingContacts;
public RendezvousPollEvent(TransportId transportId,
Collection<PendingContactId> pendingContacts) {
this.transportId = transportId;
this.pendingContacts = pendingContacts;
}
public TransportId getTransportId() {
return transportId;
}
public Collection<PendingContactId> getPendingContacts() {
return pendingContacts;
}
}

View File

@@ -1,10 +1,16 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record acknowledging receipt of one or more {@link Message Messages}.
*/
@Immutable
@NotNullByDefault
public class Ack {
private final Collection<MessageId> acked;

View File

@@ -1,8 +1,14 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@Immutable
@NotNullByDefault
public class Message {
/**

View File

@@ -1,10 +1,16 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record offering the recipient one or more {@link Message Messages}.
*/
@Immutable
@NotNullByDefault
public class Offer {
private final Collection<MessageId> offered;

View File

@@ -9,5 +9,5 @@ public interface RecordTypes {
byte MESSAGE = 1;
byte OFFER = 2;
byte REQUEST = 3;
byte VERSIONS = 4;
}

View File

@@ -1,10 +1,16 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record requesting one or more {@link Message Messages} from the recipient.
*/
@Immutable
@NotNullByDefault
public class Request {
private final Collection<MessageId> requested;

View File

@@ -2,6 +2,9 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId;
import java.util.List;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
public interface SyncConstants {
@@ -11,6 +14,11 @@ public interface SyncConstants {
*/
byte PROTOCOL_VERSION = 0;
/**
* The versions of the sync protocol this peer supports.
*/
List<Byte> SUPPORTED_VERSIONS = singletonList(PROTOCOL_VERSION);
/**
* The maximum length of a group descriptor in bytes.
*/
@@ -35,4 +43,10 @@ public interface SyncConstants {
* The maximum number of message IDs in an ack, offer or request record.
*/
int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_BYTES / UniqueId.LENGTH;
/**
* The maximum number of versions of the sync protocol a peer may support
* simultaneously.
*/
int MAX_SUPPORTED_VERSIONS = 10;
}

View File

@@ -25,4 +25,7 @@ public interface SyncRecordReader {
Request readRequest() throws IOException;
boolean hasVersions() throws IOException;
Versions readVersions() throws IOException;
}

View File

@@ -15,5 +15,7 @@ public interface SyncRecordWriter {
void writeRequest(Request r) throws IOException;
void writeVersions(Versions v) throws IOException;
void flush() throws IOException;
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
/**
* A record telling the recipient which versions of the sync protocol the
* sender supports.
*/
@Immutable
@NotNullByDefault
public class Versions {
private final List<Byte> supported;
public Versions(List<Byte> supported) {
this.supported = supported;
}
public List<Byte> getSupportedVersions() {
return supported;
}
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when the versions of the sync protocol supported
* by a contact are updated.
*/
@Immutable
@NotNullByDefault
public class SyncVersionsUpdatedEvent extends Event {
private final ContactId contactId;
private final List<Byte> supported;
public SyncVersionsUpdatedEvent(ContactId contactId, List<Byte> supported) {
this.contactId = contactId;
this.supported = supported;
}
public ContactId getContactId() {
return contactId;
}
public List<Byte> getSupportedVersions() {
return supported;
}
}

View File

@@ -1,57 +0,0 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.concurrent.Immutable;
/**
* Abstract superclass for {@link TransportKeys} and {@link HandshakeKeys}.
*/
@Immutable
@NotNullByDefault
public abstract class AbstractTransportKeys {
private final TransportId transportId;
private final IncomingKeys inPrev, inCurr, inNext;
private final OutgoingKeys outCurr;
AbstractTransportKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1)
throw new IllegalArgumentException();
if (inCurr.getTimePeriod() != outCurr.getTimePeriod())
throw new IllegalArgumentException();
if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1)
throw new IllegalArgumentException();
this.transportId = transportId;
this.inPrev = inPrev;
this.inCurr = inCurr;
this.inNext = inNext;
this.outCurr = outCurr;
}
public TransportId getTransportId() {
return transportId;
}
public IncomingKeys getPreviousIncomingKeys() {
return inPrev;
}
public IncomingKeys getCurrentIncomingKeys() {
return inCurr;
}
public IncomingKeys getNextIncomingKeys() {
return inNext;
}
public OutgoingKeys getCurrentOutgoingKeys() {
return outCurr;
}
public long getTimePeriod() {
return outCurr.getTimePeriod();
}
}

View File

@@ -1,70 +0,0 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* A set of keys for handshaking with a given contact or pending contact over a
* given transport. Unlike a {@link TransportKeySet} these keys do not provide
* forward secrecy.
*/
@Immutable
@NotNullByDefault
public class HandshakeKeySet {
private final HandshakeKeySetId keySetId;
@Nullable
private final ContactId contactId;
@Nullable
private final PendingContactId pendingContactId;
private final HandshakeKeys keys;
public HandshakeKeySet(HandshakeKeySetId keySetId, ContactId contactId,
HandshakeKeys keys) {
this.keySetId = keySetId;
this.contactId = contactId;
this.keys = keys;
pendingContactId = null;
}
public HandshakeKeySet(HandshakeKeySetId keySetId,
PendingContactId pendingContactId, HandshakeKeys keys) {
this.keySetId = keySetId;
this.pendingContactId = pendingContactId;
this.keys = keys;
contactId = null;
}
public HandshakeKeySetId getKeySetId() {
return keySetId;
}
@Nullable
public ContactId getContactId() {
return contactId;
}
@Nullable
public PendingContactId getPendingContactId() {
return pendingContactId;
}
public HandshakeKeys getKeys() {
return keys;
}
@Override
public int hashCode() {
return keySetId.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof HandshakeKeySet &&
keySetId.equals(((HandshakeKeySet) o).keySetId);
}
}

View File

@@ -1,36 +0,0 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.concurrent.Immutable;
/**
* Keys for handshaking with a given contact or pending contact over a given
* transport. Unlike {@link TransportKeys} these keys do not provide forward
* secrecy.
*/
@Immutable
@NotNullByDefault
public class HandshakeKeys extends AbstractTransportKeys {
private final SecretKey rootKey;
private final boolean alice;
public HandshakeKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr,
SecretKey rootKey, boolean alice) {
super(transportId, inPrev, inCurr, inNext, outCurr);
this.rootKey = rootKey;
this.alice = alice;
}
public SecretKey getRootKey() {
return rootKey;
}
public boolean isAlice() {
return alice;
}
}

View File

@@ -8,8 +8,8 @@ import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
/**
* Contains transport keys for receiving streams from a given contact over a
* given transport in a given time period.
* Contains transport keys for receiving streams from a given contact or
* pending contact over a given transport in a given time period.
*/
@Immutable
@NotNullByDefault

View File

@@ -1,11 +1,15 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.TransportId;
import java.security.GeneralSecurityException;
import java.util.Map;
import javax.annotation.Nullable;
@@ -17,24 +21,49 @@ import javax.annotation.Nullable;
public interface KeyManager {
/**
* Informs the key manager that a new contact has been added. Derives and
* stores a set of transport keys for communicating with the contact over
* each transport and returns the key set IDs.
* Derives and stores a set of rotation mode transport keys for
* communicating with the given contact over each transport and returns the
* key set IDs.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.
*
* @param alice true if the local party is Alice
* @param active whether the derived keys can be used for outgoing streams
* @param alice True if the local party is Alice
* @param active Whether the derived keys can be used for outgoing streams
*/
Map<TransportId, TransportKeySetId> addContact(Transaction txn, ContactId c,
SecretKey rootKey, long timestamp, boolean alice, boolean active)
throws DbException;
Map<TransportId, KeySetId> addRotationKeys(Transaction txn,
ContactId c, SecretKey rootKey, long timestamp, boolean alice,
boolean active) throws DbException;
/**
* Informs the key manager that a new contact has been added. Derives and
* stores a set of handshake mode transport keys for communicating with the
* contact over each transport and returns the key set IDs.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.
*/
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
PublicKey theirPublicKey, KeyPair ourKeyPair)
throws DbException, GeneralSecurityException;
/**
* Informs the key manager that a new pending contact has been added.
* Derives and stores a set of handshake mode transport keys for
* communicating with the pending contact over each transport and returns
* the key set IDs.
* <p/>
* {@link StreamContext StreamContexts} for the pending contact can be
* created after this method has returned.
*/
Map<TransportId, KeySetId> addPendingContact(Transaction txn,
PendingContactId p, PublicKey theirPublicKey, KeyPair ourKeyPair)
throws DbException, GeneralSecurityException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
void activateKeys(Transaction txn, Map<TransportId, TransportKeySetId> keys)
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
throws DbException;
/**
@@ -43,15 +72,28 @@ public interface KeyManager {
*/
boolean canSendOutgoingStreams(ContactId c, TransportId t);
/**
* Returns true if we have keys that can be used for outgoing streams to
* the given pending contact over the given transport.
*/
boolean canSendOutgoingStreams(PendingContactId p, TransportId t);
/**
* Returns a {@link StreamContext} for sending a stream to the given
* contact over the given transport, or null if an error occurs or the
* contact does not support the transport.
* contact over the given transport, or null if an error occurs.
*/
@Nullable
StreamContext getStreamContext(ContactId c, TransportId t)
throws DbException;
/**
* Returns a {@link StreamContext} for sending a stream to the given
* pending contact over the given transport, or null if an error occurs.
*/
@Nullable
StreamContext getStreamContext(PendingContactId p, TransportId t)
throws DbException;
/**
* Looks up the given tag and returns a {@link StreamContext} for reading
* from the corresponding stream, or null if an error occurs or the tag was

View File

@@ -5,17 +5,16 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* Type-safe wrapper for an integer that uniquely identifies a
* {@link HandshakeKeySet set of handshake keys} within the scope of the local
* device.
* Type-safe wrapper for an integer that uniquely identifies a set of
* {@link TransportKeySet transport keys} within the scope of the local device.
*/
@Immutable
@NotNullByDefault
public class HandshakeKeySetId {
public class KeySetId {
private final int id;
public HandshakeKeySetId(int id) {
public KeySetId(int id) {
this.id = id;
}
@@ -30,7 +29,6 @@ public class HandshakeKeySetId {
@Override
public boolean equals(Object o) {
return o instanceof HandshakeKeySetId &&
id == ((HandshakeKeySetId) o).id;
return o instanceof KeySetId && id == ((KeySetId) o).id;
}
}

View File

@@ -6,8 +6,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* Contains transport keys for sending streams to a given contact over a given
* transport in a given time period.
* Contains transport keys for sending streams to a given contact or pending
* contact over a given transport in a given time period.
*/
@Immutable
@NotNullByDefault

View File

@@ -1,34 +1,53 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireExactlyOneNull;
@Immutable
@NotNullByDefault
public class StreamContext {
@Nullable
private final ContactId contactId;
@Nullable
private final PendingContactId pendingContactId;
private final TransportId transportId;
private final SecretKey tagKey, headerKey;
private final long streamNumber;
private final boolean handshakeMode;
public StreamContext(ContactId contactId, TransportId transportId,
SecretKey tagKey, SecretKey headerKey, long streamNumber) {
public StreamContext(@Nullable ContactId contactId,
@Nullable PendingContactId pendingContactId,
TransportId transportId, SecretKey tagKey, SecretKey headerKey,
long streamNumber, boolean handshakeMode) {
requireExactlyOneNull(contactId, pendingContactId);
this.contactId = contactId;
this.pendingContactId = pendingContactId;
this.transportId = transportId;
this.tagKey = tagKey;
this.headerKey = headerKey;
this.streamNumber = streamNumber;
this.handshakeMode = handshakeMode;
}
@Nullable
public ContactId getContactId() {
return contactId;
}
@Nullable
public PendingContactId getPendingContactId() {
return pendingContactId;
}
public TransportId getTransportId() {
return transportId;
}
@@ -44,4 +63,8 @@ public class StreamContext {
public long getStreamNumber() {
return streamNumber;
}
public boolean isHandshakeMode() {
return handshakeMode;
}
}

View File

@@ -63,14 +63,6 @@ public interface TransportConstants {
int MAX_PAYLOAD_LENGTH = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH
- MAC_LENGTH;
/**
* The minimum stream length in bytes that all transport plugins must
* support. Streams may be shorter than this length, but all transport
* plugins must support streams of at least this length.
*/
int MIN_STREAM_LENGTH = STREAM_HEADER_LENGTH + FRAME_HEADER_LENGTH
+ MAC_LENGTH;
/**
* The maximum difference in milliseconds between two peers' clocks.
*/
@@ -81,6 +73,26 @@ public interface TransportConstants {
*/
int REORDERING_WINDOW_SIZE = 32;
/**
* Label for deriving the static master key from handshake key pairs.
*/
String STATIC_MASTER_KEY_LABEL =
"org.briarproject.bramble.transport/STATIC_MASTER_KEY";
/**
* Label for deriving the handshake mode root key for a pending contact
* from the static master key.
*/
String PENDING_CONTACT_ROOT_KEY_LABEL =
"org.briarproject.bramble.transport/PENDING_CONTACT_ROOT_KEY";
/**
* Label for deriving the handshake mode root key for a contact from the
* static master key.
*/
String CONTACT_ROOT_KEY_LABEL =
"org.briarproject.bramble.transport/CONTACT_ROOT_KEY";
/**
* Label for deriving Alice's initial tag key from the root key in
* rotation mode.

View File

@@ -1,37 +1,52 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireExactlyOneNull;
/**
* A set of keys for communicating with a given contact over a given transport.
* Unlike a {@link HandshakeKeySet} these keys provide forward secrecy.
* A set of keys for communicating with a given contact or pending contact
* over a given transport.
*/
@Immutable
@NotNullByDefault
public class TransportKeySet {
private final TransportKeySetId keySetId;
private final KeySetId keySetId;
@Nullable
private final ContactId contactId;
@Nullable
private final PendingContactId pendingContactId;
private final TransportKeys keys;
public TransportKeySet(TransportKeySetId keySetId, ContactId contactId,
TransportKeys keys) {
public TransportKeySet(KeySetId keySetId, @Nullable ContactId contactId,
@Nullable PendingContactId pendingContactId, TransportKeys keys) {
requireExactlyOneNull(contactId, pendingContactId);
this.keySetId = keySetId;
this.contactId = contactId;
this.pendingContactId = pendingContactId;
this.keys = keys;
}
public TransportKeySetId getKeySetId() {
public KeySetId getKeySetId() {
return keySetId;
}
@Nullable
public ContactId getContactId() {
return contactId;
}
@Nullable
public PendingContactId getPendingContactId() {
return pendingContactId;
}
public TransportKeys getKeys() {
return keys;
}

View File

@@ -1,38 +0,0 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* Type-safe wrapper for an integer that uniquely identifies a
* {@link TransportKeySet set of transport keys} within the scope of the local
* device.
* <p/>
* Key sets created on a given device must have increasing identifiers.
*/
@Immutable
@NotNullByDefault
public class TransportKeySetId {
private final int id;
public TransportKeySetId(int id) {
this.id = id;
}
public int getInt() {
return id;
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object o) {
return o instanceof TransportKeySetId &&
id == ((TransportKeySetId) o).id;
}
}

View File

@@ -1,20 +1,108 @@
package org.briarproject.bramble.api.transport;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* Keys for communicating with a given contact over a given transport. Unlike
* {@link HandshakeKeys} these keys provide forward secrecy.
* Keys for communicating with a given contact or pending contact over a given
* transport.
*/
@Immutable
@NotNullByDefault
public class TransportKeys extends AbstractTransportKeys {
public class TransportKeys {
private final TransportId transportId;
private final IncomingKeys inPrev, inCurr, inNext;
private final OutgoingKeys outCurr;
@Nullable
private final SecretKey rootKey;
private final boolean alice;
/**
* Constructor for rotation mode.
*/
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
super(transportId, inPrev, inCurr, inNext, outCurr);
this(transportId, inPrev, inCurr, inNext, outCurr, null, false);
}
/**
* Constructor for handshake mode.
*/
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr,
@Nullable SecretKey rootKey, boolean alice) {
if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1)
throw new IllegalArgumentException();
if (inCurr.getTimePeriod() != outCurr.getTimePeriod())
throw new IllegalArgumentException();
if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1)
throw new IllegalArgumentException();
this.transportId = transportId;
this.inPrev = inPrev;
this.inCurr = inCurr;
this.inNext = inNext;
this.outCurr = outCurr;
this.rootKey = rootKey;
this.alice = alice;
}
public TransportId getTransportId() {
return transportId;
}
public IncomingKeys getPreviousIncomingKeys() {
return inPrev;
}
public IncomingKeys getCurrentIncomingKeys() {
return inCurr;
}
public IncomingKeys getNextIncomingKeys() {
return inNext;
}
public OutgoingKeys getCurrentOutgoingKeys() {
return outCurr;
}
public long getTimePeriod() {
return outCurr.getTimePeriod();
}
/**
* Returns true if these keys are for use in handshake mode or false if
* they're for use in rotation mode.
*/
public boolean isHandshakeMode() {
return rootKey != null;
}
/**
* If these keys are for use in handshake mode, returns the root key.
*
* @throws UnsupportedOperationException If these keys are for use in
* rotation mode
*/
public SecretKey getRootKey() {
if (rootKey == null) throw new UnsupportedOperationException();
return rootKey;
}
/**
* If these keys are for use in handshake mode, returns true if the local
* party is Alice.
*
* @throws UnsupportedOperationException If these keys are for use in
* rotation mode
*/
public boolean isAlice() {
if (rootKey == null) throw new UnsupportedOperationException();
return alice;
}
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.util;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -19,6 +20,7 @@ public class LogUtils {
/**
* Logs the duration of a task.
*
* @param logger the logger to use
* @param task a description of the task
* @param start the start time of the task, as returned by {@link #now()}
@@ -33,4 +35,26 @@ public class LogUtils {
public static void logException(Logger logger, Level level, Throwable t) {
if (logger.isLoggable(level)) logger.log(level, t.toString(), t);
}
public static void logFileOrDir(Logger logger, Level level, File f) {
if (logger.isLoggable(level)) {
if (f.isFile()) {
logWithType(logger, level, f, "F");
} else if (f.isDirectory()) {
logWithType(logger, level, f, "D");
File[] children = f.listFiles();
if (children != null) {
for (File child : children)
logFileOrDir(logger, level, child);
}
} else if (f.exists()) {
logWithType(logger, level, f, "?");
}
}
}
private static void logWithType(Logger logger, Level level, File f,
String type) {
logger.log(level, type + " " + f.getAbsolutePath() + " " + f.length());
}
}

View File

@@ -5,7 +5,13 @@ import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.AgreementPrivateKey;
import org.briarproject.bramble.api.crypto.AgreementPublicKey;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.SignaturePrivateKey;
import org.briarproject.bramble.api.crypto.SignaturePublicKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
@@ -30,11 +36,10 @@ import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_PUBLIC_KEY_BYTES;
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_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
@@ -101,10 +106,28 @@ public class TestUtils {
return new SecretKey(getRandomBytes(SecretKey.LENGTH));
}
public static PublicKey getSignaturePublicKey() {
byte[] key = getRandomBytes(MAX_SIGNATURE_PUBLIC_KEY_BYTES);
return new SignaturePublicKey(key);
}
public static PrivateKey getSignaturePrivateKey() {
return new SignaturePrivateKey(getRandomBytes(123));
}
public static PublicKey getAgreementPublicKey() {
byte[] key = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
return new AgreementPublicKey(key);
}
public static PrivateKey getAgreementPrivateKey() {
return new AgreementPrivateKey(getRandomBytes(123));
}
public static Identity getIdentity() {
LocalAuthor localAuthor = getLocalAuthor();
byte[] handshakePub = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
byte[] handshakePriv = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
PublicKey handshakePub = getAgreementPublicKey();
PrivateKey handshakePriv = getAgreementPrivateKey();
return new Identity(localAuthor, handshakePub, handshakePriv,
timestamp);
}
@@ -113,8 +136,8 @@ public class TestUtils {
AuthorId id = new AuthorId(getRandomId());
int nameLength = 1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH);
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
PublicKey publicKey = getSignaturePublicKey();
PrivateKey privateKey = getSignaturePrivateKey();
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey);
}
@@ -122,7 +145,7 @@ public class TestUtils {
AuthorId id = new AuthorId(getRandomId());
int nameLength = 1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH);
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
PublicKey publicKey = getSignaturePublicKey();
return new Author(id, FORMAT_VERSION, name, publicKey);
}
@@ -155,10 +178,9 @@ public class TestUtils {
public static PendingContact getPendingContact(int nameLength) {
PendingContactId id = new PendingContactId(getRandomId());
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
PublicKey publicKey = getAgreementPublicKey();
String alias = getRandomString(nameLength);
return new PendingContact(id, publicKey, alias, WAITING_FOR_CONNECTION,
timestamp);
return new PendingContact(id, publicKey, alias, timestamp);
}
public static ContactId getContactId() {
@@ -179,7 +201,7 @@ public class TestUtils {
boolean verified) {
return new Contact(c, remote, local,
getRandomString(MAX_AUTHOR_NAME_LENGTH),
getRandomBytes(MAX_PUBLIC_KEY_LENGTH), verified);
getAgreementPublicKey(), verified);
}
public static double getMedian(Collection<? extends Number> samples) {

View File

@@ -7,7 +7,7 @@ import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
@@ -29,7 +29,7 @@ public interface BrambleCoreEagerSingletons {
void inject(PropertiesModule.EagerSingletons init);
void inject(ReportingModule.EagerSingletons init);
void inject(RendezvousModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init);
@@ -38,4 +38,19 @@ public interface BrambleCoreEagerSingletons {
void inject(ValidationModule.EagerSingletons init);
void inject(VersioningModule.EagerSingletons init);
default void injectBrambleCoreEagerSingletons() {
inject(new ContactModule.EagerSingletons());
inject(new CryptoExecutorModule.EagerSingletons());
inject(new DatabaseExecutorModule.EagerSingletons());
inject(new IdentityModule.EagerSingletons());
inject(new LifecycleModule.EagerSingletons());
inject(new RendezvousModule.EagerSingletons());
inject(new PluginModule.EagerSingletons());
inject(new PropertiesModule.EagerSingletons());
inject(new SystemModule.EagerSingletons());
inject(new TransportModule.EagerSingletons());
inject(new ValidationModule.EagerSingletons());
inject(new VersioningModule.EagerSingletons());
}
}

View File

@@ -15,9 +15,8 @@ import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.record.RecordModule;
import org.briarproject.bramble.reliability.ReliabilityModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
@@ -42,9 +41,8 @@ import dagger.Module;
PropertiesModule.class,
RecordModule.class,
ReliabilityModule.class,
ReportingModule.class,
RendezvousModule.class,
SettingsModule.class,
SocksModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class,
@@ -54,17 +52,6 @@ import dagger.Module;
public class BrambleCoreModule {
public static void initEagerSingletons(BrambleCoreEagerSingletons c) {
c.inject(new ContactModule.EagerSingletons());
c.inject(new CryptoExecutorModule.EagerSingletons());
c.inject(new DatabaseExecutorModule.EagerSingletons());
c.inject(new IdentityModule.EagerSingletons());
c.inject(new LifecycleModule.EagerSingletons());
c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons());
c.injectBrambleCoreEagerSingletons();
}
}

View File

@@ -3,6 +3,9 @@ package org.briarproject.bramble.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyParser;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfReader;
@@ -82,14 +85,21 @@ class ClientHelperImpl implements ClientHelper {
@Override
public void addLocalMessage(Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException {
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared));
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared,
false));
}
@Override
public void addLocalMessage(Transaction txn, Message m,
BdfDictionary metadata, boolean shared)
BdfDictionary metadata, boolean shared, boolean temporary)
throws DbException, FormatException {
db.addLocalMessage(txn, m, metadataEncoder.encode(metadata), shared);
db.addLocalMessage(txn, m, metadataEncoder.encode(metadata), shared,
temporary);
}
@Override
public Message createMessage(GroupId g, long timestamp, byte[] body) {
return messageFactory.createMessage(g, timestamp, body);
}
@Override
@@ -305,14 +315,15 @@ class ClientHelperImpl implements ClientHelper {
}
@Override
public byte[] sign(String label, BdfList toSign, byte[] privateKey)
public byte[] sign(String label, BdfList toSign, PrivateKey privateKey)
throws FormatException, GeneralSecurityException {
return crypto.sign(label, toByteArray(toSign), privateKey);
}
@Override
public void verifySignature(byte[] signature, String label, BdfList signed,
byte[] publicKey) throws FormatException, GeneralSecurityException {
PublicKey publicKey)
throws FormatException, GeneralSecurityException {
if (!crypto.verifySignature(signature, label, toByteArray(signed),
publicKey)) {
throw new GeneralSecurityException("Invalid signature");
@@ -327,11 +338,29 @@ class ClientHelperImpl implements ClientHelper {
if (formatVersion != FORMAT_VERSION) throw new FormatException();
String name = author.getString(1);
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
byte[] publicKey = author.getRaw(2);
checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
byte[] publicKeyBytes = author.getRaw(2);
checkLength(publicKeyBytes, 1, MAX_PUBLIC_KEY_LENGTH);
KeyParser parser = crypto.getSignatureKeyParser();
PublicKey publicKey;
try {
publicKey = parser.parsePublicKey(publicKeyBytes);
} catch (GeneralSecurityException e) {
throw new FormatException();
}
return authorFactory.createAuthor(formatVersion, name, publicKey);
}
@Override
public PublicKey parseAndValidateAgreementPublicKey(byte[] publicKeyBytes)
throws FormatException {
KeyParser parser = crypto.getAgreementKeyParser();
try {
return parser.parsePublicKey(publicKeyBytes);
} catch (GeneralSecurityException e) {
throw new FormatException();
}
}
@Override
public TransportProperties parseAndValidateTransportProperties(
BdfDictionary properties) throws FormatException {

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.client;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory;
@@ -55,7 +54,7 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
private byte[] createGroupDescriptor(AuthorId local, AuthorId remote) {
try {
if (Bytes.COMPARATOR.compare(local, remote) < 0)
if (local.compareTo(remote) < 0)
return clientHelper.toByteArray(BdfList.of(local, remote));
else return clientHelper.toByteArray(BdfList.of(remote, local));
} catch (FormatException e) {

View File

@@ -1,16 +1,6 @@
package org.briarproject.bramble.api.contact;
package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
/**
* A task for conducting a contact information exchange with a remote peer.
*/
@NotNullByDefault
public interface ContactExchangeTask {
interface ContactExchangeConstants {
/**
* The current version of the contact exchange protocol.
@@ -39,9 +29,7 @@ public interface ContactExchangeTask {
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
/**
* Exchanges contact information with a remote peer.
* Label for signing key binding nonces.
*/
void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
DuplexTransportConnection conn, TransportId transportId,
boolean alice);
String SIGNING_LABEL = "org.briarproject.briar.contact/EXCHANGE";
}

View File

@@ -0,0 +1,35 @@
package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
interface ContactExchangeCrypto {
/**
* Derives the header key for a contact exchange stream from the master key.
*
* @param alice Whether the header key is for the stream sent by Alice
*/
SecretKey deriveHeaderKey(SecretKey masterKey, boolean alice);
/**
* Creates and returns a signature that proves ownership of a pseudonym.
*
* @param privateKey The pseudonym's signature private key
* @param alice Whether the pseudonym belongs to Alice
*/
byte[] sign(PrivateKey privateKey, SecretKey masterKey, boolean alice);
/**
* Verifies a signature that proves ownership of a pseudonym.
*
* @param publicKey The pseudonym's signature public key
* @param alice Whether the pseudonym belongs to Alice
* @return True if the signature is valid
*/
boolean verify(PublicKey publicKey, SecretKey masterKey, boolean alice,
byte[] signature);
}

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