Compare commits

...

136 Commits

Author SHA1 Message Date
ameba23
48d943d98e Resolve merge conflict with social-backup-poc 2022-03-04 10:13:20 +01:00
ameba23
fabd8298ef Reduce text size in remote wipe display fragment 2022-03-02 17:17:56 +01:00
ameba23
3ca23652ae Success dialog for deactivate remote wipe - additional explainer 2022-03-02 17:09:01 +01:00
ameba23
55efa9dad9 Success dialog for deactivate remote wipe 2022-03-02 16:59:28 +01:00
ameba23
bf1b5c0c95 Rm unused layout file 2022-03-02 16:52:01 +01:00
ameba23
ac685a82e6 Rm unused method 2022-03-02 16:50:39 +01:00
ameba23
97c49d75f8 Revoke all wipers method 2022-03-02 16:49:47 +01:00
ameba23
088a4ee7b2 Buttons on remote wipe display fragment 2022-03-02 16:49:27 +01:00
ameba23
60d0665ad6 Rm mockups fragment 2022-03-02 16:49:06 +01:00
ameba23
9a99b24fe8 Add button to remote wipe display fragment 2022-03-02 11:28:34 +01:00
ameba23
7be5cba64a Improve remote wipe display fragment 2022-03-01 11:45:08 +01:00
ameba23
d463d69971 Add remote wipe display fragment 2022-03-01 11:44:29 +01:00
ameba23
255ce7d0a5 Improve remote wipe display fragment 2022-02-28 10:43:36 +01:00
ameba23
fcfbf8e72b Fix bug with displaying existing remote wipers 2022-02-25 09:34:37 +01:00
ameba23
90d0a772be Delete old remote wipe activate success fragment 2022-02-25 09:17:13 +01:00
ameba23
07a556c40f Popup dialog on wipe signal sent successfully 2022-02-25 08:55:54 +01:00
ameba23
5374a27bff Delete old remote wipe setup fragment 2022-02-24 13:46:03 +01:00
ameba23
f7894dd159 Add pop-up dialog on remote wipe setup success 2022-02-24 13:42:50 +01:00
ameba23
5e0f7219c5 return number of confirm messages sent 2022-02-24 13:12:03 +01:00
ameba23
f29278b436 Rm unused method 2022-02-24 13:11:30 +01:00
ameba23
5bd4ab689b return number of confirm messages sent 2022-02-24 13:11:09 +01:00
ameba23
a665179377 Confirm messages method in remote wipe manager 2022-02-24 13:01:39 +01:00
ameba23
d84d638f7c Confirm messages method in briar api 2022-02-24 13:01:23 +01:00
ameba23
a6b85e5979 Remote wipe activated activity 2022-02-24 13:00:45 +01:00
ameba23
4453d7b36d Add remote wipe activated view model 2022-02-24 13:00:27 +01:00
ameba23
9b5e10baf2 Bug with conditional when checking if confirm messages are sent 2022-02-22 10:26:21 +01:00
ameba23
24c95236f0 Add message header for confirm message. Await delivery before wiping 2022-02-22 10:03:16 +01:00
ameba23
91e5d7c70f Improve message for remote wipe confirm 2022-02-22 09:10:19 +01:00
ameba23
99ffbfd5ae Validate remote wipe confirm messages 2022-02-22 08:49:10 +01:00
ameba23
189dd6f7e5 Remote wipe notification 2022-02-22 08:48:56 +01:00
ameba23
4f60873e2a Remote wipe confirm message notifiction 2022-02-21 10:09:20 +01:00
ameba23
cf5522e7fb Rm unused dependency spongy castle from briar-android witness.gradle 2022-02-21 09:58:09 +01:00
ameba23
3f19aeb2d7 Implement CONFIRM remote wipe message 2022-02-21 09:09:10 +01:00
ameba23
bb30fe622d Add CONFIRM remote wipe message type 2022-02-21 09:08:50 +01:00
ameba23
0ae3ace1da Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  Improve setup password explanation string
  Improve choose password info dialog
  Improve threshold selector screen
  Basic strength meter when choosing threshold
2022-02-21 08:34:34 +01:00
ameba23
f1d803820c Fix merge conflicts 2022-02-10 10:53:09 +01:00
ameba23
6d6cbaf769 Remove only invalid pluralisation rules in Indonesian language 2022-01-13 08:54:52 +01:00
ameba23
02743867df Comment out plural strings to avoid formatting problems in Indonesian 2022-01-12 14:56:36 +01:00
ameba23
36d83c8974 Disable expiring warning as a workaround for i18n issue 2022-01-12 14:21:58 +01:00
ameba23
c9ddcf50f1 Use in language code rather than id 2022-01-10 09:41:20 +01:00
ameba23
12148201e4 Rm untranslatable strings 2022-01-10 09:27:34 +01:00
ameba23
2ec7c2d6fc Add language code to arrays.xml 2022-01-10 09:02:41 +01:00
ameba23
deaadd6505 Add Bahasa Indonesian translation strings 2022-01-10 08:54:04 +01:00
ameba23
fa639ec45d Improve activate remote wipe explainer 2021-10-12 11:06:54 +02:00
ameba23
b9363b16b7 Add explainer screen when setting up remote wipe 2021-10-12 09:26:27 +02:00
ameba23
ba9661f7c8 Fix bug with remote wipe activated success button 2021-10-08 12:21:53 +02:00
ameba23
b2341e6392 Resolve merge conflict with social-backup-poc 2021-10-06 11:32:11 +02:00
ameba23
b9c614acfb Add button when displaying remote wipers allowing the list of wipers to be modified 2021-09-07 13:20:01 +02:00
ameba23
336866da51 Revoke existing wipers that are not in the updated set of wipers 2021-09-07 12:44:41 +02:00
ameba23
342cfeab08 Make it possible to amend list of wipers 2021-09-07 11:54:36 +02:00
ameba23
5895bc3427 Change spongy to bouncy for briar-headless 2021-09-07 09:58:59 +02:00
akwizgran
bb775901e3 Resolve conflict on cherry pick commit to use ByteBuddyClassImposteriser 2021-09-07 09:58:27 +02:00
ameba23
c76d419ecb Tell animal sniffer gradle plugin to ignore java.util.Objects 2021-09-06 12:27:57 +02:00
ameba23
581ecc9aaa Fix header problem with revoke remote wipe messages 2021-09-01 11:59:12 +02:00
ameba23
18d1dd041d Fix type when sending revoke messages 2021-08-31 13:03:58 +02:00
ameba23
03a624ab8f Add revoke remote wipe conversation notification on revoke received 2021-08-31 12:59:39 +02:00
ameba23
9a28203437 Add revoke remote wipe conversation notification 2021-08-31 12:55:48 +02:00
ameba23
d81964844f Fix success fragment 2021-08-31 12:55:18 +02:00
ameba23
a26df1d11a Add revoke remote wipe activity to remote wipe module 2021-08-31 12:44:20 +02:00
ameba23
1ae5de8b2f Downgrade bouncy castle 2021-08-31 12:40:44 +02:00
ameba23
7119771c6e Add revoke remote wipe method 2021-08-31 12:40:24 +02:00
ameba23
6e67c1dfbf Add revoke remote wipe status option to conversation actions menu 2021-08-31 12:39:52 +02:00
ameba23
25029e1fca Add a test to check revoke functionality 2021-08-30 12:20:06 +02:00
ameba23
0c4ad98839 Validate revoke messages 2021-08-30 12:19:37 +02:00
ameba23
8605ead547 Rm unused assertions from witness gradle 2021-08-30 12:12:54 +02:00
ameba23
6c6d41e2cb Upgrade gradle to 4.2.2 2021-08-30 12:11:44 +02:00
ameba23
29bc2a5ee9 Switch from spongycastle to bouncy castle 2021-08-30 11:15:28 +02:00
ameba23
f8f573e150 Add revoke wipe method to RemoteWipeManager 2021-08-30 10:48:45 +02:00
ameba23
c6af32650d Add revoke remote wipe back end functionality 2021-08-30 10:47:13 +02:00
ameba23
2d5e0ee840 Add an additional message type for revoking remote wipe status 2021-08-30 10:46:40 +02:00
ameba23
c64815ca16 Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  Dont accept shards from mismatched sets - all muss match the first shard received
  Change wording on shard notification messages
  Change message on success fragments
2021-06-22 16:27:08 +02:00
ameba23
5d6a76d64a Implement deleteMessages in RemoteWipeManagerImpl 2021-06-21 13:14:04 +02:00
ameba23
7ff6a72ca1 Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  Catch NoSuchGroupException when deleting contacts
  Implement deleteMessages in SocialBackupManagerImpl
  Implement deleteAllMessages in SocialBackupManagerImpl
  Add delete all messages to integration test
2021-06-21 13:03:19 +02:00
ameba23
68c880b257 Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  SecretOwnerTask also passes a provider of AuthenticatedCipher
2021-06-16 08:35:05 +02:00
ameba23
04e18a79bd Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  Use a provider to instantiate AuthenticatedCipher on each use, to prevent concurrency problems
2021-06-15 21:11:01 +02:00
ameba23
1217c2affb Merge branch 'social-backup-poc' into remote-wipe-poc
* social-backup-poc:
  Fix bug with qrCodeRead flag
  Fix bug with qrCodeRead flag
2021-06-15 16:32:24 +02:00
ameba23
736651051d Update remote wipe explainer drawable 2021-06-03 10:46:31 +02:00
ameba23
2177036044 Display expiration date on outgoing remote wipe message notification 2021-06-03 09:37:15 +02:00
ameba23
ab136d3167 Move RemoteWipeConstants to briar-api 2021-06-03 09:36:26 +02:00
ameba23
61bae55d7c Replace println with LOG in RemoteWipeManagerImpl 2021-06-01 11:15:18 +02:00
ameba23
aa9216a21e Update integration test to account for wipe messages not having headers on the remote side 2021-06-01 11:02:29 +02:00
ameba23
6bdfeb68a6 Only add remote wipe message headers to local messages 2021-05-31 14:56:36 +02:00
ameba23
985779c633 Assume remote wipe message headers are local 2021-05-31 14:56:07 +02:00
ameba23
9c0a58e3ac Merge branch social-backup-poc 2021-05-31 13:43:43 +02:00
ameba23
a448211549 Remote notification message on receiving wipe signal 2021-05-31 13:40:40 +02:00
ameba23
b4de33c58d Put the listener for remote wipe activated event in BriarService rather than AndroidNotificationManager 2021-05-28 10:04:21 +02:00
ameba23
6b10c88858 Add a RemoteWipeActivatedActivity, and listen for the event in AndroidNotificationManager 2021-05-27 12:26:27 +02:00
ameba23
b453f9b33a Add success fragment after sending an activate remote wipe signal 2021-05-26 09:12:16 +02:00
ameba23
ec21df55f8 Update message encoder and RemoteWipeManager for the new api for RemoteWipeMessageHeader 2021-05-25 12:56:51 +02:00
ameba23
a8bef40fee Display message when getting or sending a remote wipe wipe message 2021-05-25 12:55:46 +02:00
ameba23
d42c25ebf7 Move remote wipe MessageType enum to briar-api 2021-05-25 12:55:26 +02:00
ameba23
76c37431ba Shorten explainer string to fit on screen 2021-05-25 11:31:59 +02:00
ameba23
a183f16a3d Set activity view 2021-05-25 11:31:17 +02:00
ameba23
cc37529f9f Add activate remote wipe activity to manifest 2021-05-25 11:21:21 +02:00
ameba23
7eea532a81 Add explainer fragment for activating a remote wipe 2021-05-25 11:18:22 +02:00
ameba23
4d5bad13ca Only show remote wipe menu item if we are a remote wiper for that contact 2021-05-25 09:52:13 +02:00
ameba23
ef7d182a74 Error message on failure to set up remote wipe 2021-05-21 11:34:54 +02:00
ameba23
0fe699c9b5 RemoteWipeSetupSuccess fragment 2021-05-21 11:22:44 +02:00
ameba23
29ef603122 Add RemoteWipeActivatedEvent to activate wipe 2021-05-18 11:02:02 +02:00
ameba23
67015d7294 Improve wording for received setup message notification 2021-05-17 17:39:01 +02:00
ameba23
78a91d43b2 Update RemoteWipeMessageHeader 2021-05-17 17:16:57 +02:00
ameba23
d8a0b6f877 Add remote wipe menu item to ConversationActivity 2021-05-17 17:14:58 +02:00
ameba23
7d86ec5510 Add to BriarCoreEagerSingletons 2021-05-17 17:14:11 +02:00
ameba23
6f8f9eaf9f ActivateRemoteWipe activity and view model 2021-05-17 17:13:36 +02:00
ameba23
60065fe38f Format test for displaying existing wipers 2021-05-17 12:17:28 +02:00
ameba23
ff493273c1 Add remote wipe display fragment to show details of an existing setup 2021-05-17 11:52:04 +02:00
ameba23
308b9b3ec1 Add a MutableLiveData to RemoteWipeSetupState 2021-05-15 18:43:39 +02:00
ameba23
31950aef9a Create RemoteWipeSetupModule which binds the view model 2021-05-15 16:24:00 +02:00
ameba23
f0d42e0d4f Add RemoteWipeSetupActivity to manifest and settings menu 2021-05-14 12:49:37 +02:00
ameba23
f2f70fa110 Rm unused class 2021-05-14 12:40:00 +02:00
ameba23
024511aefc RemoteWipeSetup activity and view model, wiper selector fragment 2021-05-14 12:39:37 +02:00
ameba23
2de10e6f1b Sleep between messages in test 2021-05-11 12:43:48 +02:00
ameba23
92d31aa106 Add an event for received setup messages 2021-05-11 11:37:36 +02:00
ameba23
71c502df52 Create RemoteWipeReceivedEvent 2021-05-11 11:07:15 +02:00
ameba23
fd015d4992 Tidy 2021-05-11 11:04:12 +02:00
ameba23
5f3ec0846e Ignore old wipe messages when receiving 2021-05-11 11:03:08 +02:00
ameba23
892943ddf9 Ignore old wipe messages 2021-05-11 10:59:05 +02:00
ameba23
ad14a0cef8 Additional test for duplicate wipe messages 2021-05-11 09:57:36 +02:00
ameba23
3404a7d02a Check metadata for wipers in test 2021-05-10 10:31:23 +02:00
ameba23
c8c28eb6a0 Add method to get the local list of wipers 2021-05-10 10:31:04 +02:00
ameba23
d45b4be453 Update implementation and test for panic observer 2021-05-10 10:07:26 +02:00
ameba23
f998482e93 Add a panic observer 2021-05-10 10:07:02 +02:00
ameba23
7fb986ea9a Store threshold as constant 2021-05-07 17:24:11 +02:00
ameba23
d9fe8d962f Store incoming valid remote wipe messages in metadata, update test 2021-05-07 17:21:12 +02:00
ameba23
cfc705ca41 Update test 2021-05-07 11:01:35 +02:00
ameba23
e97114e322 Add method to know if you are a wiper for a given contact 2021-05-07 11:01:24 +02:00
ameba23
eb4146b175 Update MessagingController for briar-headless 2021-05-06 18:31:51 +02:00
ameba23
7659b9decb Display message when getting or sending a remote wipe setup message 2021-05-06 18:30:51 +02:00
ameba23
a93cbf852b RemoteWipeManager builds messages using the message encoder 2021-05-06 17:48:56 +02:00
ameba23
fe79a18061 Create Message encoder, parser and validator for remote wipe 2021-05-06 17:48:10 +02:00
ameba23
ae1ad4be24 RemoteWipeModule should register with ClientVersioningManager, add contact hook 2021-05-06 13:48:53 +02:00
ameba23
014db8d45f Update RemoteWipeManager 2021-05-06 11:53:22 +02:00
ameba23
f089c0da3e Add a RemoteWipeMessageHeader 2021-05-06 11:53:03 +02:00
ameba23
7b9d2621b7 Add RemoteWipeModule to BriarCoreModule 2021-05-05 19:13:27 +02:00
ameba23
0aea84a1b5 RemoteWipeModule and beginnings of integration test 2021-05-05 19:03:43 +02:00
ameba23
0224733b10 RemoteWipeManager WIP 2021-05-05 14:35:30 +02:00
84 changed files with 3832 additions and 459 deletions

View File

@@ -1,39 +1,39 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
'com.android.tools.analytics-library:protos:27.1.1:protos-27.1.1.jar:13f77e73762e58ab372d140b3a6be6903aea9775b62dd14fbc62d4cc7069c9a4',
'com.android.tools.analytics-library:shared:27.1.1:shared-27.1.1.jar:82930a52001410e97d809930b670f4de3002286975f046b9de5f6b777b06d366',
'com.android.tools.analytics-library:tracker:27.1.1:tracker-27.1.1.jar:31bc5a00be0055bac89c9b2f34751883e987cd89e3ac1783720645c164f591d9',
'com.android.tools.analytics-library:protos:27.2.2:protos-27.2.2.jar:02482564443c294dfe87c5f2b25387f724a698a09ed58e0cf0127400caa35a19',
'com.android.tools.analytics-library:shared:27.2.2:shared-27.2.2.jar:0efe017ca17ee775c5af386475a09799a1282faa04821d54810c1a34f6348d9c',
'com.android.tools.analytics-library:tracker:27.2.2:tracker-27.2.2.jar:62489d84192dc06219664945c43201654ff85c3b715f46550751512a880d0e39',
'com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524:aapt2-proto-4.1.0-alpha01-6193524.jar:17e75523e1e92dd4f222c7368ee41df9e964a508232f591e265d0c499baf9dca',
'com.android.tools.build:apksig:4.1.1:apksig-4.1.1.jar:e0a69da9e5a03986d608b45bbf954ef0e6a0b3f58c1b8315bd169ec08b279e72',
'com.android.tools.build:apkzlib:4.1.1:apkzlib-4.1.1.jar:ba4b5e419b6be0130eae7f8301c3a551ad3976f487d2e0c6852ebb175ac41127',
'com.android.tools.build:builder-model:4.1.1:builder-model-4.1.1.jar:e95c99cc298ad67b8deb6ced99c51abc8f59afebedad044b1a10dde14646a4dd',
'com.android.tools.build:builder-test-api:4.1.1:builder-test-api-4.1.1.jar:464f596ab261c051c3847406748e843770dea123f6fa5fee8a9390644e709b7a',
'com.android.tools.build:builder:4.1.1:builder-4.1.1.jar:0f78d4759d2f7b57b95865522ec34596ba419b9982f3b25e3449213f9c98b80d',
'com.android.tools.build:gradle-api:4.1.1:gradle-api-4.1.1.jar:d42e6b539e4c1353ad3546e75ec8ce11a017b97481023e8ea18577eefe374358',
'com.android.tools.build:manifest-merger:27.1.1:manifest-merger-27.1.1.jar:7a45fa143687859bb2e5a961dcf6ee88094d3853de0cb543dc03dbcb0f4b554b',
'com.android.tools.ddms:ddmlib:27.1.1:ddmlib-27.1.1.jar:da6e4bd834b6a85dae8019039849d8bd96933347dfbf460df74913ddade6e40a',
'com.android.tools.external.com-intellij:intellij-core:27.1.1:intellij-core-27.1.1.jar:2591a7363c4443c59bf9f793730acafce9d6ec3076e2f46716edaf53a41b6fb6',
'com.android.tools.external.com-intellij:kotlin-compiler:27.1.1:kotlin-compiler-27.1.1.jar:5054ae770ba788f110303c65abd6b1fa28eccf52dee1274510e201b2b81885c8',
'com.android.tools.external.org-jetbrains:uast:27.1.1:uast-27.1.1.jar:54cd8f6886a9d2f5641659dd5c91f626629672cd48301f7f0bd6aad9bd448714',
'com.android.tools.layoutlib:layoutlib-api:27.1.1:layoutlib-api-27.1.1.jar:8a9a22e3b309521ea83b724e5a89cfdac6076f52d675c0e17d77b05527bc0f8c',
'com.android.tools.lint:lint-api:27.1.1:lint-api-27.1.1.jar:c1d8176094cb0478786070d40533efb578ebc53529a82f6ef5bee879bdca418b',
'com.android.tools.lint:lint-checks:27.1.1:lint-checks-27.1.1.jar:3899c91e00bd059b40c31a9ca00cd0f8303191947608735ae1b657323693fb61',
'com.android.tools.lint:lint-gradle-api:27.1.1:lint-gradle-api-27.1.1.jar:26aa89d38b9825cc73229daa82a68875801c8b8491f30497ce62aff1f206eb0d',
'com.android.tools.lint:lint-gradle:27.1.1:lint-gradle-27.1.1.jar:f7355823ead869f4d28184ba28b7a0c693b507519a2d3705bb9848a0f35b3756',
'com.android.tools.lint:lint-model:27.1.1:lint-model-27.1.1.jar:bc23c0c413bdfca59dac2cd56b870d8360d009e9ec0d365e71f774bcf127971d',
'com.android.tools.lint:lint:27.1.1:lint-27.1.1.jar:2f6038a5398a42bd591883c3f5e5894f4ec52ca1c3683bf94fa8553c1700af81',
'com.android.tools:annotations:27.1.1:annotations-27.1.1.jar:ff28c504d2acb9fd1a5ffbd97ae85cf59ee18c76927525aad250509bccf2cab1',
'com.android.tools:common:27.1.1:common-27.1.1.jar:63d9a2a9ad6d278db319f3749b9f50bdf5457ef7020074a1bebe124e714b535c',
'com.android.tools:dvlib:27.1.1:dvlib-27.1.1.jar:998a54201fc1cefee5f2399215e95c42b1f64f9e1d8f4452eb8255c68ba5440f',
'com.android.tools:repository:27.1.1:repository-27.1.1.jar:d25b74ccabf4d876903efb375e9af6fb380d8ae0445bb74bbdcc225c1e37fa1d',
'com.android.tools:sdk-common:27.1.1:sdk-common-27.1.1.jar:4473ae97d0ef7061ee1de61041d5aa97405ae08e44c09cf7bb278b42e4b97c7c',
'com.android.tools:sdklib:27.1.1:sdklib-27.1.1.jar:08e6b83961ac9724b3c1e3d0eff971f13be6701292c77914b8794480f3391250',
'com.android:signflinger:4.1.1:signflinger-4.1.1.jar:0c66825988873ec2d51057fa463f54a8f18fc7326ff4530b9da363b71e97ce60',
'com.android:zipflinger:4.1.1:zipflinger-4.1.1.jar:0a8c3e52ac13dd031236f9fb5ba4408b1d5dcd12325a05440b36da09d8881446',
'com.android.tools.build:apksig:4.2.2:apksig-4.2.2.jar:632690bf641b429dcb31650e6b2f6a2e87c4ac8afd45a6ba3cbc99fb1612178f',
'com.android.tools.build:apkzlib:4.2.2:apkzlib-4.2.2.jar:3b5167c1265e97f65201c4d2be6a6f72165a3aa2fe9e0594a59b67af9e9e97b9',
'com.android.tools.build:builder-model:4.2.2:builder-model-4.2.2.jar:41868de0cb88ae70b828eee4191c13e0233f433abb1becdf6a2bd391bd446bc0',
'com.android.tools.build:builder-test-api:4.2.2:builder-test-api-4.2.2.jar:2f305c6d3a7b637d736b821bad372dcabd959e979f2065a9f65bac1e7b4d1875',
'com.android.tools.build:builder:4.2.2:builder-4.2.2.jar:40fedd0d16db8f34ddb4eaf812d966b90ef1764f65cf119030442823bcf995cd',
'com.android.tools.build:gradle-api:4.2.2:gradle-api-4.2.2.jar:dd4ef35bbbfb8fc2d20e3311c76b516bc1672e82b61cb3a59fc877da0f9b4f61',
'com.android.tools.build:manifest-merger:27.2.2:manifest-merger-27.2.2.jar:971974756f32d9e94c857d92772b1499b0b0f5d9c70cb8ebbd20d9bbf804a923',
'com.android.tools.ddms:ddmlib:27.2.2:ddmlib-27.2.2.jar:9ab0f9b58737c316af454184705854c75936ca3531f21acc29bd68a3343334d1',
'com.android.tools.external.com-intellij:intellij-core:27.2.2:intellij-core-27.2.2.jar:01619d5dc28ec909cbdee699f1f13056e84462faf6dccf4817561293fb28bef0',
'com.android.tools.external.com-intellij:kotlin-compiler:27.2.2:kotlin-compiler-27.2.2.jar:71bd460199ce7293ecc54b91a115319c1e4b585eca5a5b3699f6a406f29e626c',
'com.android.tools.external.org-jetbrains:uast:27.2.2:uast-27.2.2.jar:efa59302fd433015e993143530cecb456b63d10d0b89bd1d3b1a016904338a65',
'com.android.tools.layoutlib:layoutlib-api:27.2.2:layoutlib-api-27.2.2.jar:f0901f2295d814e82ad95850ea2103dd89d8489e01727fafa55ccccc0dccd163',
'com.android.tools.lint:lint-api:27.2.2:lint-api-27.2.2.jar:1ecb5959c8e624ee49cdf9178de67bb0e823b4382ed253410eb36afe5c458b05',
'com.android.tools.lint:lint-checks:27.2.2:lint-checks-27.2.2.jar:989e545a6b5e398e63a9f3608da02d6111f2241faec1baa0a3b4492cb03aeaf2',
'com.android.tools.lint:lint-gradle-api:27.2.2:lint-gradle-api-27.2.2.jar:2be9c69d6fbbfb012ff6521fdfcb22eb7cfaa57d108e07bb1d4143dae9c1b433',
'com.android.tools.lint:lint-gradle:27.2.2:lint-gradle-27.2.2.jar:742dedd5ccb459a245a35bf4fa16dfecc762da1a6b1741332cfe5228e812301a',
'com.android.tools.lint:lint-model:27.2.2:lint-model-27.2.2.jar:ee31012586462bea2d591b6175934e5f29b6f781a78fda50f79387972364b9ab',
'com.android.tools.lint:lint:27.2.2:lint-27.2.2.jar:7247016af7fba8cabee6ae887515b144f5a2ff7823422654daf23be9202f8fb1',
'com.android.tools:annotations:27.2.2:annotations-27.2.2.jar:9375fb2df5c0cf1b46fef9e65b3a27ac88925ccf90054b19ae0ca0adc7036fe1',
'com.android.tools:common:27.2.2:common-27.2.2.jar:a76f4e10cad39bed317be031fee915d280aa8bc11616c58ab94e051b1e38769d',
'com.android.tools:dvlib:27.2.2:dvlib-27.2.2.jar:9931c6b57460b5f8cc2613ca5ff8596aa089a67655ace13d173f90538ecb4301',
'com.android.tools:repository:27.2.2:repository-27.2.2.jar:ac5f9b19dc5d9d08e80b57da76059f5760ca76c221e40ffd4bf43d7b13991674',
'com.android.tools:sdk-common:27.2.2:sdk-common-27.2.2.jar:b147acc13850808d61fc391ccfeeebdf90841b461a7042acb2d92e466da8e674',
'com.android.tools:sdklib:27.2.2:sdklib-27.2.2.jar:fae0bafbe8b4f546cf64986a22b7d8ed108d45519366ff22f0170a9cf3ea7f34',
'com.android:signflinger:4.2.2:signflinger-4.2.2.jar:4d7aafd9666707b483b1ad2c466824287cf2e379dda1d204dd3b7e453ffcf760',
'com.android:zipflinger:4.2.2:zipflinger-4.2.2.jar:8e4677086c9a8f4a67374a4edc31db7e481f0d9b85907263c51ca72452c23a93',
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.code.gson:gson:2.8.6:gson-2.8.6.jar:c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a',
'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
@@ -54,17 +54,19 @@ dependencyVerification {
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:3.0.7:istack-commons-runtime-3.0.7.jar:6443e10ba2e259fb821d9b6becf10db5316285fc30c53cec9d7b19a3877e7fdf',
'com.sun.xml.fastinfoset:FastInfoset:1.2.15:FastInfoset-1.2.15.jar:785861db11ca1bd0d1956682b974ad73eb19cd3e01a4b3fa82d62eca97210aec',
'com.sun.istack:istack-commons-runtime:3.0.8:istack-commons-runtime-3.0.8.jar:4ffabb06be454a05e4398e20c77fa2b6308d4b88dfbef7ca30a76b5b7d5505ef',
'com.sun.xml.fastinfoset:FastInfoset:1.2.16:FastInfoset-1.2.16.jar:056f3a1e144409f21ed16afc26805f58e9a21f3fce1543c42d400719d250c511',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.activation:javax.activation-api:1.2.0:javax.activation-api-1.2.0.jar:43fdef0b5b6ceb31b0424b208b930c74ab58fac2ceeb7b3f6fd3aeb8b5ca4393',
'it.unimi.dsi:fastutil:8.4.0:fastutil-8.4.0.jar:2ad2824a4a0a0eb836b52ee2fc84ba2134f44bce7bfa54015ae3f31c710a3071',
'jakarta.activation:jakarta.activation-api:1.2.1:jakarta.activation-api-1.2.1.jar:8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b',
'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2:jakarta.xml.bind-api-2.3.2.jar:69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.3.1:jaxb-api-2.3.1.jar:88b955a0df57880a26a74708bc34f74dcaf8ebf4e78843a28b50eae945732b06',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
'net.java.dev.jna:jna-platform:5.6.0:jna-platform-5.6.0.jar:9ecea8bf2b1b39963939d18b70464eef60c508fed8820f9dcaba0c35518eabf7',
'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf',
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
@@ -84,24 +86,24 @@ dependencyVerification {
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.codehaus.mojo:animal-sniffer-annotations:1.18:animal-sniffer-annotations-1.18.jar:47f05852b48ee9baefef80fa3d8cea60efa4753c0013121dd7fe5eef2e5c729d',
'org.glassfish.jaxb:jaxb-runtime:2.3.1:jaxb-runtime-2.3.1.jar:45fecfa5c8217ce1f3652ab95179790ec8cc0dec0384bca51cbeb94a293d9f2f',
'org.glassfish.jaxb:txw2:2.3.1:txw2-2.3.1.jar:34975dde1c6920f1a39791142235689bc3cd357e24d05edd8ff93b885bd68d60',
'org.glassfish.jaxb:jaxb-runtime:2.3.2:jaxb-runtime-2.3.2.jar:e6e0a1e89fb6ff786279e6a0082d5cef52dc2ebe67053d041800737652b4fd1b',
'org.glassfish.jaxb:txw2:2.3.2:txw2-2.3.2.jar:4a6a9f483388d461b81aa9a28c685b8b74c0597993bf1884b04eddbca95f48fe',
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
'org.jetbrains.kotlin:kotlin-reflect:1.3.72:kotlin-reflect-1.3.72.jar:a188d9367de1c4ee9479db630985c0597b20709c83161b1430d24edb27e38c40',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72:kotlin-stdlib-common-1.3.72.jar:5e7d1552863e480c1628b1cc39ce230ef829f5b7230106215a05acda5172203a',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72:kotlin-stdlib-jdk7-1.3.72.jar:40566c0c08d414b9413ba556ff7f8a0b04b98b9f0f424d122dd2088510efccc4',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72:kotlin-stdlib-jdk8-1.3.72.jar:133da70cfc07b56094282eac5c59bccd59f167ee2ead22e5282876d8bc10bf95',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.72:kotlin-stdlib-1.3.72.jar:3856a7349ebacd6d1be6802b2fed9c4dc2c5a564ea92b6b945ac988243d4b16b',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601',
'org.jetbrains.kotlin:kotlin-reflect:1.4.31:kotlin-reflect-1.4.31.jar:91fad0b42974a7d5811e30a61f05706e176b144235717c6de7e81e3a781028f2',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31:kotlin-stdlib-common-1.4.31.jar:57962f44371a746b678218a0802a8712c6255206de9a69ede215e3aa4b044708',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31:kotlin-stdlib-jdk7-1.4.31.jar:1f966e54e86cf4b7d7014afdce04e0f3ee4625084cda3494edccc7b84af52664',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31:kotlin-stdlib-jdk8-1.4.31.jar:b2f8364435ebcb0106ff9d4415a11ffdef8ec7786ee6e5ed465a01556cbd1683',
'org.jetbrains.kotlin:kotlin-stdlib:1.4.31:kotlin-stdlib-1.4.31.jar:76a599d88b167e8ac90879b6daa722c6ad3452ba714c9aba19bd196544b97f1c',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b',
'org.jmock:jmock-legacy:2.12.0:jmock-legacy-2.12.0.jar:dea3a9cca653d082e2fe7e40232e982fe03a9984c7d67ceff24f3e03fe580dcd',
'org.jmock:jmock-testjar:2.12.0:jmock-testjar-2.12.0.jar:efefbcf6cd294d0e29f0c46eb2a3380d4ca4e1763ff719c69e2f2ac62f564a04',
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
'org.jvnet.staxex:stax-ex:1.8:stax-ex-1.8.jar:95b05d9590af4154c6513b9c5dc1fb2e55b539972ba0a9ef28e9a0c01d83ad77',
'org.jvnet.staxex:stax-ex:1.8.1:stax-ex-1.8.1.jar:20522549056e9e50aa35ef0b445a2e47a53d06be0b0a9467d704e2483ffb049a',
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
'org.ow2.asm:asm-analysis:7.0:asm-analysis-7.0.jar:e981f8f650c4d900bb033650b18e122fa6b161eadd5f88978d08751f72ee8474',
'org.ow2.asm:asm-commons:7.0:asm-commons-7.0.jar:fed348ef05958e3e846a3ac074a12af5f7936ef3d21ce44a62c4fa08a771927d',
@@ -109,5 +111,7 @@ dependencyVerification {
'org.ow2.asm:asm-util:7.0:asm-util-7.0.jar:75fbbca440ef463f41c2b0ab1a80abe67e910ac486da60a7863cbcb5bae7e145',
'org.ow2.asm:asm:7.0:asm-7.0.jar:b88ef66468b3c978ad0c97fd6e90979e56155b4ac69089ba7a44e9aa7ffe9acf',
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
'xerces:xercesImpl:2.12.0:xercesImpl-2.12.0.jar:b50d3a4ca502faa4d1c838acb8aa9480446953421f7327e338c5dda3da5e76d0',
'xml-apis:xml-apis:1.4.01:xml-apis-1.4.01.jar:a840968176645684bb01aed376e067ab39614885f9eee44abe35a5f20ebe7fad',
]
}

View File

@@ -10,7 +10,7 @@ apply from: '../dagger.gradle'
dependencies {
implementation project(path: ':bramble-api', configuration: 'default')
implementation 'com.madgag.spongycastle:core:1.58.0.0'
implementation 'org.bouncycastle:bcprov-jdk15on:1.65'
implementation 'com.h2database:h2:1.4.192' // The last version that supports Java 1.6
implementation 'org.bitlet:weupnp:0.1.4'
implementation 'net.i2p.crypto:eddsa:0.2.0'

View File

@@ -21,9 +21,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.crypto.CryptoException;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.whispersystems.curve25519.Curve25519;
import org.whispersystems.curve25519.Curve25519KeyPair;

View File

@@ -6,33 +6,33 @@ import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
import org.spongycastle.crypto.BasicAgreement;
import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.CryptoException;
import org.spongycastle.crypto.DerivationFunction;
import org.spongycastle.crypto.KeyEncoder;
import org.spongycastle.crypto.Mac;
import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
import org.spongycastle.crypto.digests.SHA256Digest;
import org.spongycastle.crypto.engines.AESLightEngine;
import org.spongycastle.crypto.engines.IESEngine;
import org.spongycastle.crypto.generators.ECKeyPairGenerator;
import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator;
import org.spongycastle.crypto.generators.KDF2BytesGenerator;
import org.spongycastle.crypto.macs.HMac;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.AsymmetricKeyParameter;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECKeyGenerationParameters;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.crypto.params.IESWithCipherParameters;
import org.spongycastle.crypto.parsers.ECIESPublicKeyParser;
import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.BasicAgreement;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.KeyEncoder;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.AESLightEngine;
import org.bouncycastle.crypto.engines.IESEngine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.IESWithCipherParameters;
import org.bouncycastle.crypto.parsers.ECIESPublicKeyParser;
import java.io.FileInputStream;
import java.io.FileOutputStream;

View File

@@ -3,7 +3,7 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
import org.spongycastle.crypto.generators.SCrypt;
import org.bouncycastle.crypto.generators.SCrypt;
import java.util.logging.Logger;

View File

@@ -4,11 +4,11 @@ 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.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.security.GeneralSecurityException;

View File

@@ -2,7 +2,7 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import javax.annotation.concurrent.Immutable;

View File

@@ -2,7 +2,7 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import javax.annotation.concurrent.Immutable;

View File

@@ -9,8 +9,8 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeys;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import java.security.GeneralSecurityException;

View File

@@ -3,12 +3,12 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.AuthenticatedCipher;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.DataLengthException;
import org.spongycastle.crypto.engines.XSalsa20Engine;
import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
import org.spongycastle.crypto.macs.Poly1305;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.engines.XSalsa20Engine;
import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
import org.bouncycastle.crypto.macs.Poly1305;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import java.security.GeneralSecurityException;

View File

@@ -5,9 +5,9 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import org.briarproject.bramble.util.Base32;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.SHA3Digest;
import org.spongycastle.util.encoders.Base64;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.util.encoders.Base64;
import java.nio.charset.Charset;

View File

@@ -3,9 +3,9 @@ package org.briarproject.bramble.rendezvous;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.spongycastle.crypto.engines.Salsa20Engine;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.engines.Salsa20Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;

View File

@@ -3,7 +3,7 @@ package org.briarproject.bramble.crypto;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.util.StringUtils;
import org.junit.Test;
import org.spongycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import java.util.Random;

View File

@@ -1,115 +0,0 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
import org.spongycastle.crypto.generators.ECKeyPairGenerator;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECKeyGenerationParameters;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.math.ec.MontgomeryLadderMultiplier;
import java.math.BigInteger;
import java.security.SecureRandom;
import static org.junit.Assert.assertEquals;
public class EllipticCurveMultiplicationTest extends BrambleTestCase {
@Test
public void testMultiplierProducesSameResultsAsDefault() throws Exception {
// Instantiate the default implementation of the curve
X9ECParameters defaultX9Parameters =
TeleTrusTNamedCurves.getByName("brainpoolp256r1");
ECCurve defaultCurve = defaultX9Parameters.getCurve();
ECPoint defaultG = defaultX9Parameters.getG();
BigInteger defaultN = defaultX9Parameters.getN();
BigInteger defaultH = defaultX9Parameters.getH();
ECDomainParameters defaultParameters = new ECDomainParameters(
defaultCurve, defaultG, defaultN, defaultH);
// Instantiate an implementation using the Montgomery ladder multiplier
ECDomainParameters montgomeryParameters =
constantTime(defaultParameters);
// Generate two key pairs with each set of parameters, using the same
// deterministic PRNG for both sets of parameters
byte[] seed = new byte[32];
new SecureRandom().nextBytes(seed);
// Montgomery ladder multiplier
SecureRandom random = new PseudoSecureRandom(seed);
ECKeyGenerationParameters montgomeryGeneratorParams =
new ECKeyGenerationParameters(montgomeryParameters, random);
ECKeyPairGenerator montgomeryGenerator = new ECKeyPairGenerator();
montgomeryGenerator.init(montgomeryGeneratorParams);
AsymmetricCipherKeyPair montgomeryKeyPair1 =
montgomeryGenerator.generateKeyPair();
ECPrivateKeyParameters montgomeryPrivate1 =
(ECPrivateKeyParameters) montgomeryKeyPair1.getPrivate();
ECPublicKeyParameters montgomeryPublic1 =
(ECPublicKeyParameters) montgomeryKeyPair1.getPublic();
AsymmetricCipherKeyPair montgomeryKeyPair2 =
montgomeryGenerator.generateKeyPair();
ECPrivateKeyParameters montgomeryPrivate2 =
(ECPrivateKeyParameters) montgomeryKeyPair2.getPrivate();
ECPublicKeyParameters montgomeryPublic2 =
(ECPublicKeyParameters) montgomeryKeyPair2.getPublic();
// Default multiplier
random = new PseudoSecureRandom(seed);
ECKeyGenerationParameters defaultGeneratorParams =
new ECKeyGenerationParameters(defaultParameters, random);
ECKeyPairGenerator defaultGenerator = new ECKeyPairGenerator();
defaultGenerator.init(defaultGeneratorParams);
AsymmetricCipherKeyPair defaultKeyPair1 =
defaultGenerator.generateKeyPair();
ECPrivateKeyParameters defaultPrivate1 =
(ECPrivateKeyParameters) defaultKeyPair1.getPrivate();
ECPublicKeyParameters defaultPublic1 =
(ECPublicKeyParameters) defaultKeyPair1.getPublic();
AsymmetricCipherKeyPair defaultKeyPair2 =
defaultGenerator.generateKeyPair();
ECPrivateKeyParameters defaultPrivate2 =
(ECPrivateKeyParameters) defaultKeyPair2.getPrivate();
ECPublicKeyParameters defaultPublic2 =
(ECPublicKeyParameters) defaultKeyPair2.getPublic();
// The key pairs generated with both sets of parameters should be equal
assertEquals(montgomeryPrivate1.getD(), defaultPrivate1.getD());
assertEquals(montgomeryPublic1.getQ(), defaultPublic1.getQ());
assertEquals(montgomeryPrivate2.getD(), defaultPrivate2.getD());
assertEquals(montgomeryPublic2.getQ(), defaultPublic2.getQ());
// OK, all of the above was just sanity checks - now for the test!
ECDHCBasicAgreement agreement = new ECDHCBasicAgreement();
agreement.init(montgomeryPrivate1);
BigInteger sharedSecretMontgomeryMontgomery =
agreement.calculateAgreement(montgomeryPublic2);
agreement.init(montgomeryPrivate1);
BigInteger sharedSecretMontgomeryDefault =
agreement.calculateAgreement(defaultPublic2);
agreement.init(defaultPrivate1);
BigInteger sharedSecretDefaultMontgomery =
agreement.calculateAgreement(montgomeryPublic2);
agreement.init(defaultPrivate1);
BigInteger sharedSecretDefaultDefault =
agreement.calculateAgreement(defaultPublic2);
// Shared secrets calculated with different multipliers should be equal
assertEquals(sharedSecretMontgomeryMontgomery,
sharedSecretMontgomeryDefault);
assertEquals(sharedSecretMontgomeryMontgomery,
sharedSecretDefaultMontgomery);
assertEquals(sharedSecretMontgomeryMontgomery,
sharedSecretDefaultDefault);
}
private static ECDomainParameters constantTime(ECDomainParameters in) {
ECCurve curve = in.getCurve().configure().setMultiplier(
new MontgomeryLadderMultiplier()).create();
BigInteger x = in.getG().getAffineXCoord().toBigInteger();
BigInteger y = in.getG().getAffineYCoord().toBigInteger();
ECPoint g = curve.createPoint(x, y);
return new ECDomainParameters(curve, g, in.getN(), in.getH());
}
}

View File

@@ -3,30 +3,26 @@ package org.briarproject.bramble.crypto;
import net.i2p.crypto.eddsa.EdDSASecurityProvider;
import net.i2p.crypto.eddsa.KeyPairGenerator;
import org.spongycastle.asn1.sec.SECNamedCurves;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
import org.spongycastle.crypto.BasicAgreement;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
import org.spongycastle.crypto.digests.Blake2bDigest;
import org.spongycastle.crypto.generators.ECKeyPairGenerator;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECKeyGenerationParameters;
import org.spongycastle.crypto.params.ParametersWithRandom;
import org.spongycastle.crypto.signers.DSADigestSigner;
import org.spongycastle.crypto.signers.DSAKCalculator;
import org.spongycastle.crypto.signers.ECDSASigner;
import org.spongycastle.crypto.signers.HMacDSAKCalculator;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.math.ec.MontgomeryLadderMultiplier;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.BasicAgreement;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.DSADigestSigner;
import org.bouncycastle.crypto.signers.DSAKCalculator;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
import org.whispersystems.curve25519.Curve25519;
import org.whispersystems.curve25519.Curve25519KeyPair;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.Provider;
@@ -55,14 +51,12 @@ public class EllipticCurvePerformanceTest {
for (String name : SEC_NAMES) {
ECDomainParameters params =
convertParams(SECNamedCurves.getByName(name));
runTest(name + " default", params);
runTest(name + " constant", constantTime(params));
runTest(name, params);
}
for (String name : BRAINPOOL_NAMES) {
ECDomainParameters params =
convertParams(TeleTrusTNamedCurves.getByName(name));
runTest(name + " default", params);
runTest(name + " constant", constantTime(params));
runTest(name, params);
}
runCurve25519Test();
runEd25519Test();
@@ -193,13 +187,4 @@ public class EllipticCurvePerformanceTest {
return new ECDomainParameters(in.getCurve(), in.getG(), in.getN(),
in.getH());
}
private static ECDomainParameters constantTime(ECDomainParameters in) {
ECCurve curve = in.getCurve().configure().setMultiplier(
new MontgomeryLadderMultiplier()).create();
BigInteger x = in.getG().getAffineXCoord().toBigInteger();
BigInteger y = in.getG().getAffineYCoord().toBigInteger();
ECPoint g = curve.createPoint(x, y);
return new ECDomainParameters(curve, g, in.getN(), in.getH());
}
}

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import org.spongycastle.crypto.CryptoException;
import org.bouncycastle.crypto.CryptoException;
import java.security.SecureRandom;

View File

@@ -1,11 +1,11 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.digests.Blake2bDigest;
import org.spongycastle.crypto.engines.Salsa20Engine;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.engines.Salsa20Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import javax.annotation.concurrent.NotThreadSafe;

View File

@@ -15,7 +15,6 @@ dependencyVerification {
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6',
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
@@ -27,6 +26,7 @@ dependencyVerification {
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.bouncycastle:bcprov-jdk15on:1.65:bcprov-jdk15on-1.65.jar:e78f96eb59066c94c94fb2d6b5eb80f52feac6f5f9776898634f8addec6e2137',
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',

View File

@@ -464,6 +464,42 @@
</intent-filter>
</activity>
<activity
android:name="org.briarproject.briar.android.remotewipe.RemoteWipeActivatedActivity"
android:noHistory="true"
android:theme="@style/TranslucentTheme">
<intent-filter>
<action android:name="org.briarproject.briar.android.AndroidNotifiactionManager" />
</intent-filter>
</activity>
<activity
android:name="org.briarproject.briar.android.remotewipe.RemoteWipeSetupActivity"
android:label="@string/activity_name_remote_wipe"
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.settings.SettingsActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeActivity"
android:label="@string/activity_name_activate_remote_wipe"
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeActivity"
android:label="@string/activity_name_revoke_remote_wipe"
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.logout.ExitActivity"
android:theme="@android:style/Theme.NoDisplay" />

View File

@@ -33,6 +33,7 @@ import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
import org.briarproject.briar.android.remotewipe.RemoteWipeActivatedActivity;
import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.util.BriarNotificationBuilder;
import org.briarproject.briar.api.android.AndroidNotificationManager;

View File

@@ -39,6 +39,7 @@ import org.briarproject.briar.android.login.LoginModule;
import org.briarproject.briar.android.navdrawer.NavDrawerModule;
import org.briarproject.briar.android.privategroup.conversation.GroupConversationModule;
import org.briarproject.briar.android.privategroup.list.GroupListModule;
import org.briarproject.briar.android.remotewipe.RemoteWipeModule;
import org.briarproject.briar.android.reporting.DevReportModule;
import org.briarproject.briar.android.settings.SettingsModule;
import org.briarproject.briar.android.sharing.SharingModule;
@@ -96,6 +97,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
SharingModule.class,
OwnerReturnShardModule.class,
CustodianReturnShardModule.class,
RemoteWipeModule.class,
SocialBackupSetupModule.class
})
public class AppModule {

View File

@@ -18,14 +18,19 @@ import com.bumptech.glide.Glide;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.briar.R;
import org.briarproject.briar.android.logout.HideUiActivity;
import org.briarproject.briar.android.remotewipe.RemoteWipeActivatedActivity;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.LockManager;
import org.briarproject.briar.api.remotewipe.RemoteWipeActivatedEvent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -62,7 +67,7 @@ import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGO
import static org.briarproject.briar.api.android.LockManager.ACTION_LOCK;
import static org.briarproject.briar.api.android.LockManager.EXTRA_PID;
public class BriarService extends Service {
public class BriarService extends Service implements EventListener {
public static String EXTRA_START_RESULT =
"org.briarproject.briar.START_RESULT";
@@ -96,6 +101,8 @@ public class BriarService extends Service {
@Inject
volatile AndroidExecutor androidExecutor;
private volatile boolean started = false;
@Inject
volatile EventBus eventBus;
@Override
public void onCreate() {
@@ -173,6 +180,8 @@ public class BriarService extends Service {
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
registerReceiver(receiver, filter);
eventBus.addListener(this);
}, "LifecycleStartup");
}
@@ -239,6 +248,7 @@ public class BriarService extends Service {
wakeLockManager.executeWakefully(() -> {
if (started) lifecycleManager.stopServices();
}, "LifecycleShutdown");
eventBus.removeListener(this);
}, "LifecycleShutdown");
}
@@ -327,6 +337,19 @@ public class BriarService extends Service {
stopSelf(); // This will call onDestroy()
}
/**
* Listens for the remote wipe event
*/
@Override
public void eventOccurred(Event e) {
if (e instanceof RemoteWipeActivatedEvent) {
Intent i = new Intent(this, RemoteWipeActivatedActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK
| FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
}
}
public class BriarBinder extends Binder {
/**

View File

@@ -63,6 +63,15 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberModule;
import org.briarproject.briar.android.privategroup.reveal.GroupRevealModule;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment;
import org.briarproject.briar.android.remotewipe.RemoteWipeActivatedActivity;
import org.briarproject.briar.android.remotewipe.RemoteWipeDisplayFragment;
import org.briarproject.briar.android.remotewipe.RemoteWipeSetupActivity;
import org.briarproject.briar.android.remotewipe.RemoteWipeSetupExplainerFragment;
import org.briarproject.briar.android.remotewipe.WiperSelectorFragment;
import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeActivity;
import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeExplainerFragment;
import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeActivity;
import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeSuccessFragment;
import org.briarproject.briar.android.reporting.CrashFragment;
import org.briarproject.briar.android.reporting.CrashReportActivity;
import org.briarproject.briar.android.reporting.ReportFormFragment;
@@ -209,6 +218,14 @@ public interface ActivityComponent {
void inject(RestoreAccountActivity restoreAccountActivity);
void inject(RemoteWipeSetupActivity remoteWipeSetupActivity);
void inject(ActivateRemoteWipeActivity activateRemoteWipeActivity);
void inject(RemoteWipeActivatedActivity remoteWipeActivatedActivity);
void inject(RevokeRemoteWipeActivity revokeRemoteWipeActivity);
// Fragments
void inject(AuthorNameFragment fragment);
@@ -295,5 +312,15 @@ public interface ActivityComponent {
void inject(CustodianReturnShardErrorFragment custodianReturnShardErrorFragment);
void inject(WiperSelectorFragment wiperSelectorFragment);
void inject(RemoteWipeDisplayFragment remoteWipeDisplayFragment);
void inject(ActivateRemoteWipeExplainerFragment activateRemoteWipeExplainerFragment);
void inject(RevokeRemoteWipeSuccessFragment revokeRemoteWipeSuccessFragment);
void inject(RemoteWipeSetupExplainerFragment remoteWipeSetupExplainerFragment);
void inject(SetupExplainerFragment setupExplainerFragment);
}

View File

@@ -52,6 +52,8 @@ import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache
import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.introduction.IntroductionActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeActivity;
import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeActivity;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity;
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
import org.briarproject.briar.android.view.BriarRecyclerView;
@@ -371,6 +373,20 @@ public class ConversationActivity extends BriarActivity
observeOnce(viewModel.getContactItem(), this, contact ->
menu.findItem(R.id.action_set_alias).setEnabled(true));
// enable remote wipe action if available
observeOnce(viewModel.amRemoteWiper(), this, amWiper -> {
if (amWiper != null && amWiper) {
menu.findItem(R.id.action_remote_wipe).setEnabled(true);
}
});
// enable revoke remote wipe action if available
observeOnce(viewModel.isRemoteWiper(), this, isWiper -> {
if (isWiper != null && isWiper) {
menu.findItem(R.id.action_revoke_remote_wipe).setEnabled(true);
}
});
// enable help recover account action if available
observeOnce(viewModel.amCustodian(), this, enable -> {
if (enable) {
@@ -410,6 +426,18 @@ public class ConversationActivity extends BriarActivity
i.putExtra(CONTACT_ID, contactId.getInt());
startActivity(i);
return true;
case R.id.action_remote_wipe:
if (contactId == null) return false;
Intent r = new Intent(this, ActivateRemoteWipeActivity.class);
r.putExtra(CONTACT_ID, contactId.getInt());
startActivity(r);
return true;
case R.id.action_revoke_remote_wipe:
if (contactId == null) return false;
Intent s = new Intent(this, RevokeRemoteWipeActivity.class);
s.putExtra(CONTACT_ID, contactId.getInt());
startActivity(s);
return true;
default:
return super.onOptionsItemSelected(item);
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.android.conversation;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.conversation.ConversationRequest;
import org.briarproject.briar.api.conversation.ConversationResponse;
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader;
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
import javax.annotation.Nullable;
@@ -38,6 +39,13 @@ class ConversationNoticeItem extends ConversationItem {
this.msgText = null;
}
ConversationNoticeItem(@LayoutRes int layoutRes, String text,
RemoteWipeMessageHeader r) {
super(layoutRes, r);
this.text = text;
this.msgText = null;
}
@Nullable
String getMsgText() {
return msgText;

View File

@@ -40,7 +40,7 @@ import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent;
import org.briarproject.briar.api.socialbackup.SocialBackup;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
import java.util.Collection;
@@ -86,6 +86,7 @@ public class ConversationViewModel extends DbViewModel
private final PrivateMessageFactory privateMessageFactory;
private final AttachmentRetriever attachmentRetriever;
private final AttachmentCreator attachmentCreator;
private final RemoteWipeManager remoteWipeManager;
private final SocialBackupManager socialBackupManager;
@Nullable
@@ -107,6 +108,8 @@ public class ConversationViewModel extends DbViewModel
new MutableLiveData<>();
private final MutableLiveEvent<PrivateMessageHeader> addedHeader =
new MutableLiveEvent<>();
private final MutableLiveData<Boolean> amRemoteWiper = new MutableLiveData<>();
private final MutableLiveData<Boolean> isRemoteWiper = new MutableLiveData<>();
private final MutableLiveData<Boolean> amCustodian = new MutableLiveData<>();
@Inject
@@ -122,6 +125,7 @@ public class ConversationViewModel extends DbViewModel
SettingsManager settingsManager,
PrivateMessageFactory privateMessageFactory,
AttachmentRetriever attachmentRetriever,
RemoteWipeManager remoteWipeManager,
AttachmentCreator attachmentCreator,
SocialBackupManager socialBackupManager) {
super(application, dbExecutor, lifecycleManager, db, androidExecutor);
@@ -134,6 +138,7 @@ public class ConversationViewModel extends DbViewModel
this.privateMessageFactory = privateMessageFactory;
this.attachmentRetriever = attachmentRetriever;
this.attachmentCreator = attachmentCreator;
this.remoteWipeManager = remoteWipeManager;
this.socialBackupManager = socialBackupManager;
messagingGroupId = map(contactItem, c ->
messagingManager.getContactGroup(c.getContact()).getId());
@@ -303,11 +308,18 @@ public class ConversationViewModel extends DbViewModel
showIntroductionOnboarding.postEvent(true);
}
// Check if we are a remote wiper for this contact
boolean amWiper = db.transactionWithResult(true,
txn -> remoteWipeManager.amWiper(txn, c));
amRemoteWiper.postValue(amWiper);
boolean isWiper = db.transactionWithResult(true,
txn -> remoteWipeManager.isWiper(txn, c));
isRemoteWiper.postValue(isWiper);
// Check if we are a social backup custodian for this contact
boolean amCustodianBool = db.transactionWithResult(true,
txn -> socialBackupManager.amCustodian(txn, c));
amCustodian.postValue(amCustodianBool);
}
@DatabaseExecutor
@@ -393,6 +405,14 @@ public class ConversationViewModel extends DbViewModel
return addedHeader;
}
LiveData<Boolean> amRemoteWiper() {
return amRemoteWiper;
}
LiveData<Boolean> isRemoteWiper() {
return isRemoteWiper;
}
LiveData<Boolean> amCustodian() {
return amCustodian;
}

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.attachment.AttachmentItem;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.conversation.ConversationMessageVisitor;
@@ -16,6 +17,7 @@ import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader;
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
import java.util.List;
@@ -308,6 +310,55 @@ class ConversationVisitor implements
}
}
@Override
public ConversationItem visitRemoteWipeMessage(RemoteWipeMessageHeader r) {
switch (r.getMessageType()) {
case SETUP:
if (r.isLocal()) {
String text = ctx.getString(R.string.remote_wipe_setup_sent,
contactName.getValue());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_out, text,
r);
} else {
String text =
ctx.getString(R.string.remote_wipe_setup_received,
contactName.getValue());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_in, text, r);
}
case WIPE:
String text = ctx.getString(R.string.remote_wipe_wipe_sent,
contactName.getValue()) + " " + UiUtils
.formatDateAbsolute(ctx, r.getMessageExpiry());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_out, text, r);
case CONFIRM:
System.out.println("Processing confirm message");
String confirmText =
ctx.getString(R.string.remote_wipe_confirm_received,
contactName.getValue());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_in, confirmText, r);
default: // REVOKE
String revokeText;
if (r.isLocal()) {
revokeText = ctx.getString(R.string.remote_wipe_revoke_sent,
contactName.getValue());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_out,
revokeText, r);
} else {
revokeText =
ctx.getString(R.string.remote_wipe_revoke_received,
contactName.getValue());
return new ConversationNoticeItem(
R.layout.list_item_conversation_notice_in,
revokeText, r);
}
}
}
interface TextCache {
@Nullable
String getText(MessageId m);

View File

@@ -138,6 +138,7 @@ public class NavDrawerActivity extends BriarActivity implements
navDrawerViewModel.showExpiryWarning()
.observe(this, this::showExpiryWarning);
}
navDrawerViewModel.shouldAskForDozeWhitelisting().observe(this, ask -> {
if (ask) showDozeDialog(getString(R.string.setup_doze_intro));
});

View File

@@ -0,0 +1,41 @@
package org.briarproject.briar.android.remotewipe;
import android.os.Bundle;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.lifecycle.ViewModelProvider;
public class RemoteWipeActivatedActivity extends BriarActivity {
@Inject
ViewModelProvider.Factory viewModelFactory;
RemoteWipeActivatedViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(RemoteWipeActivatedViewModel.class);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel.getConfirmSent()
.observeEvent(this, confirmed -> {
if (confirmed) {
signOut(true, true);
}
});
viewModel.sendConfirmMessages();
}
}

View File

@@ -0,0 +1,67 @@
package org.briarproject.briar.android.remotewipe;
import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
public class RemoteWipeActivatedViewModel extends AndroidViewModel implements
EventListener {
private final RemoteWipeManager remoteWipeManager;
private final DatabaseComponent db;
private final MutableLiveEvent<Boolean> confirmSent =
new MutableLiveEvent<>();
private int numberOfConfirmMessages;
private int messagesSent = 0;
@Inject
RemoteWipeActivatedViewModel(
@NonNull Application application,
RemoteWipeManager remoteWipeManager,
DatabaseComponent db, EventBus eventBus) {
super(application);
this.remoteWipeManager = remoteWipeManager;
this.db = db;
eventBus.addListener(this);
}
public void sendConfirmMessages() {
try {
numberOfConfirmMessages = db.transactionWithResult(false,
remoteWipeManager::sendConfirmMessages);
} catch (DbException | FormatException e) {
// If there is a problem sending the messages, just wipe
confirmSent.postEvent(true);
}
}
public LiveEvent<Boolean> getConfirmSent() {
return confirmSent;
}
@Override
public void eventOccurred(Event e) {
// As soon as we know the confirm messages are sent, we can wipe
if (e instanceof MessagesSentEvent) {
messagesSent++;
if (messagesSent >= numberOfConfirmMessages) {
confirmSent.postEvent(true);
}
}
}
}

View File

@@ -0,0 +1,115 @@
package org.briarproject.briar.android.remotewipe;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.contact.ContactListAdapter;
import org.briarproject.briar.android.contact.ContactListItem;
import org.briarproject.briar.android.contact.OnContactClickListener;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.view.BriarRecyclerView;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
public class RemoteWipeDisplayFragment extends BaseFragment
implements OnContactClickListener<ContactListItem> {
public static final String TAG = RemoteWipeDisplayFragment.class.getName();
private final ContactListAdapter adapter = new ContactListAdapter(this);
private BriarRecyclerView list;
@Inject
ViewModelProvider.Factory viewModelFactory;
private RemoteWipeSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(RemoteWipeSetupViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// change toolbar text (relevant when navigating back to this fragment)
requireActivity().setTitle(R.string.assigned_wipers);
View contentView = inflater.inflate(R.layout.fragment_remote_wipe_display, container, false);
viewModel.getWiperContactIds();
list = contentView.findViewById(R.id.wiperList);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
list.setAdapter(adapter);
list.setEmptyText(R.string.no_contacts);
viewModel.getContactListItems().observe(getViewLifecycleOwner(),
result -> result.onError(this::handleException)
.onSuccess(adapter::submitList)
);
Button changeWipersButton = contentView.findViewById(R.id.button_change);
changeWipersButton.setOnClickListener(e -> viewModel.onModifyWipers());
Button disableRemoteWipeButton = contentView.findViewById(R.id.button_cancel);
disableRemoteWipeButton.setOnClickListener(e -> viewModel.onDisableRemoteWipe());
viewModel.getState().observe(getViewLifecycleOwner(), this::onStateChanged);
return contentView;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void onItemClick(View view, ContactListItem item) {
}
@Override
public void onStart() {
super.onStart();
list.startPeriodicUpdate();
}
@Override
public void onStop() {
super.onStop();
list.stopPeriodicUpdate();
}
private void onStateChanged(RemoteWipeSetupState state) {
if (state.equals(RemoteWipeSetupState.DISABLED)) {
showDisabledDialog();
}
}
private void showDisabledDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
builder.setTitle(R.string.remote_wipe_disable_success);
builder.setMessage(R.string.remote_wipe_disable_success_explain);
builder.setPositiveButton(R.string.ok,
(dialog, which) -> viewModel.onSuccessDismissed());
builder.setIcon(R.drawable.ic_baseline_done_outline_24);
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

@@ -0,0 +1,38 @@
package org.briarproject.briar.android.remotewipe;
import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeViewModel;
import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeViewModel;
import org.briarproject.briar.android.viewmodel.ViewModelKey;
import androidx.lifecycle.ViewModel;
import dagger.Binds;
import dagger.Module;
import dagger.multibindings.IntoMap;
@Module
public abstract class RemoteWipeModule {
@Binds
@IntoMap
@ViewModelKey(RemoteWipeSetupViewModel.class)
abstract ViewModel bindRemoteWipeSetupViewModel(
RemoteWipeSetupViewModel remoteWipeSetupViewModel);
@Binds
@IntoMap
@ViewModelKey(ActivateRemoteWipeViewModel.class)
abstract ViewModel bindActivateRemoteWipeViewModel(
ActivateRemoteWipeViewModel activateRemoteWipeViewModel);
@Binds
@IntoMap
@ViewModelKey(RevokeRemoteWipeViewModel.class)
abstract ViewModel bindRevokeRemoteWipeViewModel(
RevokeRemoteWipeViewModel RevokeRemoteWipeViewModel);
@Binds
@IntoMap
@ViewModelKey(RemoteWipeActivatedViewModel.class)
abstract ViewModel bindRemoteWipeActivatedViewModel(
RemoteWipeActivatedViewModel remoteWipeActivatedViewModel);
}

View File

@@ -0,0 +1,76 @@
package org.briarproject.briar.android.remotewipe;
import android.os.Bundle;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.contactselection.ContactSelectorListener;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
import java.util.Collection;
import javax.inject.Inject;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
public class RemoteWipeSetupActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener, ContactSelectorListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
RemoteWipeSetupViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(RemoteWipeSetupViewModel.class);
viewModel.getState().observe(this, this::onStateChanged);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_distributed_backup);
if (viewModel.remoteWipeIsSetup()) {
showInitialFragment(new RemoteWipeDisplayFragment());
} else {
showInitialFragment(new RemoteWipeSetupExplainerFragment());
}
}
@Override
public void contactsSelected(Collection<ContactId> contacts) {
Toast.makeText(this,
String.format("Selected %d contacts", contacts.size()),
Toast.LENGTH_SHORT).show();
try {
viewModel.setupRemoteWipe(contacts);
} catch (Exception e) {
// Display error fragment
}
}
private void onStateChanged(RemoteWipeSetupState state) {
if (state.equals(RemoteWipeSetupState.FAILED)) {
Toast.makeText(this,
R.string.remote_wipe_setup_failed,
Toast.LENGTH_LONG).show();
finish();
} else if (state.equals(RemoteWipeSetupState.SELECTING)) {
showNextFragment(WiperSelectorFragment.newInstance());
} else if (state.equals(RemoteWipeSetupState.FINISHED)) {
finish();
} else if (state.equals(RemoteWipeSetupState.MODIFY)) {
showNextFragment(WiperSelectorFragment.newInstance());
}
}
}

View File

@@ -0,0 +1,57 @@
package org.briarproject.briar.android.remotewipe;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
public class RemoteWipeSetupExplainerFragment extends
BaseFragment {
public static final String TAG =
RemoteWipeSetupExplainerFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private RemoteWipeSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(RemoteWipeSetupViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_remote_wipe_setup_explainer,
container, false);
Button confirmButton = view.findViewById(R.id.button_confirm);
confirmButton.setOnClickListener(e -> viewModel.onExplainerConfirmed());
Button cancelButton = view.findViewById(R.id.button_cancel);
cancelButton.setOnClickListener(e -> viewModel.onExplainerCancelled());
return view;
}
@Override
public String getUniqueTag() {
return TAG;
}
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.briar.android.remotewipe;
public enum RemoteWipeSetupState {
FAILED,
SUCCESS,
FINISHED,
SELECTING,
MODIFY,
DISABLED
}

View File

@@ -0,0 +1,140 @@
package org.briarproject.briar.android.remotewipe;
import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.connection.ConnectionRegistry;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.android.contact.ContactsViewModel;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import androidx.lifecycle.MutableLiveData;
@NotNullByDefault
public class RemoteWipeSetupViewModel extends ContactsViewModel {
private final RemoteWipeManager remoteWipeManager;
private final DatabaseComponent db;
private List<ContactId> wiperContactIds;
private final MutableLiveData<RemoteWipeSetupState> state =
new MutableLiveData<>();
private final ContactManager contactManager;
private final AuthorManager authorManager;
@Inject
RemoteWipeSetupViewModel(
@NonNull Application application,
RemoteWipeManager remoteWipeManager,
@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager,
AuthorManager authorManager,
ConversationManager conversationManager,
ConnectionRegistry connectionRegistry,
EventBus eventBus,
AndroidExecutor androidExecutor,
ContactManager contactManager,
DatabaseComponent db) {
super(application, dbExecutor, lifecycleManager, db, androidExecutor,
contactManager, authorManager, conversationManager,
connectionRegistry, eventBus);
this.remoteWipeManager = remoteWipeManager;
this.contactManager = contactManager;
this.authorManager = authorManager;
this.db = db;
getWiperContactIds();
loadContacts();
}
public boolean remoteWipeIsSetup() {
try {
return db.transactionWithResult(true,
txn -> {
boolean isSetup = remoteWipeManager.remoteWipeIsSetup(txn);
if (isSetup) wiperContactIds = remoteWipeManager.getWiperContactIds(txn);
return isSetup;
});
} catch (DbException e) {
return false;
}
}
public List<ContactId> getWiperContactIds() {
try {
wiperContactIds = db.transactionWithResult(true,
remoteWipeManager::getWiperContactIds);
} catch (DbException ignored) {
return new ArrayList<ContactId>();
}
return wiperContactIds;
}
@UiThread
public void onExplainerConfirmed() {
state.postValue(RemoteWipeSetupState.SELECTING);
}
@UiThread
public void onExplainerCancelled() {
state.postValue(RemoteWipeSetupState.FINISHED);
}
@UiThread
public void onSuccessDismissed() {
state.postValue(RemoteWipeSetupState.FINISHED);
}
@UiThread
public void onModifyWipers() {
state.postValue(RemoteWipeSetupState.MODIFY);
}
@UiThread
public void onDisableRemoteWipe() {
try {
db.transaction(false, remoteWipeManager::revokeAll);
state.postValue(RemoteWipeSetupState.DISABLED);
} catch (DbException | FormatException e) {
e.printStackTrace();
state.postValue(RemoteWipeSetupState.FINISHED);
}
}
public void setupRemoteWipe(Collection<ContactId> wipers)
throws DbException, FormatException {
db.transaction(false, txn -> {
remoteWipeManager.setup(txn, (List<ContactId>) wipers);
state.postValue(RemoteWipeSetupState.SUCCESS);
});
}
@Override
protected boolean displayContact(ContactId contactId) {
// Check if contact is a wiper
return wiperContactIds.contains(contactId);
}
public MutableLiveData<RemoteWipeSetupState> getState() {
return state;
}
}

View File

@@ -0,0 +1,118 @@
package org.briarproject.briar.android.remotewipe;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.contactselection.BaseContactSelectorAdapter;
import org.briarproject.briar.android.contactselection.ContactSelectorController;
import org.briarproject.briar.android.contactselection.ContactSelectorFragment;
import org.briarproject.briar.android.contactselection.SelectableContactItem;
import org.briarproject.briar.android.socialbackup.creation.CreateBackupController;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class WiperSelectorFragment extends ContactSelectorFragment {
public static final String TAG = WiperSelectorFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private RemoteWipeSetupViewModel viewModel;
@Inject
CreateBackupController controller;
public static WiperSelectorFragment newInstance() {
Bundle args = new Bundle();
WiperSelectorFragment
fragment = new WiperSelectorFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(RemoteWipeSetupViewModel.class);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
selectedContacts.addAll(viewModel.getWiperContactIds());
requireActivity().setTitle(R.string.title_select_wipers);
viewModel.getState().observe(this, this::onStateChanged);
}
private void onStateChanged(RemoteWipeSetupState state) {
if (state.equals(RemoteWipeSetupState.SUCCESS)) {
showSuccessDialog();
}
}
@Override
protected ContactSelectorController<SelectableContactItem> getController() {
return controller;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
protected void onSelectionChanged() {
super.onSelectionChanged();
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_contacts_selected);
if (item == null) return;
BaseContactSelectorAdapter a = adapter;
selectedContacts = a.getSelectedContactIds();
int n = selectedContacts.size();
int min = 2;
boolean enough = n >= min;
item.setVisible(enough);
if (n == 0) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_contacts), min),
Toast.LENGTH_SHORT).show();
} else if (n < min) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_more_contacts), min - n),
Toast.LENGTH_SHORT).show();
}
}
private void showSuccessDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
builder.setTitle(R.string.remote_wipe_setup_success);
builder.setPositiveButton(R.string.ok,
(dialog, which) -> viewModel.onSuccessDismissed());
builder.setIcon(R.drawable.ic_baseline_done_outline_24);
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

@@ -0,0 +1,66 @@
package org.briarproject.briar.android.remotewipe.activate;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.lifecycle.ViewModelProvider;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
public class ActivateRemoteWipeActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
ActivateRemoteWipeViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(ActivateRemoteWipeViewModel.class);
viewModel.getState().observe(this, this::onStateChanged);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_distributed_backup);
if (savedInstanceState == null) {
Intent intent = getIntent();
int id = intent.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException("No ContactId");
ContactId contactId = new ContactId(id);
viewModel.setContactId(contactId);
showInitialFragment(new ActivateRemoteWipeExplainerFragment());
}
}
private void onStateChanged(ActivateRemoteWipeState state) {
switch(state) {
case FAILED:
Toast.makeText(this,
R.string.remote_wipe_activate_failure,
Toast.LENGTH_LONG).show();
break;
case SUCCESS:
// Handled by the popup dialog on the explainer
break;
default: // FINISHED or CANCELLED
finish();
break;
}
}
}

View File

@@ -0,0 +1,83 @@
package org.briarproject.briar.android.remotewipe.activate;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
public class ActivateRemoteWipeExplainerFragment extends BaseFragment {
public static final String TAG =
ActivateRemoteWipeExplainerFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private ActivateRemoteWipeViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(ActivateRemoteWipeViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_activate_remote_wipe_explainer,
container, false);
TextView titleText = view.findViewById(R.id.textView);
titleText.setText(String.format(getString(R.string.remote_wipe_activate_explain_short), viewModel.getContactName()));
TextView explainText = view.findViewById(R.id.textViewExplain);
explainText.setText(String.format(getString(R.string.remote_wipe_activate_explain_long), viewModel.getContactName()));
Button cancelButton = view.findViewById(R.id.button_cancel);
cancelButton.setOnClickListener(e -> viewModel.onCancelClicked());
Button confirmButton = view.findViewById(R.id.button_confirm);
confirmButton.setOnClickListener(e -> viewModel.onConfirmClicked());
viewModel.getState().observe(getViewLifecycleOwner(), this::onStateChanged);
return view;
}
private void onStateChanged(ActivateRemoteWipeState state) {
if (state == ActivateRemoteWipeState.SUCCESS) {
showSuccessDialog();
}
}
@Override
public String getUniqueTag() {
return TAG;
}
private void showSuccessDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
builder.setTitle(R.string.remote_wipe_activate_success);
builder.setPositiveButton(R.string.ok,
(dialog, which) -> viewModel.onSuccessDismissed());
builder.setIcon(R.drawable.ic_baseline_done_outline_24);
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.briar.android.remotewipe.activate;
public enum ActivateRemoteWipeState {
FAILED,
SUCCESS,
FINISHED,
CANCELLED
}

View File

@@ -0,0 +1,89 @@
package org.briarproject.briar.android.remotewipe.activate;
import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.android.remotewipe.RemoteWipeSetupState;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import java.text.Normalizer;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
public class ActivateRemoteWipeViewModel extends AndroidViewModel {
private final RemoteWipeManager remoteWipeManager;
private final ContactManager contactManager;
private final DatabaseComponent db;
private final MutableLiveData<ActivateRemoteWipeState> state = new MutableLiveData<>();
private ContactId contactId;
private String contactName;
@Inject
public ActivateRemoteWipeViewModel(
@NonNull Application application,
RemoteWipeManager remoteWipeManager,
ContactManager contactManager,
DatabaseComponent db) {
super(application);
this.remoteWipeManager = remoteWipeManager;
this.contactManager = contactManager;
this.db = db;
}
private void activateWipe() {
try {
db.transaction(false, txn -> {
try {
remoteWipeManager.wipe(txn, db.getContact(txn, contactId));
} catch (DbException e) {
state.postValue(ActivateRemoteWipeState.FAILED);
} catch (FormatException e) {
state.postValue(ActivateRemoteWipeState.FAILED);
}
state.postValue(ActivateRemoteWipeState.SUCCESS);
});
} catch (DbException e) {
state.postValue(ActivateRemoteWipeState.FAILED);
}
}
public MutableLiveData<ActivateRemoteWipeState> getState() {
return state;
}
public void setContactId(ContactId c) {
contactId = c;
try {
contactName = UiUtils.getContactDisplayName(contactManager.getContact(c));
} catch (DbException e) {
e.printStackTrace();
}
}
public String getContactName() {
return contactName;
}
public void onCancelClicked() {
state.postValue(ActivateRemoteWipeState.CANCELLED);
}
public void onSuccessDismissed() {
state.postValue(ActivateRemoteWipeState.FINISHED);
}
public void onConfirmClicked() {
activateWipe();
}
}

View File

@@ -0,0 +1,67 @@
package org.briarproject.briar.android.remotewipe.revoke;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.lifecycle.ViewModelProvider;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
public class RevokeRemoteWipeActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
RevokeRemoteWipeViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(RevokeRemoteWipeViewModel.class);
viewModel.getState().observe(this, this::onStateChanged);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_distributed_backup);
if (savedInstanceState == null) {
Intent intent = getIntent();
int id = intent.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException("No ContactId");
ContactId contactId = new ContactId(id);
viewModel.revokeRemoteWipeStatus(contactId);
// showInitialFragment(new ActivateRemoteWipeExplainerFragment());
}
}
private void onStateChanged(RevokeRemoteWipeState state) {
switch(state) {
case FAILED:
// TODO change text
Toast.makeText(this,
R.string.remote_wipe_activate_failure,
Toast.LENGTH_LONG).show();
break;
case SUCCESS:
showNextFragment(new RevokeRemoteWipeSuccessFragment());
break;
default: // FINISHED or CANCELLED
finish();
break;
}
}
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.briar.android.remotewipe.revoke;
public enum RevokeRemoteWipeState {
FAILED,
SUCCESS,
FINISHED
}

View File

@@ -0,0 +1,53 @@
package org.briarproject.briar.android.remotewipe.revoke;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
public class RevokeRemoteWipeSuccessFragment extends BaseFragment {
public static final String TAG =
RevokeRemoteWipeSuccessFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private RevokeRemoteWipeViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(RevokeRemoteWipeViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_revoke_remote_wipe_success,
container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(e -> viewModel.onSuccessDismissed());
return view;
}
@Override
public String getUniqueTag() {
return TAG;
}
}

View File

@@ -0,0 +1,60 @@
package org.briarproject.briar.android.remotewipe.revoke;
import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeState;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
public class RevokeRemoteWipeViewModel extends AndroidViewModel {
private final RemoteWipeManager remoteWipeManager;
private final DatabaseComponent db;
private final MutableLiveData<RevokeRemoteWipeState> state = new MutableLiveData<>();
private ContactId contactId;
@Inject
public RevokeRemoteWipeViewModel(
@NonNull Application application,
RemoteWipeManager remoteWipeManager,
DatabaseComponent db) {
super(application);
this.remoteWipeManager = remoteWipeManager;
this.db = db;
}
public MutableLiveData<RevokeRemoteWipeState> getState() {
return state;
}
public void revokeRemoteWipeStatus(ContactId c) {
contactId = c;
try {
db.transaction(false, txn -> {
remoteWipeManager.revoke(txn, contactId);
});
} catch (DbException e) {
state.postValue(RevokeRemoteWipeState.FAILED);
} catch (FormatException e) {
state.postValue(RevokeRemoteWipeState.FAILED);
}
state.postValue(RevokeRemoteWipeState.SUCCESS);
}
public void onCancelClicked() {
// state.postValue(ActivateRemoteWipeState.CANCELLED);
}
public void onSuccessDismissed() {
state.postValue(RevokeRemoteWipeState.FINISHED);
}
}

View File

@@ -0,0 +1,27 @@
package org.briarproject.briar.android.socialbackup;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.BaseContactListAdapter;
import org.briarproject.briar.android.contact.ContactItem;
import org.briarproject.briar.android.contact.ContactItemViewHolder;
public class CustodianStatusAdapter extends BaseContactListAdapter<ContactItem, ContactItemViewHolder<ContactItem>> {
CustodianStatusAdapter(Context context) {
super(context, ContactItem.class, null);
}
@Override
public ContactItemViewHolder<ContactItem> onCreateViewHolder(
ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.list_item_contact_small, viewGroup, false);
return new ContactItemViewHolder<>(v);
}
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="409.2dp"
android:height="161.7dp"
android:viewportHeight="161.7"
android:viewportWidth="409.2">
<path
android:fillColor="#FF000000"
android:pathData="M369.8,157.4l-4.3,-4.3l-7.1,-2.4c-3.9,-1.3 -8.7,-3 -10.7,-3.7l-3.7,-1.3l3.5,-0.2c8.2,-0.4 13,-4 14.3,-10.9c0.8,-4.1 1.1,-17.3 0.8,-33c-0.2,-8.1 -0.2,-15.4 0,-16.3c0.1,-0.9 0.5,-2.4 0.9,-3.4c1.2,-3.5 0.3,-11.9 -1.9,-17.6c-0.3,-0.9 -1.9,-4.2 -3.5,-7.4c-4.2,-8.2 -4.5,-8.9 -4.9,-10.5c-0.5,-1.8 -0.2,-5.4 0.5,-6.8c0.7,-1.3 2.2,-2.9 3.2,-3.5c1.3,-0.7 2.6,0.1 4.7,2.9c3.4,4.5 14,19.4 15.7,22.2c3.7,6 6,11.2 8,18.8c0.7,2.5 1.9,7 2.7,10.1c0.8,3.1 2.7,10.2 4.1,15.8l2.6,10.2l4.6,5.2c2.6,2.9 5.8,6.5 7.2,8c1.4,1.6 2.5,3 2.5,3.2c0,0.3 -34.5,29.3 -34.9,29.3C374.2,161.7 372.2,159.7 369.8,157.4zM275.9,141c-1.3,-0.6 -2.2,-1.4 -2.9,-2.3c-2.1,-2.7 -2,2.4 -1.9,-68.5l0.1,-64l0.7,-1.2c1,-1.9 2,-2.9 3.7,-3.9l1.6,-0.9l37.8,-0.1c42.5,-0.1 39.4,-0.2 42.1,2.2c0.9,0.8 1.8,2 2.2,2.9c0.7,1.6 0.7,1.6 0.8,14.2l0.1,12.6l-1.8,-0.1c-1.4,-0.1 -2.1,0 -3.2,0.5c-2,1 -3.9,2.9 -5.1,5.1l-1,2l0,-12.8l0,-12.8h-33.6h-33.6v51.3v51.3h33.6h33.6l0.1,-34.4c0.1,-33 0.1,-34.4 0.6,-32.9c0.3,0.8 1.8,4 3.4,7c5.5,10.6 5.4,9.9 5.4,47.2c0,27.6 -0.1,30 -1.7,33.1c-1.1,2.2 -2.7,3.7 -5.1,4.7l-1.7,0.7L314,141.8l-36.2,0.1L275.9,141L275.9,141zM318.3,135.9c2.9,-1.3 4.5,-3.7 4.4,-6.6c0,-4.1 -3.1,-7.2 -7.1,-7.2c-2.1,0 -3.6,0.6 -5.2,2.2c-2.2,2.2 -2.8,5.4 -1.3,8.3c0.7,1.4 2.5,3 4,3.5C314.6,136.6 317,136.6 318.3,135.9z"/>
<path
android:fillColor="#FF000000"
android:pathData="M39.4,157.4l4.3,-4.3l7.1,-2.4c3.9,-1.3 8.7,-3 10.7,-3.7l3.7,-1.3l-3.5,-0.2c-8.2,-0.4 -13,-4 -14.3,-10.9c-0.8,-4.1 -1.1,-17.3 -0.8,-33c0.2,-8.1 0.2,-15.4 0,-16.3c-0.1,-0.9 -0.5,-2.4 -0.9,-3.4c-1.2,-3.5 -0.3,-11.9 1.9,-17.6c0.3,-0.9 1.9,-4.2 3.5,-7.4c4.2,-8.2 4.5,-8.9 4.9,-10.5c0.5,-1.8 0.2,-5.4 -0.5,-6.8c-0.7,-1.3 -2.2,-2.9 -3.2,-3.5c-1.3,-0.7 -2.6,0.1 -4.7,2.9c-3.4,4.5 -14,19.4 -15.7,22.2c-3.7,6 -6,11.2 -8,18.8c-0.7,2.5 -1.9,7 -2.7,10.1c-0.8,3.1 -2.7,10.2 -4.1,15.8l-2.6,10.2l-4.6,5.2c-2.6,2.9 -5.8,6.5 -7.2,8s-2.5,3 -2.5,3.2c0,0.3 34.5,29.3 34.9,29.3C35,161.7 37.1,159.7 39.4,157.4zM133.3,141c1.3,-0.6 2.2,-1.4 2.9,-2.3c2.1,-2.7 2,2.4 1.9,-68.5l-0.1,-64l-0.7,-1.2c-1,-1.9 -2,-2.9 -3.7,-3.9l-1.6,-0.9l-37.8,-0.1c-42.5,-0.1 -39.4,-0.2 -42.1,2.2c-0.9,0.8 -1.8,2 -2.2,2.9c-0.7,1.6 -0.7,1.6 -0.8,14.2L49,32l1.8,-0.1c1.4,-0.1 2.1,0 3.2,0.5c2,1 3.9,2.9 5.1,5.1l1,2l0,-12.8l0,-12.8h33.6h33.6v51.3v51.3L93.8,116.5L60.2,116.5l-0.1,-34.4c-0.1,-33 -0.1,-34.4 -0.6,-32.9c-0.3,0.8 -1.8,4 -3.4,7c-5.5,10.6 -5.4,9.9 -5.4,47.2c0,27.6 0.1,30 1.7,33.1c1.1,2.2 2.7,3.7 5.1,4.7l1.7,0.7l36.2,0.1l36.2,0.1L133.3,141L133.3,141zM90.9,135.9c-2.9,-1.3 -4.5,-3.7 -4.4,-6.6c0,-4.1 3.1,-7.2 7.1,-7.2c2.1,0 3.6,0.6 5.2,2.2c2.2,2.2 2.8,5.4 1.3,8.3c-0.7,1.4 -2.5,3 -4,3.5C94.6,136.6 92.3,136.6 90.9,135.9z"/>
<path
android:fillColor="#000000"
android:pathData="M 207.61295,88.782357 h -6.42588 v -12.85177 h 6.42588 m 0,25.703533 h -6.42588 v -6.425883 h 6.42588 m -38.5553,16.064713 h 70.68472 L 204.40001,50.227047 Z"
android:strokeWidth="3.21294165"/>
<path
android:fillColor="#000000"
android:pathData="M90.58,50.42A8.19,8.01 0 0,1 98.77,42.42A8.19,8.01 0 0,1 106.96,50.42C106.96,51.46 107.79,52.27 108.85,52.27C109.91,52.27 110.74,51.46 110.74,50.42V48.58H113.99V50.42A5.67,5.54 0 0,1 108.85,55.97A5.67,5.54 0 0,1 103.18,50.42A4.41,4.31 0 0,0 98.77,46.11A4.41,4.31 0 0,0 94.36,50.42H97.35V53.6C104.79,55.71 110.11,62.31 110.11,70.14A17.64,17.25 0 0,1 92.47,87.38A17.64,17.25 0 0,1 74.83,70.14C74.83,62.31 80.15,55.71 87.43,53.6V50.42H90.58M117.67,50.42H122.6V52.89H117.67V50.42M110.11,45.5V40.57H112.57V45.5H110.11M114.92,46.42L118.5,42.92L120.29,44.68L116.71,48.18L114.92,46.42Z" />
</vector>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium"
tools:ignore="VectorDrawableCompat">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/remote_wipe_activate_explain_short"
android:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:srcCompat="@drawable/remote_wipe_activate_explain" />
<TextView
android:id="@+id/textViewExplain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/remote_wipe_activate_explain_long"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/button_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/remote_wipe_activate_button_confirm"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
<Button
android:id="@+id/button_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/remote_wipe_activate_button_cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_confirm" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,130 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Backup creation" />
<Button
android:id="@+id/buttonSelectThreshold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Select Threshold" />
<Button
android:id="@+id/buttonShardsSent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Shards sent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Setup" />
<Button
android:id="@+id/buttonWelcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Welcome" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Recovery from secrect owner's point of view" />
<Button
android:id="@+id/buttonOwnerRecoveryExplainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Explainer" />
<Button
android:id="@+id/buttonOwnerRecoveryReceivedShard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Shard received" />
<Button
android:id="@+id/buttonOwnerRecoveryMain1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Main (0 shards)" />
<Button
android:id="@+id/buttonOwnerRecoveryMain2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Main (1 shard)" />
<Button
android:id="@+id/buttonOwnerRecoveryMain3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Recovering account…" />
<Button
android:id="@+id/buttonOwnerRecoveryAccountRecovered"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Account recovered" />
<Button
android:id="@+id/buttonOwnerRecoveryErrorExplainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Error" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Recovery from custodian's point of view" />
<Button
android:id="@+id/buttonCustodianRecoveryExplainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Explainer" />
<Button
android:id="@+id/buttonCustodianRecoveryErrorExplainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Error" />
<Button
android:id="@+id/buttonCustodianRecoveryDone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_security"
android:text="Done" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium"
tools:ignore="VectorDrawableCompat">
<TextView
android:id="@+id/text_view_explain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/remote_wipe_display_explain"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/button_cancel"
style="@style/BriarButtonFlat.Negative.Tiny"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/remote_wipe_disable"
app:layout_constraintBottom_toBottomOf="@+id/button_change"
app:layout_constraintEnd_toStartOf="@id/button_change"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_explain" />
<Button
android:id="@+id/button_change"
style="@style/BriarButtonFlat.Positive.Tiny"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/remote_wipe_modify_contacts"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/button_cancel"
app:layout_constraintTop_toBottomOf="@id/text_view_explain" />
<org.briarproject.briar.android.view.BriarRecyclerView
android:id="@+id/wiperList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button_change"
app:scrollToEnd="false" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium"
tools:ignore="VectorDrawableCompat">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/remote_wipe_setup_explain_title"
android:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:srcCompat="@drawable/remote_wipe_activate_explain" />
<TextView
android:id="@+id/textViewExplain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/remote_wipe_setup_explain_long"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/button_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/title_select_wipers"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
<Button
android:id="@+id/button_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/remote_wipe_activate_button_cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_confirm" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/button_confirm"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/remote_wipe_revoke_success"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_done_outline_24" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -33,4 +33,18 @@
android:title="@string/help_recover_account"
android:enabled="false"
app:showAsAction="never"/>
<item
android:id="@+id/action_remote_wipe"
android:icon="@drawable/action_delete_white"
android:title="@string/activate_remote_wipe"
android:enabled="false"
app:showAsAction="never"/>
<item
android:id="@+id/action_revoke_remote_wipe"
android:icon="@drawable/action_delete_white"
android:title="@string/revoke_remote_wipe"
android:enabled="false"
app:showAsAction="never"/>
</menu>

View File

@@ -0,0 +1,524 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<!-- Setup -->
<string name="setup_title">Selamat Datang di Briar</string>
<string name="setup_name_explanation">Nama panggilan Anda akan terlihat pada setiap materi yang Anda unggah. Anda tidak bisa mengubah setelah membuatnya.</string>
<string name="setup_next">Selanjutnya</string>
<string name="setup_password_intro">Pilih Kata Sandi</string>
<string name="setup_password_explanation">Akun Briar Anda tersimpan dalam perangkat terenkripsi, bukan di komputasi awan. Jika lupa kata sandi atau menghapus aplikasi Briar, Anda hanya bisa mengembalikan akun jika sudah membuat pencadangan sosial.\n\nBuatlah kata sandi panjang yang susah ditebak, misalnya empat kata acak atau sepuluh huruf, angka, dan simbol acak.</string>
<string name="setup_doze_title">Sambungan Belakang</string>
<string name="setup_doze_intro">Untuk menerima pesan, Briar perlu tetap terkoneksi dengan sambungan belakang.</string>
<string name="setup_doze_explanation">Untuk menerima pesan, Briar perlu tetap terkoneksi dengan sambungan belakang. Silakan nonaktifkan pengoptimalan baterai agar Briar tetap bisa terkoneksi.</string>
<string name="setup_doze_button">Izinkan Koneksi</string>
<string name="choose_nickname">Pilih nama panggilan Anda</string>
<string name="choose_password">Pilih kata sandi Anda</string>
<string name="confirm_password">Konfirmasi kata sandi Anda</string>
<string name="name_too_long">Nama terlalu panjang</string>
<string name="password_too_weak">Kata sandi terlalu lemah</string>
<string name="passwords_do_not_match">Kata sandi tidak cocok</string>
<string name="create_account_button">Buat Akun</string>
<string name="more_info">Informasi Selanjutnya</string>
<string name="don_t_ask_again">Jangan tanya lagi</string>
<string name="setup_huawei_text">Silakan ketuk tombol di bawah dan pastikan Briar terlindungi di layar \"Aplikasi Terlindungi\".</string>
<string name="setup_huawei_button">Lindungi Briar</string>
<string name="setup_huawei_help">Jika tidak dimasukkan dalam daftar aplikasi terlindungi, Briar tidak akan bisa berfungsi di sambungan belakang.</string>
<string name="warning_dozed">%tidak bisa berfungsi di sambungan belakang</string>
<!-- Login -->
<string name="enter_password">Kata Sandi</string>
<string name="try_again">Kata sandi salah, coba lagi</string>
<string name="dialog_title_cannot_check_password">Tidak Bisa Memeriksa Kata Sandi</string>
<string name="dialog_message_cannot_check_password">Briar tidak bisa memeriksa kata sandi Anda. Silakan booting ulang perangkat untuk memecahkan masalah Anda.</string>
<string name="sign_in_button">Masuk</string>
<string name="forgotten_password">Saya lupa kata sandi</string>
<string name="dialog_title_lost_password">Kata sandi hilang</string>
<string name="dialog_message_lost_password">Akun Briar Anda tersimpan dalam perangkat terenkripsi, bukan di komputasi awan, jadi kami tidak bisa membuat ulang kata sandi Anda. Jika Anda memiliki cadangan sosial, Anda bisa menghapus akun Anda dan membuat kata sandi baru ketika Anda mengembalikan. Apakah Anda mau menghapus akun dan memulai lagi?\n\nPerhatian: Identitas, kontak, dan pesan Anda akan sepenuhnya hilang jika Anda tidak punya cadangan.</string>
<string name="startup_failed_notification_title">Briar tidak bisa memulai</string>
<string name="startup_failed_notification_text">Ketuk untuk informasi selanjutnya.</string>
<string name="startup_failed_activity_title">Briar Gagal Memulai</string>
<string name="startup_failed_db_error">Karena beberapa alasan, pangkalan data Briar Anda rusak dan tidak bisa diperbaiki. Akun, data, dan semua kontak Anda hilang. Sayangnya, Anda perlu memasang ulang Briar atau membuat akun baru dengan memilih \'Saya lupa kata sandi\' pada bagian kata sandi.</string>
<string name="startup_failed_data_too_old_error">Akun Anda dibuat menggunakan versi lama aplikasi ini dan tidak bisa dibuka dengan versi sekarang. Anda harus memasang ulang versi lama atau membuat akun baru dengan memilih \'Saya lupa kata sandi\' pada bagian kata sandi.</string>
<string name="startup_failed_data_too_new_error">Versi aplikasi ini sudah usang. Silakan naikkan ke versi terbaru dan coba lagi.</string>
<string name="startup_failed_service_error">Briar tidak bisa memulai pengaya yang diperlukan. Memasang ulang Briar biasanya memecahkan masalah. Namun, harap diperhatikan bahwa Anda akan kehilangan semua data karena Briar tidak menggunakan peladen terpusat untuk menyimpan data Anda.</string>
<plurals name="expiry_warning">
<item quantity="other">Ini adalah Briar versi percobaan. Akun Anda akan kedaluwarsa pada % hari dan tidak bisa diperbarui.</item>
</plurals>
<string name="expiry_date_reached">Perangkat lunak ini sudah kedaluwarsa.\nTerima kasih sudah mencoba!</string>
<string name="download_briar">Untuk lanjut menggunakan Briar, silakan unduh versi terbaru.</string>
<string name="create_new_account">Anda akan perlu membuat akun baru, tetapi bisa menggunakan nama sama.</string>
<string name="download_briar_button">Unduh Keluaran Terbaru</string>
<string name="startup_open_database">Mendekrip Pangkalan Data…</string>
<string name="startup_migrate_database">Meningkatkan Pangkalan Data…</string>
<string name="startup_compact_database">Meringkas Pangkalan Data…</string>
<!-- Navigation Drawer -->
<string name="nav_drawer_open_description">Buka penarik navigasi</string>
<string name="nav_drawer_close_description">Tutup penarik navigasi</string>
<string name="contact_list_button">Kontak</string>
<string name="groups_button">Group Pribadi</string>
<string name="forums_button">Forum</string>
<string name="blogs_button">Blog</string>
<!-- This is part of the main menu. The app will be locked when this is tapped. -->
<string name="lock_button">Kunci Aplikasi</string>
<string name="settings_button">Pengaturan</string>
<string name="sign_out_button">Keluar</string>
<string name="transports_onboarding_text">Ketuk di sini untuk mengontrol bagaimana Briar tersambung dengan kontak Anda.</string>
<!-- Transports: Tor -->
<string name="transport_tor">Internet</string>
<string name="tor_device_status_online_wifi">Ponsel Anda punya akses Internet lewat Wi-Fi</string>
<string name="tor_device_status_online_mobile">Ponsel Anda punya akses Internet lewat paket data</string>
<string name="tor_device_status_offline">Ponsel Anda tidak punya akses Internet</string>
<string name="tor_plugin_status_enabling">Briar menyambung ke Internet</string>
<string name="tor_plugin_status_active">Briar tersambung Internet</string>
<string name="tor_plugin_status_inactive">Briar tidak bisa menyambung ke Internet</string>
<string name="tor_plugin_status_disabled">Briar dikonfigurasi tidak menggunakan Internet</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar dikonfigurasi tidak menggunakan paket data</string>
<string name="tor_plugin_status_disabled_battery">Briar dikonfigurasi tidak menggunakan Internet ketika menggunakan baterai</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar dikonfigurasi tidak menggunakan Internet di negara ini</string>
<!-- Transports: Wi-Fi -->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">Jaringan Wi-Fi Sama</string>
<string name="lan_device_status_on">Ponsel Anda tersambung Wi-Fi</string>
<string name="lan_device_status_off">Ponsel Anda tidak tersambung Wi-Fi</string>
<string name="lan_plugin_status_enabling">Briar menyambung ke Wi-Fi</string>
<string name="lan_plugin_status_active">Briar tersambung Wi-Fi</string>
<string name="lan_plugin_status_inactive">Briar tidak tersambung Wi-Fi</string>
<string name="lan_plugin_status_disabled">Briar dikonfigutasi tidak menggunakan Wi-Fi</string>
<!-- Transports: Bluetooth -->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">Bluetooth ponsel Anda hidup</string>
<string name="bt_device_status_off">Bluetooth ponsel Anda mati</string>
<string name="bt_plugin_status_enabling">Briar menyambung ke Bluetooth</string>
<string name="bt_plugin_status_active">Briar tersambung Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar tidak bisa tersambung Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar dikonfigurasi tidak menggunakan Bluetooth</string>
<!-- Notifications -->
<string name="reminder_notification_title">Keluar Briar</string>
<string name="reminder_notification_text">Ketuk untuk masuk kembali.</string>
<string name="reminder_notification_channel_title">Pengingat Masuk Briar</string>
<string name="reminder_notification_dismiss">Singkirkan</string>
<string name="ongoing_notification_title">Masuk Briar</string>
<string name="ongoing_notification_text">Sentuh untuk membuka Briar.</string>
<plurals name="private_message_notification_text">
<item quantity="other">%d Pesan-pesan pribadi baru.</item>
</plurals>
<!-- Misc -->
<string name="now">sekarang</string>
<string name="show">Tunjukkan</string>
<string name="hide">Sembunyikan</string>
<string name="ok">OK</string>
<string name="cancel">Batal</string>
<string name="got_it">Paham</string>
<string name="delete">Hapus</string>
<string name="accept">Terima</string>
<string name="decline">Tolak</string>
<string name="online">Daring</string>
<string name="offline">Luring</string>
<string name="send">Kirim</string>
<string name="allow">Izinkan</string>
<string name="open">Buka</string>
<string name="change">Ubah</string>
<string name="no_data">Tidak Ada Data</string>
<string name="ellipsis"></string>
<string name="text_too_long">Teks yang dimasukkan terlalu panjang</string>
<string name="show_onboarding">Perlihatkan Dialog Bantuan</string>
<string name="fix">Bereskan</string>
<string name="help">Bantu</string>
<string name="sorry">Maaf</string>
<string name="error_start_activity">Tidak tersedia di sistem Anda</string>
<string name="status_heading">Status:</string>
<!-- Contacts and Private Conversations-->
<string name="no_contacts">Tidak ada kontak untuk diperlihatkan</string>
<string name="no_contacts_action">Ketuk ikon + untuk menambah kontak</string>
<string name="date_no_private_messages">Tidak ada pesan.</string>
<string name="no_private_messages">Tidak ada pesan untuk diperlihatkan</string>
<string name="message_hint">Tulisa pesan</string>
<string name="image_caption_hint">Tambahkan keterangan (pilihan)</string>
<string name="image_attach">Lampirkan gambar</string>
<string name="image_attach_error">Tidak bisa melampirkan gambar</string>
<string name="image_attach_error_too_big">Gambar terlalu besar. Batasnya %d MB.</string>
<string name="image_attach_error_invalid_mime_type">Format gambar tidak mendukung: %s</string>
<string name="set_contact_alias">Ubah nama kontak</string>
<string name="set_contact_alias_hint">Nama kontak</string>
<string name="delete_all_messages">Hapus semua pesan</string>
<string name="dialog_title_delete_all_messages">Konfirmasi Penghapusan Pesan</string>
<string name="dialog_message_delete_all_messages">Anda yakin untuk menghapus semua pesan?</string>
<string name="dialog_title_not_all_messages_deleted">Tidak bisa menghapus semua pesan</string>
<string name="delete_contact">Hapus kontak</string>
<string name="dialog_title_delete_contact">Konfirmasi Penghapusan Kontak</string>
<string name="dialog_message_delete_contact">Apakah Anda yakin akan menghapus kontak ini dan semua pesannya?</string>
<string name="contact_deleted_toast">Kontak Dihapus</string>
<!-- This is shown in the action bar when opening an image in fullscreen that the user sent -->
<string name="you">Anda</string>
<string name="save_image">Simpan gambar</string>
<string name="dialog_title_save_image">Simpan gambar?</string>
<string name="save_image_success">Gambar tersimpan</string>
<string name="save_image_error">Tidak bisa menghapus gambar</string>
<string name="dialog_title_no_image_support">Gambar tidak tersedia</string>
<!-- Adding Contacts -->
<string name="add_contact_title">Tambah Kontak Sekitar</string>
<string name="face_to_face">Anda harus bertemu dengan orang yang ingin Anda tambahkan sebagai kontak.\n\nHal ini ubtuk mencegah orang lain membuat akun tiruan atau membaca pesan Anda di kemudian hari.</string>
<string name="continue_button">Lanjut</string>
<string name="try_again_button">Coba Lagi</string>
<string name="waiting_for_contact_to_scan">Menunggu kontak untuk memindai dan menyambung\u2026</string>
<string name="exchanging_contact_details">Bertukar detail kontak\u2026</string>
<string name="contact_added_toast">Kontak ditambahkan: %s</string>
<string name="contact_already_exists">%s kontak sudah ada</string>
<string name="qr_code_invalid">Kode batang salah</string>
<string name="qr_code_too_old">Kode batang yang Anda pindai adalah versi lebih lama %s.\n\nSilakan minta kontak Anda untuk menaikkan ke versi terbaru dan coba lagi.</string>
<string name="qr_code_too_new">Kode batang yang Anda pindai adalah versi lebih mutakhir %s.\n\nSilakan naikkan ke versi terbaru dan coba lagi.</string>
<string name="camera_error">Kamera Rusak</string>
<string name="connecting_to_device">Menyambung ke perangkat\u2026</string>
<string name="authenticating_with_device">Mengautentikasi ke perangkat\u2026</string>
<string name="connection_error_title">Tidak bisa menyambung dengan kontak Anda</string>
<string name="connection_error_feedback">Jika masalah ini berulang, silakan <a href="feedback">kirim umpan balik</a> untuk memperbaiki aplikasi.</string>
<!-- Adding Contacts Remotely -->
<string name="add_contact_remotely_title_case">Tambahkan kontak jarak jauh</string>
<string name="add_contact_nearby_title">Tambahkan kontak di dekat Anda</string>
<string name="add_contact_remotely_title">Tambahkan kontak jarak jauh</string>
<string name="contact_link_intro">Masukkan tautan dari kontak Anda di sini</string>
<string name="contact_link_hint">Tautan kontak</string>
<string name="paste_button">Tempel</string>
<string name="add_contact_button">Tambahkan kontak</string>
<string name="copy_button">Salin</string>
<string name="share_button">Bagi</string>
<string name="send_link_title">Tukar tautan</string>
<string name="add_contact_choose_nickname">Pilih Nama Panggilan</string>
<string name="add_contact_choose_a_nickname">Masukkan Nama Panggilan</string>
<string name="nickname_intro">Berikan kontak Anda nama panggilan. Hanya Anda yang bisa melihat.</string>
<string name="your_link">Beri tautan ini pada kontak yang ingin Anda tambahkan</string>
<string name="link_clip_label">Tautan Briar</string>
<string name="link_copied_toast">Tautan Tersalin</string>
<string name="adding_contact_error">Ada masalah ketika menambah kontak.</string>
<string name="pending_contact_requests_snackbar">Ada permintaan kontak yang tertunda</string>
<string name="pending_contact_requests">Permintaan Kontak Tertunda</string>
<string name="no_pending_contacts">Tidak ada kontak tertunda</string>
<string name="waiting_for_contact_to_come_online">Menunggu kontak untuk daring…</string>
<string name="connecting">Menyambung…</string>
<string name="adding_contact">Menambah kontak…</string>
<string name="adding_contact_failed">Penambahan kontak gagal</string>
<string name="dialog_title_remove_pending_contact">Konfirmasi Penghapusan</string>
<string name="dialog_message_remove_pending_contact">Kontak ini masih sedang ditambahkan. Jika Anda menghapusnya, kontak tidak akan ditambahkan.</string>
<string name="own_link_error">Masukkan tautan kontak Anda, bukan tautan Anda sendiri</string>
<string name="nickname_missing">Masukkan nama panggilan</string>
<string name="invalid_link">Tautan Keliru</string>
<string name="unsupported_link">Tautan ini dari Briar versi lebih mutakhir. Silakan naikkan ke versi terbaru dan coba lagi.</string>
<string name="intent_own_link">Anda membuka tautan Anda sendiri. Gunakan dari kontak yang ingin Anda tambahkan!</string>
<string name="missing_link">Masukkan tautan</string>
<!-- This is a numeral indicating the first step in a series of screens -->
<string name="step_1">1</string>
<!-- This is a numeral indicating the second step in a series of screens -->
<string name="step_2">2</string>
<plurals name="contact_added_notification_text">
<item quantity="other">%d kontak baru ditambahkan.</item>
</plurals>
<string name="offline_state">Tidak ada koneksi Internet</string>
<string name="duplicate_link_dialog_title">Gandakan Tautan</string>
<string name="duplicate_link_dialog_text_1">Anda memiliki kontak tertunda dengan tautan berikut: %s</string>
<string name="duplicate_link_dialog_text_1_contact">Anda sudah memiliki kontak dengan tautan berikut: %s</string>
<!-- This is a question asking whether two nicknames refer to the same person -->
<string name="duplicate_link_dialog_text_2">Apakah %s and %s adalah orang yang sama?</string>
<!-- This is a button for answering that two nicknames do indeed refer to the same person. This
string will be used in a dialog button, so if the translation of this string is longer than 20
characters, please use "Yes" instead, and use "No" for the "Different Person" button -->
<string name="same_person_button">Orang Sama</string>
<!-- This is a button for answering that two nicknames refer to different people. This string
will be used in a dialog button, so if the translation of this string longer than 20 characters,
please use "No" instead, and use "Yes" for the "Same Person" button -->
<string name="different_person_button">Orang Berbeda</string>
<string name="duplicate_link_dialog_text_3">%s dan %s mengirimkan tautan yang sama.\n\nSalah satu dari mereka mungkin sedang mencoba menemukan siapa kontak Anda.\n\nJangan beritahu bahwa Anda menerima tautan sama dari orang lain.</string>
<string name="pending_contact_updated_toast">Menunda pembaruan kontak</string>
<!-- Settings Profile Picture -->
<string name="change_profile_picture">Ketuk untuk mengubah gambar profil Anda</string>
<string name="dialog_confirm_profile_picture_title">Ubah gambar profil Anda</string>
<string name="dialog_confirm_profile_picture_remark">Hanya kontak Anda yang bisa melihat gambar ini</string>
<string name="change_profile_picture_failed_message">Mohon maaf, tetapi ada masalah ketika Anda memutakhirkan gambar profil Anda</string>
<!-- Settings Display -->
<string name="pref_language_title">Bahasa &amp; region</string>
<string name="pref_language_changed">Pengaturan ini akan mempengaruhi ketika Anda memulai ulang Briar. Silakan keluar dan mulai ulang Briar.</string>
<string name="pref_language_default">Bawaan sistem</string>
<string name="display_settings_title">Tampilan</string>
<string name="pref_theme_title">Tema</string>
<string name="pref_theme_light">Terang</string>
<string name="pref_theme_dark">Gelap</string>
<string name="pref_theme_auto">Otomatis (Siang)</string>
<string name="pref_theme_system">Bawaan sistem</string>
<!-- Settings Connections -->
<string name="network_settings_title">Koneksi</string>
<string name="bluetooth_setting">Menyambung kontak lewat Bluetooth</string>
<string name="wifi_setting">Menyambung kontak di Wi-Fi yang Sama</string>
<string name="tor_enable_title">Menyambung kontak lewat Internet</string>
<string name="tor_enable_summary">Semua koneksi melalui jaringan Tor untuk privasi</string>
<string name="tor_network_setting">Metode koneksi untuk jaringan Tor</string>
<string name="tor_network_setting_automatic">Otomatis sesuai lokasi</string>
<string name="tor_network_setting_without_bridges">Gunakan jaringan Tor tanpa jembatan</string>
<string name="tor_network_setting_with_bridges">Gunakan jaringan Tor dengan jembatan</string>
<string name="tor_network_setting_never">Jangan sambungkan ke Internet</string>
<!-- How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)" -->
<string name="tor_network_setting_summary">Otomatis: %1$s (di %2$s)</string>
<string name="tor_mobile_data_title">Gunakan paket data</string>
<string name="tor_only_when_charging_title">Sambungkan ke Internet hanya ketika mengisi daya</string>
<string name="tor_only_when_charging_summary">Nonaktifkan koneksi Internet ketika perangkat menggunakan baterai</string>
<!-- Settings Security and Panic -->
<string name="security_settings_title">Keamanan</string>
<string name="pref_lock_title">Kunci Aplikasi</string>
<string name="pref_lock_summary">Gunakan kunci layar perangkat untuk melindungi Briar ketika masuk</string>
<string name="pref_lock_disabled_summary">untuk menggunakan fitur ini, gunakan kunci layar untuk perangkat Anda</string>
<string name="pref_lock_timeout_title">Waktu ketidakaktifan kunci selesai</string>
<!-- The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour -->
<string name="pref_lock_timeout_summary">Ketika tidak menggunakan Briar, otomatis akan mengunci setelah %s</string>
<!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" -->
<string name="pref_lock_timeout_1">1 menit</string>
<!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" -->
<string name="pref_lock_timeout_5">5 menit</string>
<!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" -->
<string name="pref_lock_timeout_15">15 menit</string>
<!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" -->
<string name="pref_lock_timeout_30">30 menit</string>
<!-- Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s" -->
<string name="pref_lock_timeout_60">1 jama</string>
<string name="pref_lock_timeout_never">Tidak Usah</string>
<string name="pref_lock_timeout_never_summary">Jangan pernah kunci Briar secara otomatis</string>
<string name="change_password">Ubah kata sandi</string>
<string name="current_password">Kata sandi saat ini</string>
<string name="choose_new_password">Kata sandi baru</string>
<string name="confirm_new_password">Konfirmasi kata sandi baru</string>
<string name="password_changed">Kata sandi telah diubah.</string>
<string name="panic_setting">Pengaturan tombol darurat</string>
<string name="panic_setting_title">Tombol darurat</string>
<string name="panic_setting_hint">Konfigurasikan bagaimana Briar akan bereaksi ketika Anda menggunakan aplikasi tombol darurat</string>
<string name="panic_app_setting_title">Aplikasi Tombol Darurat</string>
<string name="unknown_app">aplikasi tidak dikenal</string>
<string name="panic_app_setting_summary">Tidak ada aplikasi yang diatur</string>
<string name="panic_app_setting_none">Tidak Ada</string>
<string name="dialog_title_connect_panic_app">Konfirmasi Aplikasi Darurat</string>
<string name="dialog_message_connect_panic_app">Apakah Anda yakin mengizinkan %1$s untuk memicu tindakan merusak tombol darurat?</string>
<string name="panic_setting_destructive_action">Tindak Merusak</string>
<string name="panic_setting_signout_title">Keluar</string>
<string name="panic_setting_signout_summary">Keluar dari Briar jika tombol darurat ditekan</string>
<string name="purge_setting_title">Hapus Akun</string>
<string name="purge_setting_summary">Hapus akun Briar Anda jika tombol darurat ditekan. Perhatian: Tindakan ini akan menghapus semua identitas, kontak, dan pesan Anda.</string>
<!-- Settings Notifications -->
<string name="notification_settings_title">Notifikasi</string>
<string name="notify_sign_in_title">Ingatkan saya untuk masuk</string>
<string name="notify_sign_in_summary">Tunjukkan pengingat ketika ponsel mulai atau aplikasi telah diperbarui</string>
<string name="notify_private_messages_setting_title">Pesan pribadi</string>
<string name="notify_private_messages_setting_summary">Tunjukkan peringatan pesan pribadi</string>
<string name="notify_private_messages_setting_summary_26">Konfigurasi peringatan pesan pribadi</string>
<string name="notify_group_messages_setting_title">Pesan grup</string>
<string name="notify_group_messages_setting_summary">Tunjukkan peringatan pesan grup</string>
<string name="notify_group_messages_setting_summary_26">Konfigurasi peringatan pesan grup</string>
<string name="notify_forum_posts_setting_title">Unggahan forum</string>
<string name="notify_forum_posts_setting_summary">Tunjukkan peringatan unggahan forum</string>
<string name="notify_forum_posts_setting_summary_26">Konfigurasi peringatan unggahan forum</string>
<string name="notify_blog_posts_setting_title">Unggahan blog</string>
<string name="notify_blog_posts_setting_summary">Tunjukkan peringatan unggahan blog</string>
<string name="notify_blog_posts_setting_summary_26">Konfigurasi peringatan unggahan blog</string>
<string name="notify_vibration_setting">Getar</string>
<string name="notify_sound_setting">Suara</string>
<string name="notify_sound_setting_default">Nada dering bawaan</string>
<string name="notify_sound_setting_disabled">Tidak ada</string>
<string name="choose_ringtone_title">Pilih nada dering</string>
<string name="cannot_load_ringtone">Tidak bisa memuat nada dering</string>
<!-- Settings Feedback -->
<string name="feedback_settings_title">Umpan balik</string>
<string name="send_feedback">Kirim umpan balik</string>
<!-- Crash Reporter -->
<string name="crash_report_title">Laporan Kerusakan Briar</string>
<string name="briar_crashed">Maaf, Briar Rusak.</string>
<string name="not_your_fault">Ini bukan kesalahan Anda.</string>
<string name="please_send_report">Silakan bantu kami untuk membuat Briar lebih baik dengan mengirimkan laporan kerusakan.</string>
<string name="report_is_encrypted">Kami berjanji laporan Anda terenkripsi dan dikirim dengan aman.</string>
<string name="feedback_title">Umpan balik</string>
<string name="describe_crash">Jelaskan apa yang terjadi (pilihan)</string>
<string name="enter_feedback">Masukkan masukan Anda</string>
<string name="optional_contact_email">Surel Anda (pilihan)</string>
<string name="include_debug_report_crash">Sertakan data anonimus kerusakan</string>
<string name="include_debug_report_feedback">Sertakan data anonimus perangkat</string>
<string name="dev_report_basic_info">Informasi dasar</string>
<string name="dev_report_device_info">Informasi perangkat</string>
<string name="dev_report_stacktrace">Jejak tumpukan</string>
<string name="dev_report_time_info">Informasi waktu</string>
<string name="dev_report_memory">Memori</string>
<string name="dev_report_storage">Penyimpanan</string>
<string name="dev_report_connectivity">Konektivitas</string>
<string name="dev_report_build_config">Bua konfigurasi</string>
<string name="dev_report_logcat">Catatan aplikasi</string>
<string name="dev_report_device_features">Fitur Perangkat</string>
<string name="send_report">Kirim laporan</string>
<string name="close">Tutup</string>
<string name="dev_report_sending">Mengirim umpan balik…</string>
<string name="dev_report_sent">Kirim balik terkirim</string>
<string name="dev_report_saved">Laporan tersimpan. Akan dikirim pada saat Anda masuk Briar.</string>
<string name="dev_report_error">Masalah: Pengiriman laporan gagal</string>
<!-- Sign Out -->
<string name="progress_title_logout">Keluar dari Briar…</string>
<!-- Permission Requests -->
<string name="permission_camera_title">Izin Kamera</string>
<string name="permission_camera_request_body">Untuk memindai kode batang, Briar memerlukan akses ke kamera.</string>
<string name="permission_location_title">Izin lokasi</string>
<string name="permission_location_request_body">Untuk menemukan Bluetooth perangkat, Briar memerlukan izin untuk mengakses lokasi Anda.\n\nBriar tidak menyimpan lokasi Anda atau membaginya kepada orang lain.</string>
<string name="permission_camera_location_title">Kamera dan lokasi</string>
<string name="permission_camera_location_request_body">Untuk memindai kode batang, Briar memerlukan akses ke kamera.\n\nUntuk menemukan Bluetooth perangkat, Briar memerlukan izin untuk mengakses lokasi Anda.\n\nBriar tidak menyimpan lokasi Anda atau membaginya kepada orang lain.</string>
<string name="permission_camera_denied_body">Anda sudah menolak akses ke kamera, tetapi menambahkan kontak memerlukan penggunaan kamera.\n\nHarap pertimbangkan memberikan akses.</string>
<string name="permission_location_denied_body">Anda sudah menolak akses ke lokasi, tetapi Briar memerlukan izin tersebut untuk menemukan Bluetooth perangkat. Harap pertimbangkan memberikan akses.</string>
<string name="permission_location_setting_title">Pengaturan Lokasi</string>
<string name="permission_location_setting_body">Pengaturan lokasi perangkat Anda harus diaktifkan untuk menemukan perangkat lain melalui Bluetooth. Harap hidupkan lokasi untuk melanjutkan. Anda bisa mematikan setelahnya.</string>
<string name="permission_location_setting_button">Aktifkan Lokasi</string>
<string name="qr_code">Kode Batang</string>
<string name="show_qr_code_fullscreen">Tunjukkan Kode Batang Tampilan Penuh</string>
<!-- App Locking -->
<string name="lock_unlock">Buka Biar</string>
<string name="lock_unlock_verbose">Masukkan PIN, pola, atau kata sandi untuk membuka perangkat Anda</string>
<string name="lock_unlock_password">Gunakan kata sandi</string>
<string name="lock_is_locked">Briar terkunci</string>
<string name="lock_tap_to_unlock">Ketuk untuk membuka</string>
<!-- Connections Screen -->
<string name="transports_help_text">Briar bisa tersambung dengan kontak Anda lewat Internet, Wi-Fi, Bluetooth.\n\nSemua akses Internet menggunakan jaringan Tor untuk privasi.\n\nJika salah satu kontak tidak bisa dijangkau melalui beberapa cara, Briar akan menggunakannya secara bersamaan.</string>
<!-- Social Backup Feature -->
<!-- Settings -->
<string name="pref_distributed_backup_title">Pencadangan Sosial</string>
<string name="pref_distributed_backup_summary">Cadangkan akun Anda menggunakan kontak tepercaya</string>
<string name="pref_distributed_old_backup_title">Cadangan Sosial yang Ada</string>
<string name="pref_distributed_old_backup_summary">Informasi tentang pencadangan sosial terbaru Anda</string>
<!-- Social backup setup -->
<string name="select_custodians">Pilih Kontak Tepercaya:</string>
<string name="select_at_least_n_contacts">Pilih setidaknya %d kontak</string>
<string name="select_at_least_n_more_contacts">Harap pilih setidaknya %d kontak lagi</string>
<string name="threshold">Pilih angka minimal kontak tepercaya yang diperlukan untuk mengembalikan akun Anda</string>
<string name="threshold_disabled">Dua kontak tepercaya diperlukan untuk mengembalikan akun Anda</string>
<string name="threshold_secure">Aman</string>
<string name="threshold_recommended">Aman - jejak tumpukan direkomendasikan</string>
<string name="threshold_low_insecure">Tidak Aman - jejak tumpukan lebih tinggi direkomendasikan</string>
<string name="threshold_high_insecure">Bahaya kehilangan ambang lebih rendah direkomendasikan</string>
<string name="threshold_defined">Pilih Ambang</string>
<string name="threshold_m_of_n">%d dari %d kontak diperlukan untuk memulihkan akun Anda</string>
<string name="backup_done_info">Data cadangan dikirim ke kontak tepercaya</string>
<!-- Recovery from the secret owner's POV -->
<string name="recovery_explainer">Anda perlu bertemu langsung kontak tepercaya Anda untuk menerima data</string>
<string name="recovery_explainer_extra">Kontak tepercaya Anda harus memindai kode batang untuk memulai pemindahan.\n\nAnda berdua harus tersambung melalui Wi-Fi yang sama</string>
<string name="recovery_begin">Mulai</string>
<string name="recovery_failed_to_receive">Gagal menerima data cadangan</string>
<string name="recovery_helpful_suggestions">Pastikan Anda berdua tersambung Wi-Fi yang sama dan coba lagi</string>
<string name="recovery_retry">Ulangi</string>
<string name="recovery_recovered_shards">Data cadangan dikembalikan:</string>
<string name="recovery_scan_qr_code">Tunjukkan kode batang</string>
<string name="recovery_recovering_account">Memulihkan akun…</string>
<string name="recovery_shard_received">Data cadangan akun diterima</string>
<string name="recovery_account_recovered">Akun dipulihkan</string>
<string name="recovery_account_recovered_explain">Anda harus membuat kata sandi baru untuk akun Anda sekarang</string>
<string name="recovery_sending_ack">Mengirim pernyataan</string>
<!-- Recovery from the custodian's POV -->
<string name="custodian_recovery_explainer">Anda harus bertemu langsung untuk memindahkan data cadangan</string>
<string name="custodian_recovery_explainer_extra">Pastikan Anda berdua tersambung Wi-Fi yang sama, dan pindai ulang kode batang di perangkat kontak Anda untuk mulai memindahkan data cadangan</string>
<string name="custodian_recovery_failed_to_send">Gagal mengirim data cadangan</string>
<string name="custodian_scan_code">Memindai kode</string>
<string name="custodian_shard_sent">Data cadangan akun dipindahkan</string>
<!-- Titles for the app bar -->
<string name="title_distributed_backup">Pencadangan Sosial</string>
<string name="title_select_custodians">Pilih Kontak Tepercaya</string>
<string name="title_define_threshold">Ambang Batas</string>
<string name="title_recovery_mode">Model Pemulihan</string>
<string name="title_help_recover">Bantu memulihkan akun</string>
<!-- Conversation action for custodian -->
<string name="help_recover_account">Bantu mengembalikan akun</string>
<!-- Setup screen -->
<string name="setup_new_account">Buat akun baru</string>
<string name="setup_restore_account">Mengembalikan akun dari cadangan</string>
<!-- Symbols for visualising threshold values for social backup -->
<string name="filled_bullet">\u25CF</string>
<string name="linear_bullet">\u25CB</string>
<!-- Activity names -->
<string name="activity_name_distributed_backup">Pencadangan Sosial</string>
<string name="activity_name_restore_account">Mengembalikan Akun</string>
<!-- Conversation -->
<string name="social_backup_shard_received">%1$s mengirimi Anda data cadangan sosial.</string>
<string name="social_backup_shard_sent">Anda sudah mengirim data cadangan ke %1$s.</string>
<string name="activity_name_new_or_recover_account">Buat akun baru atau pulihkan akun yang ada</string>
<string name="activity_name_recovery">Memulihkan Akun</string>
<string name="activity_name_custodian_help_recovery">Bantu memulihkan akun</string>
<string name="existing_backup_explain">%d kontak berikut diperlukan untuk mengembalikan akun Anda:</string>
<string name="social_backup_not_enough_contacts">Untuk membuat pencadangan sosial, Anda harus memilih minimal 2 kontak dari daftar kontak Anda</string>
<string name="reading_contacts_error">Ada masalah ketika membaca daftar kontak Anda</string>
<!-- Remote Wipe Feature -->
<!-- Setup -->
<string name="remote_wipe_setup_success">Penghapusan jarak jauh diaktifkan</string>
<string name="remote_wipe_setup_failed">Gagal mengaktifkan penghapusan jarak jauh</string>
<string name="remote_wipe_setup_explain_title">Mengaktifkan fungsi penghapusan jarak jauh</string>
<string name="remote_wipe_setup_explain_long">Anda bisa memilih sejumlah kontak tepercaya yang akan bisa mengaktifkan penghapusan jarak jauh semua data Briar Anda.\nPengahpusan jarak jauh bisa diaktifkan oleh salah satu dari dua kontak.</string>
<!-- Settings menu -->
<string name="pref_remote_wipe_summary">Izinkan kontak tepercaya untuk mengaktifkan penghapusan akun jarak jauh</string>
<string name="pref_remote_wipe_title">Penghapusan Jarak Jauh</string>
<!-- Titles for the app bar -->
<string name="title_select_wipers">Pilih Kontak Tepercaya</string>
<!-- Conversation -->
<string name="remote_wipe_setup_received">%1$s telah ditambahkan sebagai penghapus jarak jauh Anda.</string>
<string name="remote_wipe_setup_sent">Anda sudah menambahkan %1$s sebagai penghapus jarak jauh.</string>
<string name="remote_wipe_wipe_sent">Anda sudah mengirim sinyal mengaktifkan penghapusan jarak jauh kepada %1$s. Sudah kedaluwarsa </string>
<string name="activity_name_remote_wipe">Penghapusan Jarak Jauh</string>
<string name="assigned_wipers">Kontak tepercaya yang ditentukan</string>
<string name="activate_remote_wipe">Mengaktifkan penghapusan jarak jauh</string>
<string name="remote_wipe_revoke_sent">Anda sudah menghapus %1$s sebagai penghapus jarak jauh.</string>
<string name="remote_wipe_revoke_received">Anda sudah tidak bisa mengaktifkan penghapusan jarak jauh kepada %1$s.</string>
<!-- Activate -->
<string name="activity_name_activate_remote_wipe">Aktifkan Penghapusan Jarak Jauh</string>
<string name="remote_wipe_activate_success">Sinyal penghapusan jarak terkirim</string>
<string name="remote_wipe_activate_failure">Gagal mengirimkan sinyal penghapusan jarak jauh</string>
<string name="remote_wipe_activate_button_confirm">Mengaktifkan penghapusan jarak jauh</string>
<string name="remote_wipe_activate_button_cancel">Batal</string>
<string name="remote_wipe_activate_explain_short">Mengaktifkan penghapusan jarak jauh kepada %1$s</string>
<string name="remote_wipe_activate_explain_long">Jika dikonfirmasi oleh kontak kedua, mengirim sinyal ini akan menghapus semua data Briar dari perangkat %1$s\.</string>
<!-- Revoke -->
<string name="activity_name_revoke_remote_wipe">Cabut Penghapusan Jarak Jauh</string>
<string name="revoke_remote_wipe">Cabut Penghapusan Status Jarak Jauh</string>
<string name="remote_wipe_revoke_success">Penghapusan Status Jarak Jauh Tercabut</string>
<string name="remote_wipe_modify_contacts">Ubah Penghapus Jarak Jauh</string>
<string name="button_confirm">Oke</string>
</resources>

View File

@@ -32,6 +32,7 @@
<item>he</item>
<item>hi</item>
<item>hu</item>
<item>in</item>
<item>is</item>
<item>it</item>
<item>ja</item>

View File

@@ -641,20 +641,17 @@
<!-- This is a message to be used in screenshots. -->
<string name="screenshot_message_3">No problem, hope you like it 😀</string>
<!-- social backup -->
<!-- settings -->
<!-- Social Backup Feature -->
<!-- Settings -->
<string name="pref_distributed_backup_title">Social backup</string>
<string name="pref_distributed_backup_summary">Backup your account using trusted contacts</string>
<string name="pref_distributed_old_backup_title">Existing Social backup</string>
<string name="pref_distributed_old_backup_summary">Information about your most recent social backup</string>
<!-- social backup procedure -->
<!-- Social backup setup -->
<string name="select_custodians">Select Trusted Contacts</string>
<string name="select_at_least_n_contacts">Please select at least %d contacts</string>
<string name="select_at_least_n_more_contacts">Please select at least %d more contacts</string>
<string name="select_no_more_than_n_contacts">Too many! Please select no more than %d contacts</string>
@@ -668,6 +665,8 @@
<string name="threshold_defined">Choose Minimum Needed</string>
<string name="threshold_m_of_n">%d of %d contacts needed to recover your account</string>
<!-- Recovery from the secret owner's POV -->
<string name="backup_created">Social Backup created</string>
<string name="backup_done_info">Backup pieces sent to trusted contacts</string>
@@ -694,36 +693,34 @@
<string name="recovery_account_recovered_explain">You must now set a new password for your account</string>
<string name="recovery_sending_ack">Sending acknowledgement</string>
<!-- recovery from the custodian's POV -->
<!-- Recovery from the custodian's POV -->
<string name="custodian_recovery_explainer">You need to meet in-person to transfer backup piece</string>
<string name="custodian_recovery_explainer_extra">Make sure you are both connected to the same wifi network, and scan the QR code on your contact\'s device to begin transferring the backup piece</string>
<string name="custodian_recovery_failed_to_send">Failed to send backup piece</string>
<string name="custodian_scan_code">Scan code</string>
<string name="custodian_shard_sent">Account backup piece transmitted</string>
<!-- titles for the app bar -->
<!-- Titles for the app bar -->
<string name="title_distributed_backup">Social Backup</string>
<string name="title_select_custodians">Select Trusted Contacts</string>
<string name="title_define_threshold">Minimum Needed</string>
<string name="title_recovery_mode">Recovery Mode</string>
<string name="title_help_recover">Help recover account</string>
<!-- conversation action for custodian -->
<!-- Conversation action for custodian -->
<string name="help_recover_account">Help recover account</string>
<!-- setup screen -->
<!-- Setup screen -->
<string name="setup_new_account">Create new account</string>
<string name="setup_restore_account">Restore account from backup</string>
<!-- activity names -->
<!-- Activity names -->
<string name="activity_name_distributed_backup">Social Backup</string>
<string name="activity_name_restore_account">Restore Account</string>
<!-- conversation -->
<!-- Conversation -->
<string name="social_backup_shard_received">%1$s has sent you a social backup piece.</string>
<string name="social_backup_shard_sent">You have sent a social backup piece to %1$s.</string>
@@ -736,5 +733,55 @@
<string name="reading_contacts_error">There was an error reading your contacts list</string>
<!-- Display existing backup -->
<string name="social_backup_trusted_contacts">Trusted Contacts</string>
<!-- Remote Wipe Feature -->
<!-- Setup -->
<string name="remote_wipe_setup_success">Remote wipe is set up</string>
<string name="remote_wipe_setup_failed">Failed to set up remote wipe</string>
<string name="remote_wipe_setup_explain_title">Setup remote wipe function</string>
<string name="remote_wipe_setup_explain_long">You can choose a set of trusted contacts who are able to activate a remote wipe of all Briar data.\nThe wipe may be activated by any two contacts from the set.</string>
<string name="remote_wipe_display_explain">Any two of these trusted contacts may activate a wipe of all Briar data from your device.</string>
<!-- Settings menu -->
<string name="pref_remote_wipe_summary">Allow trusted contacts to activate an account wipe remotely</string>
<string name="pref_remote_wipe_title">Remote Wipe</string>
<!-- Titles for the app bar -->
<string name="title_select_wipers">Select Trusted Contacts</string>
<!-- Conversation -->
<string name="remote_wipe_setup_received">%1$s has added you as a remote wiper.</string>
<string name="remote_wipe_setup_sent">You have added %1$s as a remote wiper.</string>
<string name="remote_wipe_wipe_sent">You have sent an activate remote wipe signal to %1$s. It expires </string>
<string name="activity_name_remote_wipe">Remote Wipe</string>
<string name="assigned_wipers">Your assigned trusted wipers</string>
<string name="activate_remote_wipe">Activate remote wipe</string>
<string name="remote_wipe_revoke_sent">You have removed %1$s as a remote wiper.</string>
<string name="remote_wipe_revoke_received">You can no longer activate a remote wipe for %1$s.</string>
<!-- Activate -->
<string name="activity_name_activate_remote_wipe">Activate Remote Wipe</string>
<string name="remote_wipe_activate_success">Remote wipe signal sent</string>
<string name="remote_wipe_activate_failure">Failed to send remote wipe signal</string>
<string name="remote_wipe_activate_button_confirm">Activate remote wipe</string>
<string name="remote_wipe_activate_button_cancel">Cancel</string>
<string name="remote_wipe_activate_explain_short">Activate a remote wipe for %1$s</string>
<string name="remote_wipe_activate_explain_long">If confirmed by a second contact, sending this signal will remove all Briar data from %1$s\'s device.</string>
<!-- Revoke -->
<string name="activity_name_revoke_remote_wipe">Revoke Remote Wipe</string>
<string name="revoke_remote_wipe">Revoke remote wipe status</string>
<string name="remote_wipe_revoke_success">Remote wipe status revoked</string>
<string name="remote_wipe_modify_contacts">Change remote wipers</string>
<string name="remote_wipe_disable">Disable remote wipe</string>
<string name="remote_wipe_disable_success">Remote wipe is disabled</string>
<string name="remote_wipe_disable_success_explain">None of your contacts are able to activate a wipe.</string>
<string name="remote_wipe_confirm_received">Briar data has been wiped from %1$s\'s device. They will be unreachable until they recover their account.</string>
<string name="button_confirm">Ok</string>
</resources>

View File

@@ -65,6 +65,12 @@
<item name="android:minWidth">@dimen/button_size</item>
</style>
<style name="BriarButtonFlat.Negative.Tiny" parent="BriarButtonFlat.Negative">
<item name="android:textSize">@dimen/text_size_tiny</item>
<item name="android:padding">@dimen/margin_medium</item>
<item name="android:minWidth">@dimen/button_size</item>
</style>
<style name="Divider">
<item name="android:background">@color/divider</item>
</style>

View File

@@ -101,6 +101,17 @@
</Preference>
<Preference
android:summary="@string/pref_remote_wipe_summary"
android:title="@string/pref_remote_wipe_title"
app:iconSpaceReserved="false">
<intent
android:targetClass="org.briarproject.briar.android.remotewipe.RemoteWipeSetupActivity"
android:targetPackage="@string/app_package" />
</Preference>
<SwitchPreference
android:enabled="false"
android:key="pref_key_lock"

View File

@@ -67,36 +67,36 @@ dependencyVerification {
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
'classworlds:classworlds:1.1-alpha-2:classworlds-1.1-alpha-2.jar:2bf4e59f3acd106fea6145a9a88fe8956509f8b9c0fdd11eb96fee757269e3f3',
'com.almworks.sqlite4java:sqlite4java:0.282:sqlite4java-0.282.jar:9e1d8dd83ca6003f841e3af878ce2dc7c22497493a7bb6d1b62ec1b0d0a83c05',
'com.android.tools.analytics-library:protos:27.1.1:protos-27.1.1.jar:13f77e73762e58ab372d140b3a6be6903aea9775b62dd14fbc62d4cc7069c9a4',
'com.android.tools.analytics-library:shared:27.1.1:shared-27.1.1.jar:82930a52001410e97d809930b670f4de3002286975f046b9de5f6b777b06d366',
'com.android.tools.analytics-library:tracker:27.1.1:tracker-27.1.1.jar:31bc5a00be0055bac89c9b2f34751883e987cd89e3ac1783720645c164f591d9',
'com.android.tools.analytics-library:protos:27.2.2:protos-27.2.2.jar:02482564443c294dfe87c5f2b25387f724a698a09ed58e0cf0127400caa35a19',
'com.android.tools.analytics-library:shared:27.2.2:shared-27.2.2.jar:0efe017ca17ee775c5af386475a09799a1282faa04821d54810c1a34f6348d9c',
'com.android.tools.analytics-library:tracker:27.2.2:tracker-27.2.2.jar:62489d84192dc06219664945c43201654ff85c3b715f46550751512a880d0e39',
'com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524:aapt2-proto-4.1.0-alpha01-6193524.jar:17e75523e1e92dd4f222c7368ee41df9e964a508232f591e265d0c499baf9dca',
'com.android.tools.build:apksig:4.1.1:apksig-4.1.1.jar:e0a69da9e5a03986d608b45bbf954ef0e6a0b3f58c1b8315bd169ec08b279e72',
'com.android.tools.build:apkzlib:4.1.1:apkzlib-4.1.1.jar:ba4b5e419b6be0130eae7f8301c3a551ad3976f487d2e0c6852ebb175ac41127',
'com.android.tools.build:builder-model:4.1.1:builder-model-4.1.1.jar:e95c99cc298ad67b8deb6ced99c51abc8f59afebedad044b1a10dde14646a4dd',
'com.android.tools.build:builder-test-api:4.1.1:builder-test-api-4.1.1.jar:464f596ab261c051c3847406748e843770dea123f6fa5fee8a9390644e709b7a',
'com.android.tools.build:builder:4.1.1:builder-4.1.1.jar:0f78d4759d2f7b57b95865522ec34596ba419b9982f3b25e3449213f9c98b80d',
'com.android.tools.build:gradle-api:4.1.1:gradle-api-4.1.1.jar:d42e6b539e4c1353ad3546e75ec8ce11a017b97481023e8ea18577eefe374358',
'com.android.tools.build:manifest-merger:27.1.1:manifest-merger-27.1.1.jar:7a45fa143687859bb2e5a961dcf6ee88094d3853de0cb543dc03dbcb0f4b554b',
'com.android.tools.ddms:ddmlib:27.1.1:ddmlib-27.1.1.jar:da6e4bd834b6a85dae8019039849d8bd96933347dfbf460df74913ddade6e40a',
'com.android.tools.external.com-intellij:intellij-core:27.1.1:intellij-core-27.1.1.jar:2591a7363c4443c59bf9f793730acafce9d6ec3076e2f46716edaf53a41b6fb6',
'com.android.tools.external.com-intellij:kotlin-compiler:27.1.1:kotlin-compiler-27.1.1.jar:5054ae770ba788f110303c65abd6b1fa28eccf52dee1274510e201b2b81885c8',
'com.android.tools.external.org-jetbrains:uast:27.1.1:uast-27.1.1.jar:54cd8f6886a9d2f5641659dd5c91f626629672cd48301f7f0bd6aad9bd448714',
'com.android.tools.layoutlib:layoutlib-api:27.1.1:layoutlib-api-27.1.1.jar:8a9a22e3b309521ea83b724e5a89cfdac6076f52d675c0e17d77b05527bc0f8c',
'com.android.tools.lint:lint-api:27.1.1:lint-api-27.1.1.jar:c1d8176094cb0478786070d40533efb578ebc53529a82f6ef5bee879bdca418b',
'com.android.tools.lint:lint-checks:27.1.1:lint-checks-27.1.1.jar:3899c91e00bd059b40c31a9ca00cd0f8303191947608735ae1b657323693fb61',
'com.android.tools.lint:lint-gradle-api:27.1.1:lint-gradle-api-27.1.1.jar:26aa89d38b9825cc73229daa82a68875801c8b8491f30497ce62aff1f206eb0d',
'com.android.tools.lint:lint-gradle:27.1.1:lint-gradle-27.1.1.jar:f7355823ead869f4d28184ba28b7a0c693b507519a2d3705bb9848a0f35b3756',
'com.android.tools.lint:lint-model:27.1.1:lint-model-27.1.1.jar:bc23c0c413bdfca59dac2cd56b870d8360d009e9ec0d365e71f774bcf127971d',
'com.android.tools.lint:lint:27.1.1:lint-27.1.1.jar:2f6038a5398a42bd591883c3f5e5894f4ec52ca1c3683bf94fa8553c1700af81',
'com.android.tools:annotations:27.1.1:annotations-27.1.1.jar:ff28c504d2acb9fd1a5ffbd97ae85cf59ee18c76927525aad250509bccf2cab1',
'com.android.tools:common:27.1.1:common-27.1.1.jar:63d9a2a9ad6d278db319f3749b9f50bdf5457ef7020074a1bebe124e714b535c',
'com.android.tools:dvlib:27.1.1:dvlib-27.1.1.jar:998a54201fc1cefee5f2399215e95c42b1f64f9e1d8f4452eb8255c68ba5440f',
'com.android.tools:repository:27.1.1:repository-27.1.1.jar:d25b74ccabf4d876903efb375e9af6fb380d8ae0445bb74bbdcc225c1e37fa1d',
'com.android.tools:sdk-common:27.1.1:sdk-common-27.1.1.jar:4473ae97d0ef7061ee1de61041d5aa97405ae08e44c09cf7bb278b42e4b97c7c',
'com.android.tools:sdklib:27.1.1:sdklib-27.1.1.jar:08e6b83961ac9724b3c1e3d0eff971f13be6701292c77914b8794480f3391250',
'com.android:signflinger:4.1.1:signflinger-4.1.1.jar:0c66825988873ec2d51057fa463f54a8f18fc7326ff4530b9da363b71e97ce60',
'com.android:zipflinger:4.1.1:zipflinger-4.1.1.jar:0a8c3e52ac13dd031236f9fb5ba4408b1d5dcd12325a05440b36da09d8881446',
'com.android.tools.build:apksig:4.2.2:apksig-4.2.2.jar:632690bf641b429dcb31650e6b2f6a2e87c4ac8afd45a6ba3cbc99fb1612178f',
'com.android.tools.build:apkzlib:4.2.2:apkzlib-4.2.2.jar:3b5167c1265e97f65201c4d2be6a6f72165a3aa2fe9e0594a59b67af9e9e97b9',
'com.android.tools.build:builder-model:4.2.2:builder-model-4.2.2.jar:41868de0cb88ae70b828eee4191c13e0233f433abb1becdf6a2bd391bd446bc0',
'com.android.tools.build:builder-test-api:4.2.2:builder-test-api-4.2.2.jar:2f305c6d3a7b637d736b821bad372dcabd959e979f2065a9f65bac1e7b4d1875',
'com.android.tools.build:builder:4.2.2:builder-4.2.2.jar:40fedd0d16db8f34ddb4eaf812d966b90ef1764f65cf119030442823bcf995cd',
'com.android.tools.build:gradle-api:4.2.2:gradle-api-4.2.2.jar:dd4ef35bbbfb8fc2d20e3311c76b516bc1672e82b61cb3a59fc877da0f9b4f61',
'com.android.tools.build:manifest-merger:27.2.2:manifest-merger-27.2.2.jar:971974756f32d9e94c857d92772b1499b0b0f5d9c70cb8ebbd20d9bbf804a923',
'com.android.tools.ddms:ddmlib:27.2.2:ddmlib-27.2.2.jar:9ab0f9b58737c316af454184705854c75936ca3531f21acc29bd68a3343334d1',
'com.android.tools.external.com-intellij:intellij-core:27.2.2:intellij-core-27.2.2.jar:01619d5dc28ec909cbdee699f1f13056e84462faf6dccf4817561293fb28bef0',
'com.android.tools.external.com-intellij:kotlin-compiler:27.2.2:kotlin-compiler-27.2.2.jar:71bd460199ce7293ecc54b91a115319c1e4b585eca5a5b3699f6a406f29e626c',
'com.android.tools.external.org-jetbrains:uast:27.2.2:uast-27.2.2.jar:efa59302fd433015e993143530cecb456b63d10d0b89bd1d3b1a016904338a65',
'com.android.tools.layoutlib:layoutlib-api:27.2.2:layoutlib-api-27.2.2.jar:f0901f2295d814e82ad95850ea2103dd89d8489e01727fafa55ccccc0dccd163',
'com.android.tools.lint:lint-api:27.2.2:lint-api-27.2.2.jar:1ecb5959c8e624ee49cdf9178de67bb0e823b4382ed253410eb36afe5c458b05',
'com.android.tools.lint:lint-checks:27.2.2:lint-checks-27.2.2.jar:989e545a6b5e398e63a9f3608da02d6111f2241faec1baa0a3b4492cb03aeaf2',
'com.android.tools.lint:lint-gradle-api:27.2.2:lint-gradle-api-27.2.2.jar:2be9c69d6fbbfb012ff6521fdfcb22eb7cfaa57d108e07bb1d4143dae9c1b433',
'com.android.tools.lint:lint-gradle:27.2.2:lint-gradle-27.2.2.jar:742dedd5ccb459a245a35bf4fa16dfecc762da1a6b1741332cfe5228e812301a',
'com.android.tools.lint:lint-model:27.2.2:lint-model-27.2.2.jar:ee31012586462bea2d591b6175934e5f29b6f781a78fda50f79387972364b9ab',
'com.android.tools.lint:lint:27.2.2:lint-27.2.2.jar:7247016af7fba8cabee6ae887515b144f5a2ff7823422654daf23be9202f8fb1',
'com.android.tools:annotations:27.2.2:annotations-27.2.2.jar:9375fb2df5c0cf1b46fef9e65b3a27ac88925ccf90054b19ae0ca0adc7036fe1',
'com.android.tools:common:27.2.2:common-27.2.2.jar:a76f4e10cad39bed317be031fee915d280aa8bc11616c58ab94e051b1e38769d',
'com.android.tools:dvlib:27.2.2:dvlib-27.2.2.jar:9931c6b57460b5f8cc2613ca5ff8596aa089a67655ace13d173f90538ecb4301',
'com.android.tools:repository:27.2.2:repository-27.2.2.jar:ac5f9b19dc5d9d08e80b57da76059f5760ca76c221e40ffd4bf43d7b13991674',
'com.android.tools:sdk-common:27.2.2:sdk-common-27.2.2.jar:b147acc13850808d61fc391ccfeeebdf90841b461a7042acb2d92e466da8e674',
'com.android.tools:sdklib:27.2.2:sdklib-27.2.2.jar:fae0bafbe8b4f546cf64986a22b7d8ed108d45519366ff22f0170a9cf3ea7f34',
'com.android:signflinger:4.2.2:signflinger-4.2.2.jar:4d7aafd9666707b483b1ad2c466824287cf2e379dda1d204dd3b7e453ffcf760',
'com.android:zipflinger:4.2.2:zipflinger-4.2.2.jar:8e4677086c9a8f4a67374a4edc31db7e481f0d9b85907263c51ca72452c23a93',
'com.github.bumptech.glide:annotations:4.11.0:annotations-4.11.0.jar:d219d238006d824962176229d4708abcdddcfe342c6a18a5d0fa48d6f0479b3e',
'com.github.bumptech.glide:compiler:4.11.0:compiler-4.11.0.jar:a98cdf265c36261b1d523448b05c322ec290afa865946425eded6361980e8770',
'com.github.bumptech.glide:gifdecoder:4.11.0:gifdecoder-4.11.0.aar:197a1cd5b76855aa02b230c13974e293229b901dc2b96fab4315201e78baa804',
@@ -110,7 +110,6 @@ dependencyVerification {
'com.google.auto:auto-common:0.8:auto-common-0.8.jar:97db1709f57b91b32edacb596ef4641872f227b7d99ad90e467f0d77f5ba134a',
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.code.gson:gson:2.8.6:gson-2.8.6.jar:c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a',
@@ -136,13 +135,12 @@ dependencyVerification {
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.ibm.icu:icu4j:53.1:icu4j-53.1.jar:e37a4467bac5cdeb02c5c4b8e5063d2f4e67b69e3c7df6d6b610f13185572bab',
'com.jraska:falcon:2.1.1:falcon-2.1.1.aar:827f06556b7fa599f29a48a5277df39ca3dce5080d4ea6f9ea1f9c7b6b78bb7a',
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.1.1:javawriter-2.1.1.jar:f699823d0081f69cbb676c1845ea222e0ada79bc88a53e5d22d8bd02d328f57e',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:3.0.7:istack-commons-runtime-3.0.7.jar:6443e10ba2e259fb821d9b6becf10db5316285fc30c53cec9d7b19a3877e7fdf',
'com.sun.xml.fastinfoset:FastInfoset:1.2.15:FastInfoset-1.2.15.jar:785861db11ca1bd0d1956682b974ad73eb19cd3e01a4b3fa82d62eca97210aec',
'com.sun.istack:istack-commons-runtime:3.0.8:istack-commons-runtime-3.0.8.jar:4ffabb06be454a05e4398e20c77fa2b6308d4b88dfbef7ca30a76b5b7d5505ef',
'com.sun.xml.fastinfoset:FastInfoset:1.2.16:FastInfoset-1.2.16.jar:056f3a1e144409f21ed16afc26805f58e9a21f3fce1543c42d400719d250c511',
'com.vanniktech:emoji-google:0.6.0:emoji-google-0.6.0.aar:029d6a954cebfe3f0a5bac0c9539a054fa7db2e1272d006a8f0e850f3794d44b',
'com.vanniktech:emoji:0.6.0:emoji-0.6.0.aar:a5fcde58902305c004f03c6dc2241e718400ac4162226079791d87fac83ef639',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
@@ -150,12 +148,12 @@ dependencyVerification {
'de.hdodenhof:circleimageview:3.0.1:circleimageview-3.0.1.aar:7b0f088436ad4dcbb36d779fd09bf2192d9cc1e1a734bb6337904a7648f97617',
'info.guardianproject.panic:panic:1.0:panic-1.0.jar:35116ab95212e67f94577faf67b88c11a6b21cbf9178b3f5b51d3dff45203ffd',
'info.guardianproject.trustedintents:trustedintents:0.2:trustedintents-0.2.jar:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.activation:javax.activation-api:1.2.0:javax.activation-api-1.2.0.jar:43fdef0b5b6ceb31b0424b208b930c74ab58fac2ceeb7b3f6fd3aeb8b5ca4393',
'it.unimi.dsi:fastutil:8.4.0:fastutil-8.4.0.jar:2ad2824a4a0a0eb836b52ee2fc84ba2134f44bce7bfa54015ae3f31c710a3071',
'jakarta.activation:jakarta.activation-api:1.2.1:jakarta.activation-api-1.2.1.jar:8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b',
'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2:jakarta.xml.bind-api-2.3.2.jar:69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea',
'javax.annotation:javax.annotation-api:1.3.2:javax.annotation-api-1.3.2.jar:e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.3.1:jaxb-api-2.3.1.jar:88b955a0df57880a26a74708bc34f74dcaf8ebf4e78843a28b50eae945732b06',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'junit:junit:4.13.1:junit-4.13.1.jar:c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122',
'nekohtml:nekohtml:1.9.6.2:nekohtml-1.9.6.2.jar:fdff6cfa9ed9cc911c842a5d2395f209ec621ef1239d46810e9e495809d3ae09',
@@ -163,7 +161,9 @@ dependencyVerification {
'net.bytebuddy:byte-buddy-agent:1.10.20:byte-buddy-agent-1.10.20.jar:b592a6c43e752bf41659717956c57fbb790394d2ee5f8941876659f9c5c0e7e8',
'net.bytebuddy:byte-buddy:1.10.20:byte-buddy-1.10.20.jar:5fcad05da791e9a22811c255a4a74b7ea094b7243d9dbf3e6fc578c8c94290ac',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'net.java.dev.jna:jna-platform:5.6.0:jna-platform-5.6.0.jar:9ecea8bf2b1b39963939d18b70464eef60c508fed8820f9dcaba0c35518eabf7',
'net.java.dev.jna:jna:5.5.0:jna-5.5.0.aar:12ef4a3c2ea685c9c816caa6a77ae8f17bb7727d8460f249925409acda270101',
'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf',
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
@@ -190,8 +190,8 @@ dependencyVerification {
'org.apache.maven:maven-repository-metadata:2.2.1:maven-repository-metadata-2.2.1.jar:5fe283f47b0e7f7d95a4252af3fa7a0db4d8f080cd9df308608c0472b8f168a1',
'org.apache.maven:maven-settings:2.2.1:maven-settings-2.2.1.jar:9a9f556713a404e770c9dbdaed7eb086078014c989291960c76fdde6db4192f7',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.52:bcprov-jdk15on-1.52.jar:0dc4d181e4d347893c2ddbd2e6cd5d7287fc651c03648fa64b2341c7366b1773',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.bouncycastle:bcprov-jdk15on:1.65:bcprov-jdk15on-1.65.jar:e78f96eb59066c94c94fb2d6b5eb80f52feac6f5f9776898634f8addec6e2137',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
@@ -202,31 +202,31 @@ dependencyVerification {
'org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1:plexus-container-default-1.0-alpha-9-stable-1.jar:7c758612888782ccfe376823aee7cdcc7e0cdafb097f7ef50295a0b0c3a16edf',
'org.codehaus.plexus:plexus-interpolation:1.11:plexus-interpolation-1.11.jar:fd9507feb858fa620d1b4aa4b7039fdea1a77e09d3fd28cfbddfff468d9d8c28',
'org.codehaus.plexus:plexus-utils:1.5.15:plexus-utils-1.5.15.jar:2ca121831e597b4d8f2cb22d17c5c041fc23a7777ceb6bfbdd4dfb34bbe7d997',
'org.glassfish.jaxb:jaxb-runtime:2.3.1:jaxb-runtime-2.3.1.jar:45fecfa5c8217ce1f3652ab95179790ec8cc0dec0384bca51cbeb94a293d9f2f',
'org.glassfish.jaxb:txw2:2.3.1:txw2-2.3.1.jar:34975dde1c6920f1a39791142235689bc3cd357e24d05edd8ff93b885bd68d60',
'org.glassfish.jaxb:jaxb-runtime:2.3.2:jaxb-runtime-2.3.2.jar:e6e0a1e89fb6ff786279e6a0082d5cef52dc2ebe67053d041800737652b4fd1b',
'org.glassfish.jaxb:txw2:2.3.2:txw2-2.3.2.jar:4a6a9f483388d461b81aa9a28c685b8b74c0597993bf1884b04eddbca95f48fe',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
'org.hamcrest:hamcrest-integration:1.3:hamcrest-integration-1.3.jar:70f418efbb506c5155da5f9a5a33262ea08a9e4d7fea186aa9015c41a7224ac2',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
'org.jetbrains.kotlin:kotlin-reflect:1.3.72:kotlin-reflect-1.3.72.jar:a188d9367de1c4ee9479db630985c0597b20709c83161b1430d24edb27e38c40',
'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601',
'org.jetbrains.kotlin:kotlin-reflect:1.4.31:kotlin-reflect-1.4.31.jar:91fad0b42974a7d5811e30a61f05706e176b144235717c6de7e81e3a781028f2',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72:kotlin-stdlib-common-1.3.72.jar:5e7d1552863e480c1628b1cc39ce230ef829f5b7230106215a05acda5172203a',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72:kotlin-stdlib-jdk7-1.3.72.jar:40566c0c08d414b9413ba556ff7f8a0b04b98b9f0f424d122dd2088510efccc4',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72:kotlin-stdlib-jdk8-1.3.72.jar:133da70cfc07b56094282eac5c59bccd59f167ee2ead22e5282876d8bc10bf95',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31:kotlin-stdlib-common-1.4.31.jar:57962f44371a746b678218a0802a8712c6255206de9a69ede215e3aa4b044708',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31:kotlin-stdlib-jdk7-1.4.31.jar:1f966e54e86cf4b7d7014afdce04e0f3ee4625084cda3494edccc7b84af52664',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31:kotlin-stdlib-jdk8-1.4.31.jar:b2f8364435ebcb0106ff9d4415a11ffdef8ec7786ee6e5ed465a01556cbd1683',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.72:kotlin-stdlib-1.3.72.jar:3856a7349ebacd6d1be6802b2fed9c4dc2c5a564ea92b6b945ac988243d4b16b',
'org.jetbrains.kotlin:kotlin-stdlib:1.4.31:kotlin-stdlib-1.4.31.jar:76a599d88b167e8ac90879b6daa722c6ad3452ba714c9aba19bd196544b97f1c',
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0:kotlinx-coroutines-android-1.3.0.jar:c80aaadf041f044d324a19a73f88879dfd1e4d026b14e3230075ff9081942ae3',
'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0:kotlinx-coroutines-core-1.3.0.jar:6f3a60fea2403b80385b399952aeb3a4cf0985a45b8da04b6f31825171901a1d',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b',
'org.jmock:jmock-legacy:2.12.0:jmock-legacy-2.12.0.jar:dea3a9cca653d082e2fe7e40232e982fe03a9984c7d67ceff24f3e03fe580dcd',
'org.jmock:jmock-testjar:2.12.0:jmock-testjar-2.12.0.jar:efefbcf6cd294d0e29f0c46eb2a3380d4ca4e1763ff719c69e2f2ac62f564a04',
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
'org.jvnet.staxex:stax-ex:1.8:stax-ex-1.8.jar:95b05d9590af4154c6513b9c5dc1fb2e55b539972ba0a9ef28e9a0c01d83ad77',
'org.jvnet.staxex:stax-ex:1.8.1:stax-ex-1.8.1.jar:20522549056e9e50aa35ef0b445a2e47a53d06be0b0a9467d704e2483ffb049a',
'org.magmacollective.darkcrystal:dark-crystal-key-backup-crypto:1.0.0:dark-crystal-key-backup-crypto-1.0.0.jar:7c808f30314f7bc0c715b53415b07bd7e9a6bbcc55e5f672a296e5298d335f78',
'org.magmacollective.darkcrystal:dark-crystal-secret-sharing-wrapper:1.1.0:dark-crystal-secret-sharing-wrapper-1.1.0.aar:b8cac2348b9e652de413fa587168e9bb6ff36f6eea4bd1c72d3ecd56fc186e09',
'org.magmacollective.darkcrystal:shamir-secret-sharing-jna:1.0.0:shamir-secret-sharing-jna-1.0.0.aar:cdccfaf74dc1fcf30799a45d034c406315ce8507a8f4382eee118a66fb229ced',
@@ -252,5 +252,7 @@ dependencyVerification {
'org.whispersystems:curve25519-java:0.5.0:curve25519-java-0.5.0.jar:0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d',
'tools.fastlane:screengrab:2.0.0:screengrab-2.0.0.aar:15ac15eb7c371db05e721be8d466567c2b7274b767d91478e781b6d89ee5d3d0',
'uk.co.samuelwall:material-tap-target-prompt:3.0.0:material-tap-target-prompt-3.0.0.aar:e4d3c472b2d378e39a6535b7788e6c790fc9dde2d7659974e006ed8c7260911d',
'xerces:xercesImpl:2.12.0:xercesImpl-2.12.0.jar:b50d3a4ca502faa4d1c838acb8aa9480446953421f7327e338c5dda3da5e76d0',
'xml-apis:xml-apis:1.4.01:xml-apis-1.4.01.jar:a840968176645684bb01aed376e067ab39614885f9eee44abe35a5f20ebe7fad',
]
}

View File

@@ -10,6 +10,7 @@ import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader;
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
@NotNullByDefault
@@ -34,4 +35,6 @@ public interface ConversationMessageVisitor<T> {
T visitIntroductionResponse(IntroductionResponse r);
T visitShardMessage(ShardMessageHeader r);
T visitRemoteWipeMessage(RemoteWipeMessageHeader r);
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.briar.api.remotewipe;
public interface MessageEncoder {
byte[] encodeSetupMessage();
byte[] encodeRevokeMessage();
byte[] encodeWipeMessage();
byte[] encodeConfirmMessage();
}

View File

@@ -0,0 +1,12 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfList;
public interface MessageParser {
void parseSetupMessage(BdfList body) throws FormatException;
void parseWipeMessage(BdfList body) throws FormatException;
void parseRevokeMessage(BdfList body) throws FormatException;
}

View File

@@ -0,0 +1,29 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public enum MessageType {
SETUP(0), WIPE(1), REVOKE(2), CONFIRM(3);
private final int value;
MessageType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MessageType fromValue(int value) throws
FormatException {
for (MessageType m : values()) if (m.value == value) return m;
throw new FormatException();
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event which is activated when a critical amount of
* remote wipe messages are received.
*/
@Immutable
@NotNullByDefault
public class RemoteWipeActivatedEvent extends Event {
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.briar.api.remotewipe;
public interface RemoteWipeConstants {
int THRESHOLD = 2;
long MAX_MESSAGE_AGE = 24 * 60 * 60 * 1000;
// Group metadata keys
String GROUP_KEY_CONTACT_ID = "contactId";
String GROUP_KEY_WIPERS = "wipers";
String GROUP_KEY_RECEIVED_WIPE = "receivedWipe";
String GROUP_KEY_AM_WIPER = "amWiper";
// Message metadata keys
String MSG_KEY_TIMESTAMP = "timestamp";
String MSG_KEY_MESSAGE_TYPE = "messageType";
String MSG_KEY_LOCAL = "local";
}

View File

@@ -0,0 +1,71 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask;
import java.text.Normalizer;
import java.util.Collection;
import java.util.List;
@NotNullByDefault
public interface RemoteWipeManager extends ConversationManager.ConversationClient {
interface Observer {
void onPanic();
}
/**
* The unique ID of the remote wipe client.
*/
ClientId CLIENT_ID = new ClientId("pw.darkcrystal.remotewipe");
/**
* The current major version of the remote wipe client.
*/
int MAJOR_VERSION = 0;
/**
* The current minor version of the remote wipe client.
*/
int MINOR_VERSION = 0;
void listenForPanic(Observer observer);
void setup(Transaction txn, List<ContactId> wipers)
throws DbException, FormatException;
void wipe(Transaction txn, Contact contact)
throws DbException, FormatException;
boolean amWiper(Transaction txn, ContactId contactId);
boolean isWiper(Transaction txn, ContactId contactId);
void revoke(Transaction txn, ContactId contactId)
throws DbException, FormatException;
void revokeAll(Transaction txn) throws DbException, FormatException;
boolean remoteWipeIsSetup(Transaction txn);
List<Author> getWipers(Transaction txn) throws DbException;
List<ContactId> getWiperContactIds(Transaction txn);
int sendConfirmMessages(Transaction txn) throws DbException,
FormatException;
@Override
Collection<ConversationMessageHeader> getMessageHeaders(
Transaction txn, ContactId contactId) throws DbException;
}

View File

@@ -0,0 +1,45 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.attachment.AttachmentHeader;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.ConversationMessageVisitor;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class RemoteWipeMessageHeader extends ConversationMessageHeader {
private final List<AttachmentHeader> attachmentHeaders;
private final MessageType type;
public RemoteWipeMessageHeader(MessageId id, GroupId groupId, long timestamp,
boolean local, boolean read, boolean sent, boolean seen,
List<AttachmentHeader> headers, MessageType type) {
super(id, groupId, timestamp, local, read, sent, seen);
this.attachmentHeaders = headers;
this.type = type;
}
public List<AttachmentHeader> getAttachmentHeaders() {
return attachmentHeaders;
}
public MessageType getMessageType() {
return type;
}
public long getMessageExpiry() {
return (getTimestamp() + RemoteWipeConstants.MAX_MESSAGE_AGE);
}
@Override
public <T> T accept(ConversationMessageVisitor<T> v) {
return v.visitRemoteWipeMessage(this);
}
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.briar.api.remotewipe;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent;
import jdk.nashorn.internal.ir.annotations.Immutable;
@Immutable
@NotNullByDefault
public class RemoteWipeReceivedEvent
extends ConversationMessageReceivedEvent<RemoteWipeMessageHeader> {
public RemoteWipeReceivedEvent(RemoteWipeMessageHeader messageHeader,
ContactId contactId) {
super(messageHeader, contactId);
}
}

View File

@@ -10,9 +10,9 @@ import org.briarproject.briar.introduction.IntroductionModule;
import org.briarproject.briar.messaging.MessagingModule;
import org.briarproject.briar.privategroup.PrivateGroupModule;
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
import org.briarproject.briar.remotewipe.RemoteWipeModule;
import org.briarproject.briar.sharing.SharingModule;
import org.briarproject.briar.socialbackup.SocialBackupModule;
//import org.briarproject.briar.socialbackup.DefaultSocialBackupModule;
public interface BriarCoreEagerSingletons {
@@ -38,6 +38,8 @@ public interface BriarCoreEagerSingletons {
void inject(SocialBackupModule.EagerSingletons init);
void inject(RemoteWipeModule.EagerSingletons init);
void inject(HandshakeKeyExchangeModule.EagerSingletons init);
class Helper {
@@ -54,6 +56,7 @@ public interface BriarCoreEagerSingletons {
c.inject(new IdentityModule.EagerSingletons());
c.inject(new IntroductionModule.EagerSingletons());
c.inject(new SocialBackupModule.EagerSingletons());
c.inject(new RemoteWipeModule.EagerSingletons());
c.inject(new HandshakeKeyExchangeModule.EagerSingletons());
}
}

View File

@@ -13,6 +13,7 @@ import org.briarproject.briar.introduction.IntroductionModule;
import org.briarproject.briar.messaging.MessagingModule;
import org.briarproject.briar.privategroup.PrivateGroupModule;
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
import org.briarproject.briar.remotewipe.RemoteWipeModule;
import org.briarproject.briar.sharing.SharingModule;
import org.briarproject.briar.socialbackup.SocialBackupModule;
import org.briarproject.briar.test.TestModule;
@@ -32,6 +33,7 @@ import dagger.Module;
AttachmentModule.class,
MessagingModule.class,
PrivateGroupModule.class,
RemoteWipeModule.class,
SharingModule.class,
SocialBackupModule.class,
HandshakeKeyExchangeModule.class,

View File

@@ -0,0 +1,63 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.briar.api.remotewipe.MessageEncoder;
import javax.inject.Inject;
import static org.briarproject.briar.api.remotewipe.MessageType.CONFIRM;
import static org.briarproject.briar.api.remotewipe.MessageType.SETUP;
import static org.briarproject.briar.api.remotewipe.MessageType.WIPE;
import static org.briarproject.briar.api.remotewipe.MessageType.REVOKE;
public class MessageEncoderImpl implements MessageEncoder {
private final ClientHelper clientHelper;
@Inject
MessageEncoderImpl(ClientHelper clientHelper) {
this.clientHelper = clientHelper;
}
@Override
public byte[] encodeSetupMessage() {
BdfList body = BdfList.of(
SETUP.getValue()
);
return encodeBody(body);
}
@Override
public byte[] encodeRevokeMessage() {
BdfList body = BdfList.of(
REVOKE.getValue()
);
return encodeBody(body);
}
@Override
public byte[] encodeWipeMessage() {
BdfList body = BdfList.of(
WIPE.getValue()
);
return encodeBody(body);
}
@Override
public byte[] encodeConfirmMessage() {
BdfList body = BdfList.of(
CONFIRM.getValue()
);
return encodeBody(body);
}
private byte[] encodeBody(BdfList body) {
try {
return clientHelper.toByteArray(body);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
}

View File

@@ -0,0 +1,29 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.briar.api.remotewipe.MessageParser;
import javax.inject.Inject;
public class MessageParserImpl implements MessageParser {
@Inject
MessageParserImpl () {
}
@Override
public void parseSetupMessage(BdfList body) throws FormatException {
}
@Override
public void parseWipeMessage(BdfList body) throws FormatException {
}
@Override
public void parseRevokeMessage(BdfList body) throws FormatException {
}
}

View File

@@ -0,0 +1,656 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.attachment.AttachmentHeader;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.conversation.DeletionResult;
import org.briarproject.briar.api.remotewipe.MessageEncoder;
import org.briarproject.briar.api.remotewipe.MessageParser;
import org.briarproject.briar.api.remotewipe.MessageType;
import org.briarproject.briar.api.remotewipe.RemoteWipeActivatedEvent;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader;
import org.briarproject.briar.api.remotewipe.RemoteWipeReceivedEvent;
import org.briarproject.briar.client.ConversationClientImpl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.api.remotewipe.MessageType.CONFIRM;
import static org.briarproject.briar.api.remotewipe.MessageType.REVOKE;
import static org.briarproject.briar.api.remotewipe.MessageType.SETUP;
import static org.briarproject.briar.api.remotewipe.MessageType.WIPE;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.GROUP_KEY_AM_WIPER;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.GROUP_KEY_RECEIVED_WIPE;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.GROUP_KEY_WIPERS;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.MAX_MESSAGE_AGE;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.MSG_KEY_MESSAGE_TYPE;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.MSG_KEY_TIMESTAMP;
import static org.briarproject.briar.api.remotewipe.RemoteWipeConstants.THRESHOLD;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
public class RemoteWipeManagerImpl extends ConversationClientImpl
implements RemoteWipeManager, ContactManager.ContactHook,
ClientVersioningManager.ClientVersioningHook,
LifecycleManager.OpenDatabaseHook {
private final ClientVersioningManager clientVersioningManager;
private final Group localGroup;
private final Clock clock;
private final ContactGroupFactory contactGroupFactory;
private final ContactManager contactManager;
private final MessageEncoder messageEncoder;
private final MessageParser messageParser;
private RemoteWipeManager.Observer observer;
private static final Logger LOG =
getLogger(RemoteWipeManager.class.getName());
@Inject
protected RemoteWipeManagerImpl(
DatabaseComponent db,
ClientHelper clientHelper,
MetadataParser metadataParser,
MessageTracker messageTracker,
Clock clock,
MessageEncoder messageEncoder,
MessageParser messageParser,
ContactManager contactManager,
ClientVersioningManager clientVersioningManager,
ContactGroupFactory contactGroupFactory) {
super(db, clientHelper, metadataParser, messageTracker);
this.clock = clock;
this.contactGroupFactory = contactGroupFactory;
this.contactManager = contactManager;
this.clientVersioningManager = clientVersioningManager;
this.messageEncoder = messageEncoder;
this.messageParser = messageParser;
localGroup =
contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION);
}
@Override
public void listenForPanic(RemoteWipeManager.Observer observer) {
this.observer = observer;
}
@Override
public void onDatabaseOpened(Transaction txn) throws DbException {
if (db.containsGroup(txn, localGroup.getId())) return;
db.addGroup(txn, localGroup);
// Set things up for any pre-existing contacts
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
}
private void setContactId(Transaction txn, GroupId g, ContactId c)
throws DbException {
BdfDictionary d = new BdfDictionary();
d.put(GROUP_KEY_CONTACT_ID, c.getInt());
try {
clientHelper.mergeGroupMetadata(txn, g, d);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
@Override
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary meta) throws DbException, FormatException {
LOG.info("Incoming remote wipe message");
MessageType type = MessageType
.fromValue(body.getLong(0).intValue());
if (type == SETUP) {
messageTracker.trackIncomingMessage(txn, m);
ContactId contactId = getContactId(txn, m.getGroupId());
MessageStatus status = db.getMessageStatus(txn, contactId,
m.getId());
txn.attach(new RemoteWipeReceivedEvent(
createMessageHeader(m, meta, status, type), contactId));
// Update our local record
BdfDictionary localRecord = new BdfDictionary();
localRecord.put(GROUP_KEY_AM_WIPER, true);
if (!db.containsGroup(txn, localGroup.getId()))
db.addGroup(txn, localGroup);
clientHelper
.mergeGroupMetadata(txn, localGroup.getId(), localRecord);
} else if (type == WIPE) {
if (!remoteWipeIsSetup(txn)) return false;
if (clock.currentTimeMillis() - m.getTimestamp() > MAX_MESSAGE_AGE)
return false;
ContactId contactId = getContactId(txn, m.getGroupId());
// Check if contact is in list of wipers
if (isWiper(txn, contactId)) {
LOG.info("Got a valid wipe message from a wiper");
BdfDictionary existingMeta =
clientHelper.getGroupMetadataAsDictionary(txn,
localGroup.getId());
BdfList receivedWipeMessages =
existingMeta.getOptionalList(GROUP_KEY_RECEIVED_WIPE);
if (receivedWipeMessages == null)
receivedWipeMessages = new BdfList();
// Traverse the list backwards to avoid problems when removing items
for (int i = receivedWipeMessages.size() - 1; i >= 0; --i) {
BdfList receivedWipeMessage =
receivedWipeMessages.getList(i);
long timestamp = receivedWipeMessage.getLong(1);
LOG.info("Message age: " +
(clock.currentTimeMillis() - timestamp));
// Filter the messages for old ones
if (clock.currentTimeMillis() - timestamp >
MAX_MESSAGE_AGE) {
LOG.info("Removing outdated wipe message");
receivedWipeMessages.remove(i);
} else if (receivedWipeMessage.getLong(0).intValue() ==
contactId.getInt()) {
// If we already have one from this contact, ignore
LOG.info(
"Duplicate wipe message received - ignoring");
return false;
}
}
if (receivedWipeMessages.size() + 1 == THRESHOLD) {
LOG.warning("Threshold number of remote wipe signals reached - panic!");
// Send a CONFIRM message to each wiper
// sendConfirmMessages(txn);
if (observer != null) {
observer.onPanic();
}
txn.attach(new RemoteWipeActivatedEvent());
} else {
BdfList newReceivedWipeMessage = new BdfList();
newReceivedWipeMessage.add(contactId.getInt());
newReceivedWipeMessage.add(m.getTimestamp());
receivedWipeMessages.add(newReceivedWipeMessage);
BdfDictionary newMeta = new BdfDictionary();
newMeta.put(GROUP_KEY_RECEIVED_WIPE, receivedWipeMessages);
clientHelper.mergeGroupMetadata(txn, localGroup.getId(),
newMeta);
}
}
} else if (type == REVOKE) {
messageTracker.trackIncomingMessage(txn, m);
ContactId contactId = getContactId(txn, m.getGroupId());
MessageStatus status = db.getMessageStatus(txn, contactId,
m.getId());
txn.attach(new RemoteWipeReceivedEvent(
createMessageHeader(m, meta, status, type), contactId));
// Update our local record
BdfDictionary localRecord = new BdfDictionary();
localRecord.put(GROUP_KEY_AM_WIPER, false);
if (!db.containsGroup(txn, localGroup.getId()))
db.addGroup(txn, localGroup);
clientHelper
.mergeGroupMetadata(txn, localGroup.getId(), localRecord);
} else if (type == CONFIRM) {
messageTracker.trackIncomingMessage(txn, m);
ContactId contactId = getContactId(txn, m.getGroupId());
MessageStatus status = db.getMessageStatus(txn, contactId,
m.getId());
txn.attach(new RemoteWipeReceivedEvent(
createMessageHeader(m, meta, status, type), contactId));
}
return false;
}
private boolean isInList(Transaction txn, Author a, List<ContactId> wipers)
throws DbException {
for (ContactId c : wipers) {
if (contactManager.getContact(txn, c).getAuthor().equals(a))
return true;
}
return false;
}
public void setup(Transaction txn, List<ContactId> wipers)
throws DbException, FormatException {
if (remoteWipeIsSetup(txn)) {
// Revoke existing wipers who are not present in the new list
List<Author> existingWipers = getWipers(txn);
for (Author existingWiper : existingWipers) {
if (!isInList(txn, existingWiper, wipers)) {
LOG.info("Revoking an existing wiper");
sendRevokeMessage(txn, contactManager.getContact(txn,
authorToContactId(txn, existingWiper)));
}
}
}
if (wipers.size() < 2) throw new FormatException();
BdfList wipersMetadata = new BdfList();
for (ContactId c : wipers) {
Contact contact = contactManager.getContact(txn, c);
sendSetupMessage(txn, contact);
wipersMetadata.add(clientHelper.toList(contact.getAuthor()));
}
LOG.info("All remote wipe setup messages sent");
// Make a record of this locally
BdfDictionary meta = new BdfDictionary();
meta.put(GROUP_KEY_WIPERS, wipersMetadata);
if (!db.containsGroup(txn, localGroup.getId()))
db.addGroup(txn, localGroup);
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
}
private void sendSetupMessage(Transaction txn, Contact contact)
throws DbException, FormatException {
Group group = getContactGroup(contact);
GroupId g = group.getId();
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
long timestamp = clock.currentTimeMillis();
byte[] body = messageEncoder.encodeSetupMessage();
Message m = clientHelper.createMessage(g, timestamp, body);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SETUP.getValue()),
new BdfEntry(MSG_KEY_LOCAL, true),
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
);
clientHelper.addLocalMessage(txn, m, meta, true, false);
messageTracker.trackOutgoingMessage(txn, m);
}
private void sendRevokeMessage(Transaction txn, Contact contact)
throws DbException, FormatException {
Group group = getContactGroup(contact);
GroupId g = group.getId();
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
long timestamp = clock.currentTimeMillis();
byte[] body = messageEncoder.encodeRevokeMessage();
Message m = clientHelper.createMessage(g, timestamp, body);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, REVOKE.getValue()),
new BdfEntry(MSG_KEY_LOCAL, true),
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
);
clientHelper.addLocalMessage(txn, m, meta, true, false);
messageTracker.trackOutgoingMessage(txn, m);
}
public int sendConfirmMessages(Transaction txn)
throws DbException, FormatException {
List<ContactId> wipers = getWiperContactIds(txn);
for (ContactId c : wipers) {
Contact contact = contactManager.getContact(txn, c);
sendConfirmMessage(txn, contact);
}
return wipers.size();
}
private void sendConfirmMessage(Transaction txn, Contact contact)
throws DbException, FormatException {
Group group = getContactGroup(contact);
GroupId g = group.getId();
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
long timestamp = clock.currentTimeMillis();
byte[] body = messageEncoder.encodeConfirmMessage();
Message m = clientHelper.createMessage(g, timestamp, body);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, CONFIRM.getValue()),
new BdfEntry(MSG_KEY_LOCAL, true),
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
);
clientHelper.addLocalMessage(txn, m, meta, true, false);
messageTracker.trackOutgoingMessage(txn, m);
}
public void wipe(Transaction txn, Contact contact)
throws DbException, FormatException {
// Check that we have wiper status
if (!amWiper(txn, contact.getId())) throw new DbException();
Group group = getContactGroup(contact);
GroupId g = group.getId();
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
long timestamp = clock.currentTimeMillis();
byte[] body = messageEncoder.encodeWipeMessage();
Message m = clientHelper.createMessage(g, timestamp, body);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp),
new BdfEntry(MSG_KEY_MESSAGE_TYPE, WIPE.getValue()),
new BdfEntry(MSG_KEY_LOCAL, true)
);
clientHelper.addLocalMessage(txn, m, meta, true, false);
messageTracker.trackOutgoingMessage(txn, m);
}
public boolean isWiper(Transaction txn, ContactId contactId) {
try {
Author author =
contactManager.getContact(txn, contactId).getAuthor();
List<Author> currentWipers = getWipers(txn);
for (Author a : currentWipers) {
if (a.getId().equals(author.getId())) {
return true;
}
}
return false;
} catch (DbException e) {
return false;
}
}
public boolean amWiper(Transaction txn, ContactId contactId) {
try {
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
localGroup.getId());
return meta.getBoolean(GROUP_KEY_AM_WIPER, false);
} catch (DbException | FormatException e) {
return false;
}
}
public void revoke(Transaction txn, ContactId contactId)
throws DbException, FormatException {
// Revoke a contact's wiper status
Contact contactToRevoke = contactManager.getContact(txn, contactId);
Author authorToRevoke = contactToRevoke.getAuthor();
List<Author> currentWipers = getWipers(txn);
BdfList newWipers = new BdfList();
for (Author a : currentWipers) {
if (a.getId().equals(authorToRevoke.getId())) {
sendRevokeMessage(txn, contactToRevoke);
} else {
newWipers.add(clientHelper.toList(a));
}
}
// If we revoked someone, update our list
if (newWipers.size() < currentWipers.size()) {
BdfDictionary meta = new BdfDictionary();
meta.put(GROUP_KEY_WIPERS, newWipers);
if (!db.containsGroup(txn, localGroup.getId()))
db.addGroup(txn, localGroup);
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
}
}
public void revokeAll(Transaction txn) throws DbException, FormatException {
List<ContactId> currentWipers = getWiperContactIds(txn);
for (ContactId c : currentWipers) {
sendRevokeMessage(txn, db.getContact(txn, c));
}
BdfList noWipers = new BdfList();
BdfDictionary meta = new BdfDictionary();
meta.put(GROUP_KEY_WIPERS, noWipers);
if (!db.containsGroup(txn, localGroup.getId()))
db.addGroup(txn, localGroup);
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
}
@Override
public Group getContactGroup(Contact c) {
return contactGroupFactory.createContactGroup(CLIENT_ID,
MAJOR_VERSION, c);
}
@Override
public Collection<ConversationMessageHeader> getMessageHeaders(
Transaction txn, ContactId contactId) throws DbException {
try {
Contact contact = db.getContact(txn, contactId);
GroupId contactGroupId = getContactGroup(contact).getId();
Map<MessageId, BdfDictionary> messages = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId);
List<ConversationMessageHeader> headers =
new ArrayList<>();
for (Map.Entry<MessageId, BdfDictionary> messageEntry : messages
.entrySet()) {
BdfDictionary meta = messageEntry.getValue();
if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
SETUP.getValue()) {
Message message = clientHelper
.getMessage(txn, messageEntry.getKey());
MessageStatus status = db.getMessageStatus(txn, contactId,
messageEntry.getKey());
headers.add(
createMessageHeader(message, meta, status, SETUP));
} else if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
WIPE.getValue()) {
Message message = clientHelper
.getMessage(txn, messageEntry.getKey());
MessageStatus status = db.getMessageStatus(txn, contactId,
messageEntry.getKey());
if (meta.getBoolean(MSG_KEY_LOCAL)) {
headers.add(
createMessageHeader(message, meta, status,
WIPE));
}
} else if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
REVOKE.getValue()) {
Message message = clientHelper
.getMessage(txn, messageEntry.getKey());
MessageStatus status = db.getMessageStatus(txn, contactId,
messageEntry.getKey());
headers.add(
createMessageHeader(message, meta, status, REVOKE));
} else if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
CONFIRM.getValue()) {
Message message = clientHelper
.getMessage(txn, messageEntry.getKey());
MessageStatus status = db.getMessageStatus(txn, contactId,
messageEntry.getKey());
headers.add(
createMessageHeader(message, meta, status, CONFIRM));
}
}
return headers;
} catch (FormatException e) {
throw new DbException(e);
}
}
private RemoteWipeMessageHeader createMessageHeader(
Message message, BdfDictionary meta, MessageStatus status,
MessageType type
)
throws FormatException {
boolean isLocal = meta.getBoolean(MSG_KEY_LOCAL);
boolean read = meta.getBoolean(MSG_KEY_READ, false);
long timestamp;
if (isLocal) {
timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
} else {
timestamp = message.getTimestamp();
}
List<AttachmentHeader> attachmentHeaders =
new ArrayList<>();
return new RemoteWipeMessageHeader(
message.getId(), message.getGroupId(), timestamp,
isLocal, read, status.isSent(), status.isSeen(),
attachmentHeaders, type);
}
@Override
public Set<MessageId> getMessageIds(Transaction txn, ContactId contactId)
throws DbException {
Contact contact = db.getContact(txn, contactId);
GroupId contactGroupId = getContactGroup(contact).getId();
try {
Map<MessageId, BdfDictionary> messages = clientHelper
.getMessageMetadataAsDictionary(txn, contactGroupId);
return messages.keySet();
} catch (FormatException e) {
throw new DbException(e);
}
}
@Override
public DeletionResult deleteAllMessages(Transaction txn, ContactId c)
throws DbException {
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
for (MessageId messageId : db.getMessageIds(txn, g)) {
db.deleteMessage(txn, messageId);
db.deleteMessageMetadata(txn, messageId);
}
messageTracker.initializeGroupCount(txn, g);
return new DeletionResult();
}
@Override
public DeletionResult deleteMessages(Transaction txn, ContactId c,
Set<MessageId> messageIds) throws DbException {
for (MessageId m : messageIds) {
db.deleteMessage(txn, m);
db.deleteMessageMetadata(txn, m);
}
return new DeletionResult();
}
private ContactId getContactId(Transaction txn, GroupId g)
throws DbException {
try {
BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) {
throw new DbException(e);
}
}
@Override
public void onClientVisibilityChanging(Transaction txn, Contact c,
Group.Visibility v) throws DbException {
// Apply the client's visibility to the contact group
Group g = getContactGroup(c);
db.setGroupVisibility(txn, c.getId(), g.getId(), v);
}
@Override
public void addingContact(Transaction txn, Contact c) throws DbException {
// Create a group to share with the contact
Group g = getContactGroup(c);
db.addGroup(txn, g);
// Apply the client's visibility to the contact group
Group.Visibility client =
clientVersioningManager.getClientVisibility(txn,
c.getId(), CLIENT_ID, MAJOR_VERSION);
db.setGroupVisibility(txn, c.getId(), g.getId(), client);
// Attach the contact ID to the group
setContactId(txn, g.getId(), c.getId());
}
@Override
public void removingContact(Transaction txn, Contact c) throws DbException {
db.removeGroup(txn, getContactGroup(c));
}
@Override
public boolean remoteWipeIsSetup(Transaction txn) {
try {
return getWipers(txn).size() > 0;
} catch (DbException e) {
return false;
}
}
public List<Author> getWipers(Transaction txn) throws DbException {
try {
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
localGroup.getId());
BdfList bdfWipers = meta.getList(GROUP_KEY_WIPERS);
List<Author> wipers = new ArrayList<>(bdfWipers.size());
for (int i = 0; i < bdfWipers.size(); i++) {
BdfList author = bdfWipers.getList(i);
wipers.add(clientHelper.parseAndValidateAuthor(author));
}
return wipers;
} catch (FormatException e) {
throw new DbException(e);
}
}
public List<ContactId> getWiperContactIds(Transaction txn) {
ArrayList<ContactId> wiperContactIds = new ArrayList<>();
try {
List<Author> wipers = getWipers(txn);
for (Author wiper : wipers) {
wiperContactIds.add(authorToContactId(txn, wiper));
}
} catch (DbException ignored) {
// Will return an empty list
}
return wiperContactIds;
}
private ContactId authorToContactId(Transaction txn, Author author)
throws DbException {
ArrayList<Contact> contacts =
(ArrayList<Contact>) contactManager.getContacts(txn);
for (Contact c : contacts) {
if (c.getAuthor().equals(author)) return c.getId();
}
throw new DbException();
}
}

View File

@@ -0,0 +1,78 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.validation.ValidationManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.remotewipe.MessageEncoder;
import org.briarproject.briar.api.remotewipe.MessageParser;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static org.briarproject.briar.api.remotewipe.RemoteWipeManager.CLIENT_ID;
import static org.briarproject.briar.api.remotewipe.RemoteWipeManager.MAJOR_VERSION;
import static org.briarproject.briar.api.remotewipe.RemoteWipeManager.MINOR_VERSION;
@Module
public class RemoteWipeModule {
public static class EagerSingletons {
@Inject
RemoteWipeManager remoteWipeManager;
@Inject
RemoteWipeValidator remoteWipeValidator;
}
@Provides
@Singleton
RemoteWipeManager remoteWipeManager(
LifecycleManager lifecycleManager,
ValidationManager validationManager,
ConversationManager conversationManager,
ContactManager contactManager,
ClientVersioningManager clientVersioningManager,
RemoteWipeManagerImpl remoteWipeManager) {
lifecycleManager.registerOpenDatabaseHook(remoteWipeManager);
validationManager
.registerIncomingMessageHook(RemoteWipeManager.CLIENT_ID,
RemoteWipeManager.MAJOR_VERSION, remoteWipeManager);
contactManager.registerContactHook(remoteWipeManager);
clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION,
MINOR_VERSION, remoteWipeManager);
conversationManager.registerConversationClient(remoteWipeManager);
return remoteWipeManager;
}
@Provides
@Singleton
RemoteWipeValidator remoteWipeValidator(
ValidationManager validationManager,
ClientHelper clientHelper,
MetadataEncoder metadataEncoder,
Clock clock) {
RemoteWipeValidator validator =
new RemoteWipeValidator(clientHelper, metadataEncoder, clock);
validationManager.registerMessageValidator(CLIENT_ID, MAJOR_VERSION,
validator);
return validator;
}
@Provides
MessageEncoder messageEncoder(MessageEncoderImpl messageEncoder) {
return messageEncoder;
}
@Provides
MessageParser messageParser(MessageParserImpl messageParser) {
return messageParser;
}
}

View File

@@ -0,0 +1,85 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.BdfMessageContext;
import org.briarproject.bramble.api.client.BdfMessageValidator;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.system.Clock;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
import static org.briarproject.briar.api.remotewipe.MessageType.CONFIRM;
import static org.briarproject.briar.api.remotewipe.MessageType.REVOKE;
import static org.briarproject.briar.api.remotewipe.MessageType.SETUP;
import static org.briarproject.briar.api.remotewipe.MessageType.WIPE;
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_MESSAGE_TYPE;
@Immutable
@NotNullByDefault
class RemoteWipeValidator extends BdfMessageValidator {
@Inject
RemoteWipeValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) {
super(clientHelper, metadataEncoder, clock);
}
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException {
org.briarproject.briar.api.remotewipe.MessageType
type = org.briarproject.briar.api.remotewipe.MessageType
.fromValue(body.getLong(0).intValue());
if (type == SETUP) return validateSetupMessage(body);
else if (type == WIPE) return validateWipeMessage(body);
else if (type == REVOKE) return validateRevokeMessage(body);
else if (type == CONFIRM) return validateConfirmMessage(body);
else throw new AssertionError();
}
private BdfMessageContext validateSetupMessage(BdfList body)
throws FormatException {
checkSize(body, 1);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SETUP.getValue()),
new BdfEntry(MSG_KEY_LOCAL, false));
return new BdfMessageContext(meta);
}
private BdfMessageContext validateWipeMessage(BdfList body)
throws FormatException {
checkSize(body, 1);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, WIPE.getValue()),
new BdfEntry(MSG_KEY_LOCAL, false));
return new BdfMessageContext(meta);
}
private BdfMessageContext validateRevokeMessage(BdfList body)
throws FormatException {
checkSize(body, 1);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, REVOKE.getValue()),
new BdfEntry(MSG_KEY_LOCAL, false));
return new BdfMessageContext(meta);
}
private BdfMessageContext validateConfirmMessage(BdfList body)
throws FormatException {
checkSize(body, 1);
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(MSG_KEY_MESSAGE_TYPE, CONFIRM.getValue()),
new BdfEntry(MSG_KEY_LOCAL, false));
return new BdfMessageContext(meta);
}
}

View File

@@ -268,6 +268,7 @@ class SocialBackupManagerImpl extends ConversationClientImpl
try {
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
localGroup.getId());
return backupMetadataParser.parseBackupMetadata(meta);
} catch (FormatException e) {
throw new DbException(e);

View File

@@ -0,0 +1,282 @@
package org.briarproject.briar.remotewipe;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.test.TestDatabaseConfigModule;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader;
import org.briarproject.briar.test.BriarIntegrationTest;
import org.briarproject.briar.test.BriarIntegrationTestComponent;
import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class RemoteWipeIntegrationTest extends BriarIntegrationTest<BriarIntegrationTestComponent> implements RemoteWipeManager.Observer {
private RemoteWipeManager remoteWipeManager0;
private RemoteWipeManager remoteWipeManager1;
private RemoteWipeManager remoteWipeManager2;
private Group g1From0;
private Group g0From1;
private Group g2From0;
private Group g0From2;
private boolean panicCalled = false;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
remoteWipeManager0 = c0.getRemoteWipeManager();
remoteWipeManager1 = c1.getRemoteWipeManager();
remoteWipeManager2 = c2.getRemoteWipeManager();
g1From0 = remoteWipeManager0.getContactGroup(contact1From0);
g0From1 = remoteWipeManager1.getContactGroup(contact0From1);
g2From0 = remoteWipeManager0.getContactGroup(contact2From0);
g0From2 = remoteWipeManager2.getContactGroup(contact0From2);
}
@Override
protected void createComponents() {
BriarIntegrationTestComponent component =
DaggerBriarIntegrationTestComponent.builder().build();
BriarIntegrationTestComponent.Helper.injectEagerSingletons(component);
component.inject(this);
c0 = DaggerBriarIntegrationTestComponent.builder()
.testDatabaseConfigModule(new TestDatabaseConfigModule(t0Dir))
.build();
BriarIntegrationTestComponent.Helper.injectEagerSingletons(c0);
c1 = DaggerBriarIntegrationTestComponent.builder()
.testDatabaseConfigModule(new TestDatabaseConfigModule(t1Dir))
.build();
BriarIntegrationTestComponent.Helper.injectEagerSingletons(c1);
c2 = DaggerBriarIntegrationTestComponent.builder()
.testDatabaseConfigModule(new TestDatabaseConfigModule(t2Dir))
.build();
BriarIntegrationTestComponent.Helper.injectEagerSingletons(c2);
}
@Test
public void testRemoteWipe() throws Exception {
remoteWipeManager0.listenForPanic(this);
db0.transaction(false, txn -> {
// Assert that we do not already have a wipe setup
assertFalse(remoteWipeManager0.remoteWipeIsSetup(txn));
remoteWipeManager0.setup(txn,
asList(contactId1From0, contactId2From0));
// Now check that we do have a wipe setup
assertTrue(remoteWipeManager0.remoteWipeIsSetup(txn));
});
// Sync the setup messages to the contacts
sync0To1(1, true);
sync0To2(1, true);
// The setup message from 0 should have arrived at 1
Collection<ConversationMessageHeader> messages0At1 =
getMessages0At1();
assertEquals(1, messages0At1.size());
Collection<ConversationMessageHeader> messages0At2 =
getMessages0At2();
assertEquals(1, messages0At2.size());
for (ConversationMessageHeader h : messages0At1) {
assertTrue(h instanceof RemoteWipeMessageHeader);
RemoteWipeMessageHeader r = (RemoteWipeMessageHeader) h;
assertFalse(r.isLocal());
}
// The wipers check that they are now wipers
db1.transaction(false, txn -> {
assertTrue(remoteWipeManager1.amWiper(txn, contactId0From1));
remoteWipeManager1.wipe(txn, contact0From1);
});
db2.transaction(false, txn -> {
assertTrue(remoteWipeManager2.amWiper(txn, contactId0From2));
remoteWipeManager2.wipe(txn, contact0From2);
});
// Sync the wipe messages to the wipee
sync1To0(1, true);
sync2To0(1, true);
Collection<ConversationMessageHeader> messages1At0 =
getMessages1At0();
assertEquals(1, messages1At0.size());
Collection<ConversationMessageHeader> messages2At0 =
getMessages2At0();
assertEquals(1, messages2At0.size());
assertTrue(panicCalled);
}
@Test
public void testRemoteWipeFailsOnDuplicateMessage() throws Exception {
remoteWipeManager0.listenForPanic(this);
db0.transaction(false, txn -> {
// Assert that we do not already have a wipe setup
assertFalse(remoteWipeManager0.remoteWipeIsSetup(txn));
remoteWipeManager0.setup(txn,
asList(contactId1From0, contactId2From0));
// Now check that we do have a wipe setup
assertTrue(remoteWipeManager0.remoteWipeIsSetup(txn));
});
// Sync the setup messages to the contacts
sync0To1(1, true);
sync0To2(1, true);
// The setup message from 0 should have arrived at 1
Collection<ConversationMessageHeader> messages0At1 =
getMessages0At1();
assertEquals(1, messages0At1.size());
Collection<ConversationMessageHeader> messages0At2 =
getMessages0At2();
assertEquals(1, messages0At2.size());
for (ConversationMessageHeader h : messages0At1) {
assertTrue(h instanceof RemoteWipeMessageHeader);
RemoteWipeMessageHeader r = (RemoteWipeMessageHeader) h;
assertFalse(r.isLocal());
}
// The wipers check that they are now wipers
db1.transaction(false, txn -> {
assertTrue(remoteWipeManager1.amWiper(txn, contactId0From1));
remoteWipeManager1.wipe(txn, contact0From1);
Thread.sleep(100);
remoteWipeManager1.wipe(txn, contact0From1);
});
db2.transaction(false, txn -> {
assertTrue(remoteWipeManager2.amWiper(txn, contactId0From2));
// remoteWipeManager2.wipe(txn, contact0From2);
});
// Sync the wipe messages to the wipee
sync1To0(2, true);
// sync2To0(1, true);
Collection<ConversationMessageHeader> messages1At0 =
getMessages1At0();
assertEquals(1, messages1At0.size());
Collection<ConversationMessageHeader> messages2At0 =
getMessages2At0();
assertEquals(1, messages2At0.size());
assertFalse(panicCalled);
}
@Test
public void testRemoteWipeWithRevoke() throws Exception {
remoteWipeManager0.listenForPanic(this);
db0.transaction(false, txn -> {
// Assert that we do not already have a wipe setup
assertFalse(remoteWipeManager0.remoteWipeIsSetup(txn));
remoteWipeManager0.setup(txn,
asList(contactId1From0, contactId2From0));
// Now check that we do have a wipe setup
assertTrue(remoteWipeManager0.remoteWipeIsSetup(txn));
// Check we have 2 wipers
assertEquals(remoteWipeManager0.getWipers(txn).size(), 2);
});
// Sync the setup messages to the contacts
sync0To1(1, true);
sync0To2(1, true);
// The setup message from 0 should have arrived at 1
Collection<ConversationMessageHeader> messages0At1 =
getMessages0At1();
assertEquals(1, messages0At1.size());
Collection<ConversationMessageHeader> messages0At2 =
getMessages0At2();
assertEquals(1, messages0At2.size());
for (ConversationMessageHeader h : messages0At1) {
assertTrue(h instanceof RemoteWipeMessageHeader);
RemoteWipeMessageHeader r = (RemoteWipeMessageHeader) h;
assertFalse(r.isLocal());
}
// Revoke contact 1's wiper status
db0.transaction(false, txn -> {
remoteWipeManager0.revoke(txn, contactId1From0);
// Check we now only have one wiper
assertEquals(remoteWipeManager0.getWipers(txn).size(), 1);
});
// Sync the revoke message
sync0To1(1, true);
// The wipers check if they are now wipers
db1.transaction(false, txn -> {
assertFalse(remoteWipeManager1.amWiper(txn, contactId0From1));
boolean cannotWipe = false;
try {
remoteWipeManager1.wipe(txn, contact0From1);
} catch(DbException e) {
cannotWipe = true;
} finally {
assertTrue(cannotWipe);
}
});
}
private Collection<ConversationMessageHeader> getMessages1At0()
throws DbException {
return db0.transactionWithResult(true, txn -> remoteWipeManager0
.getMessageHeaders(txn, contactId1From0));
}
private Collection<ConversationMessageHeader> getMessages2At0()
throws DbException {
return db0.transactionWithResult(true, txn -> remoteWipeManager0
.getMessageHeaders(txn, contactId2From0));
}
private Collection<ConversationMessageHeader> getMessages0At1()
throws DbException {
return db1.transactionWithResult(true, txn -> remoteWipeManager1
.getMessageHeaders(txn, contactId0From1));
}
private Collection<ConversationMessageHeader> getMessages0At2()
throws DbException {
return db1.transactionWithResult(true, txn -> remoteWipeManager2
.getMessageHeaders(txn, contactId0From2));
}
public static void assertGroupCount(MessageTracker tracker, GroupId g,
long msgCount, long unreadCount) throws DbException {
MessageTracker.GroupCount c1 = tracker.getGroupCount(g);
assertEquals(msgCount, c1.getMsgCount());
assertEquals(unreadCount, c1.getUnreadCount());
}
@Override
public void onPanic() {
panicCalled = true;
}
}

View File

@@ -27,6 +27,7 @@ import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
import org.briarproject.briar.avatar.AvatarModule;
import org.briarproject.briar.blog.BlogModule;
@@ -36,6 +37,7 @@ import org.briarproject.briar.introduction.IntroductionModule;
import org.briarproject.briar.messaging.MessagingModule;
import org.briarproject.briar.privategroup.PrivateGroupModule;
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
import org.briarproject.briar.remotewipe.RemoteWipeModule;
import org.briarproject.briar.sharing.SharingModule;
import org.briarproject.briar.socialbackup.DefaultDarkCrystalModule;
import org.briarproject.briar.socialbackup.SocialBackupModule;
@@ -76,6 +78,8 @@ public interface BriarIntegrationTestComponent
void inject(SocialBackupModule.EagerSingletons init);
void inject(RemoteWipeModule.EagerSingletons init);
LifecycleManager getLifecycleManager();
EventBus getEventBus();
@@ -124,6 +128,8 @@ public interface BriarIntegrationTestComponent
SocialBackupManager getSocialBackupManager();
RemoteWipeManager getRemoteWipeManager();
class Helper {
public static void injectEagerSingletons(
@@ -140,6 +146,7 @@ public interface BriarIntegrationTestComponent
c.inject(new PrivateGroupModule.EagerSingletons());
c.inject(new SharingModule.EagerSingletons());
c.inject(new SocialBackupModule.EagerSingletons());
c.inject(new RemoteWipeModule.EagerSingletons());
}
}
}

View File

@@ -9,7 +9,7 @@ import com.github.ajalt.clikt.parameters.types.int
import org.briarproject.bramble.BrambleCoreEagerSingletons
import org.briarproject.briar.BriarCoreEagerSingletons
import org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY
import org.spongycastle.util.encoders.Base64.toBase64String
import org.bouncycastle.util.encoders.Base64.toBase64String
import java.io.File
import java.io.File.separator
import java.io.IOException

View File

@@ -31,8 +31,8 @@ import org.briarproject.briar.headless.getFromJson
import org.briarproject.briar.headless.json.JsonDict
import org.eclipse.jetty.http.HttpStatus.BAD_REQUEST_400
import org.eclipse.jetty.http.HttpStatus.FORBIDDEN_403
import org.spongycastle.util.encoders.Base64
import org.spongycastle.util.encoders.DecoderException
import org.bouncycastle.util.encoders.Base64
import org.bouncycastle.util.encoders.DecoderException
import java.security.GeneralSecurityException
import javax.annotation.concurrent.Immutable
import javax.inject.Inject

View File

@@ -31,14 +31,15 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory
import org.briarproject.briar.api.messaging.PrivateMessageHeader
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse
import org.briarproject.briar.api.remotewipe.RemoteWipeMessageHeader
import org.briarproject.briar.api.socialbackup.ShardMessageHeader
import org.briarproject.briar.headless.event.WebSocketController
import org.briarproject.briar.headless.event.output
import org.briarproject.briar.headless.getContactIdFromPathParam
import org.briarproject.briar.headless.getFromJson
import org.briarproject.briar.headless.json.JsonDict
import org.spongycastle.util.encoders.Base64
import org.spongycastle.util.encoders.DecoderException
import org.bouncycastle.util.encoders.Base64
import org.bouncycastle.util.encoders.DecoderException
import java.util.concurrent.Executor
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
@@ -172,4 +173,6 @@ private class JsonVisitor(
override fun visitIntroductionResponse(r: IntroductionResponse) = r.output(contactId)
override fun visitShardMessage(r: ShardMessageHeader) = r.output(contactId)
override fun visitRemoteWipeMessage(r: RemoteWipeMessageHeader) = r.output(contactId)
}

View File

@@ -32,7 +32,7 @@ import org.briarproject.briar.headless.json.JsonDict
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import org.spongycastle.util.encoders.Base64
import org.bouncycastle.util.encoders.Base64
import kotlin.random.Random
internal class MessagingControllerImplTest : ControllerTest() {
@@ -205,7 +205,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
@Test
fun markMessageRead() {
mockkStatic("org.briarproject.briar.headless.RouterKt")
mockkStatic("org.spongycastle.util.encoders.Base64")
mockkStatic("org.bouncycastle.util.encoders.Base64")
expectGetContact()
val messageIdString = message.id.bytes.toString()

View File

@@ -29,10 +29,11 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'ru.vyarus:gradle-animalsniffer-plugin:1.5.0'
classpath files('libs/gradle-witness.jar')
}
// ext.dagger_version = "2.33"
ext.junit_version = "4.12"
ext.jmock_version = '2.12.0'

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip