1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-06 00:02:48 +02:00

Compare commits

...

1318 Commits

Author SHA1 Message Date
ganfra
9903a299b9 Sqlite: make it work with latest develop version 2020-04-23 20:34:26 +02:00
ganfra
9a4cad1e45 Merge sql crypto store implementation 2020-04-23 18:58:07 +02:00
ganfra
649b4496a6 Make rx module uses Flow/Rx converter 2020-04-23 18:55:10 +02:00
ganfra
617b76c0d5 Make sdk use sqldelight module 2020-04-23 18:53:06 +02:00
ganfra
9415d9b5c5 Configure project 2020-04-23 16:49:51 +02:00
ganfra
3ba5e97392 Introduce all the tables 2020-04-23 12:54:04 +02:00
Benoit Marty
671c1259af Merge pull request #1239 from waylon531/develop
Use a bigger thread pool
2020-04-22 18:23:37 +02:00
Valere
491f0e6032 Merge pull request #1259 from vector-im/feature/restore_backup_from_ssss
KeyBackup / Use 4S if key in quadS
2020-04-21 14:31:26 +02:00
Valere
63355ca256 code review 2020-04-21 11:06:56 +02:00
Valere
8a4f0a0c00 KeyBackup / Use 4S if key in quadS 2020-04-20 19:21:44 +02:00
Benoit Marty
4d207e6acd Merge pull request #1258 from vector-im/feature/strings
Strings
2020-04-20 17:41:50 +02:00
Valere
1227de3f9c Merge pull request #1256 from vector-im/feature/increase_default_timeout
Increase default timeout to match old riot
2020-04-20 17:13:59 +02:00
Benoit Marty
6cad129625 Still waiting for translation update 2020-04-20 16:13:16 +02:00
Benoit Marty
9ccf51fbc0 Import string from Riot - new strings 2020-04-20 15:20:08 +02:00
Benoit Marty
990867204e Import string from Riot 2020-04-20 15:17:14 +02:00
Onuray Sahin
5795b7e063 Merge pull request #1242 from vector-im/feature/save_media_to_gallery
Save media files to Gallery
2020-04-20 13:24:33 +03:00
Valere
b612a7e63c Merge pull request #1252 from vector-im/feature/fix_device_detection_debounce
Avoid unnecessary /device call
2020-04-20 12:07:17 +02:00
Valere
50c73b68aa cleaning 2020-04-20 11:31:42 +02:00
Valere
c7ac5e2293 Increase default timeout to match old riot 2020-04-20 11:26:03 +02:00
Valere
43cb1fe68b Code review 2020-04-20 11:12:35 +02:00
onurays
f807de9a83 Lint fix. 2020-04-20 11:53:33 +03:00
Onuray Sahin
754f220596 Merge branch 'develop' into feature/save_media_to_gallery 2020-04-20 11:21:14 +03:00
onurays
3f7ca8669a Remove duplicated save icon. 2020-04-20 00:48:52 +03:00
Valere
28c6921a0a Avoid unnecessary /device call 2020-04-17 18:08:29 +02:00
onurays
26bb8ce2be Give user a toast after adding media file to the gallery. 2020-04-17 16:53:40 +03:00
onurays
8434f9326e Save action added to bottom sheet. 2020-04-17 15:27:42 +03:00
Waylon Cude
68f93c6c31 Merge branch 'develop' of https://github.com/vector-im/riotX-android into develop
Signed-off-by: Waylon Cude <waylon.cude@finzdani.net>
2020-04-16 12:19:17 -07:00
Benoit Marty
7961423556 Merge pull request #1244 from vector-im/feature/media_path
Fix download and upload media path
2020-04-16 17:58:08 +02:00
Benoit Marty
ac07fb47d7 Better Kotlin code 2020-04-16 17:42:55 +02:00
Valere
fbcbd6def5 Merge pull request #1243 from vector-im/feature/update_x_signing_copy
Feature/update x signing copy
2020-04-16 17:30:11 +02:00
Valere
3fe15f2d45 code review 2020-04-16 17:02:01 +02:00
Valere
968377a5be Update vector/src/main/res/values/strings_riotX.xml
Co-Authored-By: Benoit Marty <benoitm@matrix.org>
2020-04-16 16:53:24 +02:00
Benoit Marty
5652140f5d Improve ContentUrlResolver 2020-04-16 16:41:45 +02:00
Benoit Marty
e97c95f40a Fix issue with media path (Fixes #1227) 2020-04-16 16:41:45 +02:00
Valere
7ac5f58f32 Show CrossSigning info even if not developer mode 2020-04-16 16:30:45 +02:00
Valere
ce2f4e163d Update password/recovery copy + update icons 2020-04-16 16:30:45 +02:00
Benoit Marty
cc94b6cf7d Merge pull request #1116 from vector-im/feature/worker_manager
Add some documentation on Workers
2020-04-16 16:28:20 +02:00
onurays
ab3cc90ed5 Share menu item added to video media viewer. 2020-04-16 16:46:00 +03:00
Valere
614127e46b Merge pull request #1240 from vector-im/feature/update_security_notice
Feature/update security notice
2020-04-16 15:33:54 +02:00
Valere
66fc38ad4b Remove GlobalScope usage 2020-04-16 15:09:16 +02:00
Valere
f68e84d9da Update toaster to match web 2020-04-16 15:09:16 +02:00
onurays
2b2e6dd6f8 Share menu item added to image media viewer. 2020-04-16 16:04:37 +03:00
Valere
621e78a864 Merge pull request #1235 from vector-im/feature/upgrate_cross_signing
Add migration state to bootstrap
2020-04-16 15:04:06 +02:00
Benoit Marty
828e972c74 Split long lines 2020-04-16 14:35:55 +02:00
Benoit Marty
15bd7d1c5b Change the regex to detect long lines to allow schema with UTF-8 chars 2020-04-16 14:35:23 +02:00
Benoit Marty
79e81dbdde ktlint 2020-04-16 14:01:15 +02:00
Benoit Marty
f93f50b582 Code readability 2020-04-16 14:00:24 +02:00
Benoit Marty
d934f92ebd Fix bad apostrophe 2020-04-16 13:58:54 +02:00
Waylon Cude
d20cf484ff Merge branch 'develop' of https://github.com/vector-im/riotX-android into develop
Signed-off-by: Waylon Cude <waylon.cude@finzdani.net>
2020-04-16 03:10:06 -07:00
Waylon Cude
ec4458e84a Updated CHANGES.md
Signed-off-by: Waylon Cude <waylon.cude@finzdani.net>
2020-04-16 02:50:58 -07:00
waylon531
6c1719e365 Use a bigger thread pool
This patch makes RiotX use an unbounded thread pool to handle
connections. The default thread pool for the android WorkManager has a
fairly anemic number of threads and I suspect this was causing
performance issues especially because of all the long-running jobs that
happen whenever you sync.

I tested this out on my phone and all of the sluggishness appears to
have gone away. I tested both the debug and release builds to make sure
it wasn't just some release optimization. RiotX is so much snappier now!

This fixes #1221

Signed-off-by: Waylon Cude <waylon.cude@finzdani.net>
2020-04-16 02:44:31 -07:00
Benoit Marty
467f48f1a6 Merge remote-tracking branch 'origin/develop' into develop 2020-04-16 11:33:22 +02:00
Valere
a44cb876c9 move strings to resources 2020-04-16 11:30:10 +02:00
Valere
e79c824913 Fix / password visibility initial state bug 2020-04-16 11:30:10 +02:00
Valere
b8e9cc70f2 fix / line too long 2020-04-16 11:30:10 +02:00
Valere
a2f32307f0 Support back from migrate recovery key 2020-04-16 11:30:10 +02:00
Valere
c1d39cefd5 Fix / avoid upgrade secu popup on account creation 2020-04-16 11:30:10 +02:00
Valere
0edc562120 Fix / test compilation 2020-04-16 11:30:10 +02:00
Valere
8ae2f06044 Add change log 2020-04-16 11:30:10 +02:00
Valere
aa496e6efb Add migration state to bootstrap 2020-04-16 11:30:10 +02:00
Benoit Marty
1372192031 Merge pull request #1091 from vector-im/feature/secure
Add a setting to prevent screenshot of the application, disabled by default (#1027)
2020-04-16 11:27:59 +02:00
Benoit Marty
ea03f76847 Merge pull request #1129 from vector-im/feature/update_password
Change password function implemented.
2020-04-16 11:26:33 +02:00
Benoit Marty
d74a5f9979 Typo 2020-04-16 11:23:41 +02:00
Benoit Marty
febadcc4f6 Merge pull request #1238 from vector-im/feature/thumbnail_info
`mimetype` field is optional
2020-04-16 10:57:29 +02:00
Benoit Marty
17ece54cb0 mimetype field is optional 2020-04-16 10:28:23 +02:00
Benoit Marty
da04a74350 Merge pull request #1143 from MatMaul/refresh-summary
Refresh the whole notifs when cleaning one so the summary get updated
2020-04-15 17:29:36 +02:00
Benoit Marty
634c8947bd Merge branch 'develop' into refresh-summary 2020-04-15 17:29:08 +02:00
Benoit Marty
f6f6fa99fb Merge pull request #1223 from vector-im/feature/cross_signing_as_task
Make initialize cross signing as a task
2020-04-15 17:21:25 +02:00
Benoit Marty
dcfbfc4981 Merge pull request #1230 from vector-im/feature/fix_download_file
Catch network errors during file downloading.
2020-04-15 16:54:31 +02:00
Benoit Marty
6201a9b8ef Merge branch 'develop' into feature/fix_download_file 2020-04-15 16:52:40 +02:00
Benoit Marty
1981d2e9ac Merge pull request #1233 from vector-im/feature/fix_local_echo_no_update
Fix / sending event not always updating
2020-04-15 16:51:16 +02:00
Benoit Marty
66f6b1ecac Merge pull request #1224 from vector-im/feature/composer_shield
Add shield in composer
2020-04-15 16:49:50 +02:00
Benoit Marty
affe2b59da Fix crash 2020-04-15 16:40:01 +02:00
Benoit Marty
757f8ec96a Change password: prevent cancellation when processing 2020-04-15 16:39:05 +02:00
Benoit Marty
bf5e2b96df Change password: bigger margins 2020-04-15 16:39:05 +02:00
Benoit Marty
5666965321 Change password: do not trim passwords 2020-04-15 16:39:05 +02:00
Benoit Marty
7bf1f916c4 Change password: lambda 2020-04-15 16:39:05 +02:00
Benoit Marty
d44e43d94b Change password: update wording of button (Nad's request) 2020-04-15 16:39:05 +02:00
Benoit Marty
9fe32fe915 Change password: hide the preference (as Riot-Web does) if it is not possible to change the password. 2020-04-15 16:39:05 +02:00
Benoit Marty
e21cb3082b Change password: update preference summary. Some people think we know the password. Using Riot-web wording 2020-04-15 16:39:05 +02:00
Benoit Marty
c50bc10f92 Code review: improve layout 2020-04-15 16:38:44 +02:00
Benoit Marty
1b416028b4 Code review: inline the error instead of using toast 2020-04-15 16:38:44 +02:00
Benoit Marty
85493b7532 Code review: use isInvalidPassword() extension everywhere. Also be robust if the Fragment is destroyed 2020-04-15 16:38:44 +02:00
onurays
dbabe0232f Do not override the default timeout. 2020-04-15 16:38:44 +02:00
onurays
dfc8e8ec4c AccountService is created. 2020-04-15 16:38:44 +02:00
onurays
f00db49bda Change password function implemented.
Fixes #528
2020-04-15 16:38:44 +02:00
onurays
b4a3eb2cb3 Fix return the exception instead of empty one. 2020-04-15 16:39:41 +03:00
Valere
81012746c4 Code review / added new key for message hint 2020-04-15 15:39:23 +02:00
Valere
1deacfbb34 Code review 2020-04-15 15:37:43 +02:00
Valere
c35d854776 Add shield in composer 2020-04-15 15:37:43 +02:00
Benoit Marty
c0fa259b40 Add a setting to prevent screenshot of the application, disabled by default (#1027) 2020-04-15 15:04:19 +02:00
Benoit Marty
391d3cb6b5 Merge pull request #1186 from duncanturk/improvement-957-catchup-indicator-on-invite
Fix #957 catchup indicator on invite
2020-04-15 15:02:16 +02:00
Benoit Marty
6d56220d98 Merge branch 'develop' into improvement-957-catchup-indicator-on-invite 2020-04-15 15:00:34 +02:00
Benoit Marty
c57fa3f0d0 Merge pull request #1176 from vector-im/feature/target-sdk-29
Increase targetSdk to 29
2020-04-15 14:32:16 +02:00
Benoit Marty
f2bca51046 Merge pull request #1232 from vector-im/feature/translations
string sync
2020-04-15 14:24:39 +02:00
Benoit Marty
6751d88ade Remove .idea exclusion 2020-04-15 13:00:03 +02:00
Benoit Marty
e26a0bc9ae Add Android SDK version 2020-04-15 12:57:15 +02:00
Benoit Marty
6dc517584f Fix merge issue 2020-04-15 12:56:33 +02:00
Benoit Marty
24d0cdef1f Add missing changes of SDK version and build tools 2020-04-15 12:53:28 +02:00
Benoit Marty
6639f89a68 Simpler code 2020-04-15 12:53:08 +02:00
onurays
0ef5ae38d0 Merge branch 'feature/cross_signing_as_task' into feature/sqldelight_crypto_store 2020-04-15 11:16:29 +03:00
Benoit Marty
0c0e9521f5 Fix lint issue 2020-04-15 09:50:25 +02:00
Valere
f2b684aa9e Fix / user and self signing failing
bad copy paste
2020-04-14 18:23:20 +02:00
Valere
68ca0e9d4b Fix / sending event not always updating 2020-04-14 17:35:11 +02:00
Benoit Marty
e54077e020 String copied to Riot project 2020-04-14 17:26:23 +02:00
Benoit Marty
9111800e7a Create specific string for RiotX 2020-04-14 17:23:59 +02:00
Benoit Marty
ef6847671a Import strings from Riot 2020-04-14 17:13:43 +02:00
Benoit Marty
b8cb0588fe Add new resources 2020-04-14 17:06:05 +02:00
onurays
667b371653 Continue supporting old APIs. 2020-04-14 16:29:11 +03:00
onurays
190fbb95ec Merge branch 'develop' into feature/target-sdk-29
# Conflicts:
#	vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt
2020-04-14 13:59:54 +03:00
onurays
f97e08b4e5 Remove .gitignore which belongs to another PR. 2020-04-14 13:12:17 +03:00
onurays
7242cbda40 Catch network errors during file downloading.
Fixes #1229
2020-04-13 17:48:19 +03:00
onurays
c53f9359d7 Use json (de)serializer instead of object (de)serialization. 2020-04-13 13:43:39 +03:00
Valere
9e3011d4c8 Make initialize cross signing as a task 2020-04-10 17:04:34 +02:00
Valere
eb50256af7 Merge pull request #1222 from vector-im/feature/verification_unified_emoji
Uniform emoji representation for all platform
2020-04-10 16:05:42 +02:00
Valere
ccacd20428 Merge branch 'develop' into feature/verification_unified_emoji 2020-04-10 16:05:33 +02:00
Valere
ac46fe9e16 Merge pull request #1218 from vector-im/feature/scan_confirm_update
Feature/scan confirm update
2020-04-10 16:05:02 +02:00
Valere
9cfb83f0d2 Remove outdated translation 2020-04-10 14:31:03 +02:00
Valere
943ba3bebd Fix / string bad argument number - lint 2020-04-10 13:14:12 +02:00
Valere
fccfd00949 Fix / design update 2020-04-10 12:12:21 +02:00
Valere
68323057aa Update change log 2020-04-10 12:12:21 +02:00
Valere
5081361c2d Update Scan confirm flow 2020-04-10 12:12:06 +02:00
Valere
3ba619d45c Merge pull request #1215 from vector-im/feature/ssss_and_backup
Fixes #1214
2020-04-10 12:10:42 +02:00
Valere
f5dc0b38ff Code review 2020-04-10 11:47:54 +02:00
Valere
8357abd455 Added prefix to resources to avoid accidental override 2020-04-10 11:18:41 +02:00
Valere
ede899d78e Fix / Bad smiley emojii 2020-04-10 11:09:16 +02:00
Valere
a703574004 Uniform emoji representation for all platform 2020-04-10 11:02:33 +02:00
onurays
09c98c32f0 Check and insert metadata at init. 2020-04-09 18:49:10 +03:00
onurays
fc90844556 Check and insert metadata at init. 2020-04-09 18:48:46 +03:00
onurays
0ca7e6202c Use json (de)serializer instead of object (de)serialization. 2020-04-09 16:15:34 +03:00
Christopher Rossbach
ef2abbfbd4 Merge branch 'develop' into improvement-957-catchup-indicator-on-invite 2020-04-09 11:11:44 +02:00
Valere
7c0137e2dc Fix / await callback suspend forever 2020-04-09 10:46:52 +02:00
onurays
96162218e4 Lint fixes. 2020-04-09 02:40:43 +03:00
onurays
ffaacdf436 Use SqlCryptoStore implementation instead of RealmCryptoStore. 2020-04-09 02:30:52 +03:00
onurays
39fdda3715 Realm entities removed. 2020-04-09 00:52:01 +03:00
Valere
34dec64d9c Fixes #1214 2020-04-08 17:56:12 +02:00
Valere
3968bb3488 Merge pull request #1213 from vector-im/feature/timeline_sum_item
Feature/timeline sum item
2020-04-08 17:08:53 +02:00
onurays
af171b3b7e Complete storing user cross signing key function. 2020-04-08 18:05:07 +03:00
Valere
6f2d7aebba code review 2020-04-08 16:37:52 +02:00
Valere
366a35913b Fix alignement 2020-04-08 16:31:01 +02:00
Valere
aec49fe542 Change log 2020-04-08 16:31:01 +02:00
Valere
f04d8b0e03 cleaning 2020-04-08 16:31:01 +02:00
Valere
08af61b778 rename layout 2020-04-08 16:31:01 +02:00
Valere
277f35a352 Merge room creation events in one summary 2020-04-08 16:31:01 +02:00
Valere
68512e475f WIP 2020-04-08 16:31:01 +02:00
Valere
0eff00ebee Merge pull request #1211 from vector-im/feature/fix_gossiping_to_early
Fix / Send gossip request on other done received
2020-04-08 16:30:17 +02:00
onurays
3dd9693f59 Changelog added. 2020-04-08 15:32:14 +03:00
Onuray Sahin
8a4a288074 Merge branch 'develop' into feature/target-sdk-29 2020-04-08 14:15:02 +03:00
onurays
5b1f887760 Code review fixes. 2020-04-08 14:10:31 +03:00
onurays
dcb6af6c45 .gitignore file added. 2020-04-08 12:40:29 +03:00
onurays
8b0845a76b Key backup recovery key fields added to metadata. 2020-04-08 11:08:15 +03:00
onurays
8e896600c9 Initial implementation of SQLDelight CryptoStore. 2020-04-08 10:33:06 +03:00
Christopher Rossbach
3ff5952417 Merge branch 'develop' into improvement-957-catchup-indicator-on-invite 2020-04-07 20:53:31 +02:00
Valere
b480eb3688 Update change log 2020-04-07 19:20:49 +02:00
Valere
12abca1b80 Fix / Send gossip request on other done received 2020-04-07 19:09:56 +02:00
Valere
1d8ed387bc Merge pull request #1206 from vector-im/feature/gossip_keybackup_key
Feature/gossip keybackup key
2020-04-07 18:06:05 +02:00
Christopher Rossbach
5521c094f7 fix typing difference 2020-04-07 17:50:01 +02:00
Christopher Rossbach
222b72a014 Merge branch 'develop' into improvement-957-catchup-indicator-on-invite 2020-04-07 17:46:23 +02:00
Valere
8904ca27f2 clean 2020-04-07 15:30:19 +02:00
Valere
6c5da97c16 code review 2020-04-07 15:25:31 +02:00
Valere
d4d73db5ae keybackup gossip test 2020-04-07 15:15:45 +02:00
Valere
1a436f962f update change log
cleaning
2020-04-07 15:15:45 +02:00
Valere
dc61ee61f5 Fix / wrong export format 2020-04-07 15:15:45 +02:00
Valere
5b4b5e7a57 Gossip keybackup key after verification! 2020-04-07 15:15:45 +02:00
Valere
0164f94047 Merge pull request #1198 from vector-im/feature/crosssigning_bootstrap
Feature/crosssigning bootstrap
2020-04-07 15:14:54 +02:00
Valere
153587bd82 Merge branch 'develop' into feature/crosssigning_bootstrap 2020-04-07 15:14:43 +02:00
Valere
326f2e99fb klint 2020-04-06 10:00:59 +02:00
Valere
1dfd6f232a Code quality / line too long 2020-04-03 18:59:21 +02:00
Valere
42d61944b5 Merge pull request #1204 from vector-im/feature/increase_file_log_size
Increase file logger size
2020-04-03 16:40:18 +02:00
Valere
50a8ffeca1 Merge pull request #1203 from vector-im/feature/fix_e2e_null_alg
Feature/fix e2e null alg
2020-04-03 15:57:56 +02:00
Valere
f605bb8270 Code review 2020-04-03 15:57:05 +02:00
Valere
7ffb6113a4 Increase file logger size 2020-04-03 13:53:34 +02:00
Valere
156e6114c1 Updade change log 2020-04-03 13:43:40 +02:00
Valere
c91bc82cd9 Fix / Ensure encryption set even if faield to fetch members 2020-04-03 13:35:09 +02:00
Valere
8b481e2294 Remove dead code 2020-04-03 13:34:38 +02:00
Valere
92bf3f1349 Update change log
+ code quality
2020-04-03 11:14:14 +02:00
Valere
6474735662 Fix / devtools was not showing all json numbers 2020-04-03 10:31:44 +02:00
Valere
45c5626267 Add generate key option 2020-04-02 18:30:43 +02:00
Valere
c27264761d Back /Skip navigation 2020-04-02 18:11:52 +02:00
Valere
c6abfa14ea Fix / Bind continue button 2020-04-02 16:54:30 +02:00
Valere
2f237cf17b klint 2020-04-02 16:51:40 +02:00
Valere
bf5ba99653 Full bootstrap flow initial commit 2020-04-02 16:51:03 +02:00
Valere
8ecdac7c31 Fixes #1191 2020-03-31 17:08:11 +02:00
Valere
a40dd31543 Bootstrap bottomsheet 2020-03-27 17:09:18 +01:00
Christopher Rossbach
dff89cb2e1 document changes
Signed-off-by: Christopher Rossbach <31703168+duncanturk@users.noreply.github.com>
2020-03-27 14:41:48 +01:00
Christopher Rossbach
cdbb657961 Fix #957 by incrementing the catchup count on home icon.
Signed-off-by: Christopher Rossbach <31703168+duncanturk@users.noreply.github.com>
2020-03-27 14:24:42 +01:00
Onuray Sahin
443d45db6a Merge branch 'develop' into feature/target-sdk-29 2020-03-27 12:21:39 +03:00
Valere
a995615f87 Fix / protect against crash during migration 2020-03-26 18:20:12 +01:00
Valere
024c62515c Merge pull request #1181 from vector-im/feature/update_shield_logic
Update shield logic for DM
2020-03-26 16:58:10 +01:00
Valere
75e66a6550 Merge branch 'develop' into feature/update_shield_logic 2020-03-26 16:58:01 +01:00
Onuray Sahin
e2f7890bb8 Merge branch 'develop' into feature/target-sdk-29 2020-03-26 17:39:22 +03:00
onurays
0a77d5014e Fix nullability issues. 2020-03-26 17:19:29 +03:00
Valere
91464a071e Merge pull request #1180 from vector-im/feature/complete_security_design_update
Feature/complete security design update
2020-03-26 14:31:09 +01:00
Valere
5244612ef6 Update shield logic for DM 2020-03-26 14:26:34 +01:00
Valere
e51439ade0 updage change log 2020-03-26 14:10:19 +01:00
Valere
acd90657c7 Fix / prevent cancel when in conclusion fragment 2020-03-26 14:09:41 +01:00
onurays
e5482d48c0 Remove deprecated & unused ImageTools class. 2020-03-26 16:02:50 +03:00
onurays
5816a04a37 Use MediaStore instead of deprecated addCompletedDownload since Android Q. 2020-03-26 15:58:31 +03:00
onurays
4b7da9ae6b Replace deprecated getExternalStoragePublicDirectory with getExternalFilesDir. 2020-03-26 15:57:21 +03:00
onurays
f7cbc01023 Replace deprecated PreferenceManager with androidx version. 2020-03-26 15:56:33 +03:00
Valere
1de57bbf3b Fix / cancel copy when verifying other 2020-03-26 13:49:48 +01:00
Valere
42a8c561db Fix / Verification was not cancelled on back in ready state 2020-03-26 13:49:48 +01:00
Valere
5bef9aef6a Fix / add specific copy for other verif cancel confirm 2020-03-26 13:49:48 +01:00
Valere
f8c1ec985f re-prompt to verify on restart 2020-03-26 13:49:48 +01:00
onurays
12429d8091 Merge develop into the branch. 2020-03-26 14:39:50 +03:00
Onuray Sahin
3bb5e127d6 Merge pull request #1155 from vector-im/feature/multipicker
Multiple attachment picker implementation
2020-03-26 14:30:02 +03:00
Valere
1d46b523b9 Merge pull request #1172 from vector-im/feature/ensure_olm_account_unicity
Feature/ensure olm account unicity
2020-03-26 12:11:09 +01:00
Valere
6721f337bd Merge branch 'develop' into feature/ensure_olm_account_unicity 2020-03-26 12:11:00 +01:00
Valere
535cdf0ef5 Merge pull request #1162 from vector-im/feature/xs_detect_new_session
Feature/xs detect new session
2020-03-26 12:06:18 +01:00
Valere
19990b27bb Code review 2020-03-26 10:52:02 +01:00
Valere
4b3c5d5135 update change log 2020-03-26 10:35:43 +01:00
Valere
b6fe80faf4 Fix / device key could be rotated
MXOlmDevice constructor access IMXStore before is open (dagger)
2020-03-26 10:35:43 +01:00
Valere
638970fa77 Merge pull request #1175 from vector-im/feature/fix_ssss_symetric_get_secret
Fixes #1174
2020-03-26 10:34:49 +01:00
onurays
c63f3edb06 Initial fixes to support targetSdk 29. 2020-03-26 12:06:50 +03:00
Valere
9a6fe1af4e Fixes #1174 2020-03-26 09:49:34 +01:00
onurays
a01482dca4 Use Timber log instead of printStackTrace. 2020-03-25 18:51:55 +03:00
onurays
5db1010e47 Catch exceptions if the file cannot be decoded. 2020-03-25 18:39:35 +03:00
onurays
6130a0a654 Remove unused toString(). 2020-03-25 18:34:04 +03:00
onurays
3c1e1090e7 Avoid UNCHECKED_CAST. 2020-03-25 18:20:34 +03:00
onurays
5cb47dae35 Return a failure message if the file cannot be opened. 2020-03-25 18:03:20 +03:00
onurays
f68e98b2c7 Do not resize video thumbnail. 2020-03-25 17:35:18 +03:00
Valere
420a55da76 klint 2020-03-25 13:53:06 +01:00
onurays
f9aed28732 grantUriPermission to handle incoming sharing. 2020-03-25 15:51:15 +03:00
Valere
e30c17eab7 Update Changes log 2020-03-24 18:09:54 +01:00
Valere
2c9a8865bf Cancel all on going to settings 2020-03-24 17:48:16 +01:00
Valere
bddd70afdb Fix / IllegalState after token invalidation 2020-03-24 17:48:01 +01:00
Valere
c4388348f7 Show cancelled screen instead of dismissing 2020-03-24 17:38:46 +01:00
Valere
ee7828a445 Code quality 2020-03-24 16:21:22 +01:00
Valere
37ac45c90a Fix / handling of back 2020-03-24 15:51:09 +01:00
Valere
63d3bf93f2 Fix / for now keep old toaster 2020-03-24 15:50:49 +01:00
Valere
2de8865730 Fix / Key Request recipients 2020-03-24 15:49:41 +01:00
Valere
fcffe1f3c3 Clear alert when device is verified 2020-03-24 15:21:03 +01:00
Valere
cfcec04029 code cleaning 2020-03-24 14:57:51 +01:00
Valere
b56a41bec7 Custom alert design 2020-03-24 14:56:57 +01:00
onurays
6bf89aeac9 Remove JPEG_ prefix from file name. 2020-03-24 12:37:37 +03:00
onurays
e583c03751 Add documentation. 2020-03-24 12:32:37 +03:00
onurays
d20b1cb64a Add documentation. 2020-03-24 12:15:14 +03:00
Valere
22642e71a3 cleaning 2020-03-24 10:06:36 +01:00
Valere
6e85b20b0e Update copy for riotX default device Name 2020-03-24 10:06:30 +01:00
Valere
fcd290410e Also cancel pending request on back 2020-03-24 10:06:15 +01:00
onurays
727d86236b ImageUtils created with helper functions. 2020-03-24 11:31:27 +03:00
onurays
2651f82337 Refactor duplicated code. 2020-03-24 11:03:41 +03:00
Valere
3b62402cfe Fix / ensure keys trust is updated before checking devices 2020-03-23 19:15:29 +01:00
Valere
6cc8d1b205 Fix / concurrent start broke QR verification 2020-03-23 18:43:52 +01:00
Valere
49e5fafb2d New sign in detection flow 2020-03-23 16:27:32 +01:00
Valere
e36367c040 Fix / sending secret encryption + refactoring 2020-03-23 16:27:17 +01:00
onurays
f7fd23b153 App integration to the new multipicker library. 2020-03-23 16:31:32 +03:00
Valere
4f70c40b1a Refactor + share secret window implementation 2020-03-23 11:13:33 +01:00
onurays
5b875e0571 CameraPicker & incoming share implementation. 2020-03-22 18:27:59 +03:00
onurays
6db0de321c Initial implementation of multipicker. 2020-03-20 12:12:59 +03:00
Valere
0c1f30208d Fix / Epoxy divider not showing 2020-03-19 11:23:15 +01:00
Valere
08cfe79625 Merge pull request #1153 from vector-im/feature/fix_841
Fixes #841
2020-03-18 14:50:56 +01:00
Valere
22a599633d Merge pull request #1152 from vector-im/feature/concurrent_start_verification
Verif / handle concurrent start
2020-03-18 14:50:33 +01:00
Valere
14acbb2b4d Update changes 2020-03-18 12:06:37 +01:00
Valere
6f5bebedf8 Fixes #841 2020-03-18 11:53:38 +01:00
Valere
6fe77eba72 code review 2020-03-18 11:25:49 +01:00
Valere
286a5081ff Verif / handle concurrent start
Fixes #794
2020-03-18 10:07:57 +01:00
Valere
56c241c9bd Merge pull request #1140 from vector-im/feature/gossiping_work
Feature/gossiping work
2020-03-17 15:48:11 +01:00
Valere
68151d838f Update changes 2020-03-17 15:10:27 +01:00
Valere
572b174cfe code quality 2020-03-17 14:42:55 +01:00
Valere
b71d8185a2 Fix / gossiping sent to soon results in not getting keys
Overall improovment of logs
2020-03-17 14:40:05 +01:00
Valere
8051d9e3be cleaning 2020-03-17 14:40:05 +01:00
Valere
1bf8fef292 Fix realm migration 2020-03-17 14:40:05 +01:00
Valere
b8a9397e73 hide reRequest behind developer mode 2020-03-17 14:40:05 +01:00
Valere
009d691d5b post merge fix 2020-03-17 14:40:05 +01:00
Valere
6933159245 Remove refresh menu 2020-03-17 14:40:05 +01:00
Valere
75549c41e0 View source in audit + clean 2020-03-17 14:40:05 +01:00
Valere
5e2f888eaf Request secret from mobile to web 2020-03-17 14:40:05 +01:00
Valere
d3d6d44665 Post rebase fix 2020-03-17 14:40:05 +01:00
Valere
fc6225a7ac Gossiping refactoring 2020-03-17 14:40:05 +01:00
Valere
3639007985 Cancel transaction if failed to decrypt other part events 2020-03-17 14:40:05 +01:00
Valere
d5137897c1 Fix / crash No JsonAdapter for GossipingToDeviceObject 2020-03-17 14:40:05 +01:00
Valere
b67735c31a Incoming Secret Share request support
crypto DB migration
2020-03-17 14:40:05 +01:00
Valere
8ff31ac49d cleaning klint 2020-03-17 14:40:05 +01:00
Valere
5e0235e48d Add option to recover from backup + hide if not applicable 2020-03-17 14:40:05 +01:00
Valere
9e63a3219c Add Re-Request keys for fail to decrypt 2020-03-17 14:40:05 +01:00
Valere
757e90986e Key Req Dev tool initial commit 2020-03-17 14:40:05 +01:00
Valere
06fc5c2dd9 Log tunning 2020-03-17 14:40:05 +01:00
Valere
20dbe2dd0d version ++ 2020-03-17 14:18:08 +01:00
Valere
6f56c74e9d Merge branch 'release/0.18.1' into develop 2020-03-17 11:46:55 +01:00
Valere
78d90c8f04 prepare release 0.18.1 2020-03-17 11:46:42 +01:00
Valere
75fa2904d3 Merge pull request #1149 from vector-im/feature/quick_fix_backup_update_banner
QuickFix / key banner not clickable
2020-03-17 11:12:43 +01:00
Valere
a9ed55e6a2 Fixes #757 2020-03-17 10:50:34 +01:00
Valere
b37600f536 QuickFix / key banner not clickable 2020-03-17 10:43:48 +01:00
Valere
ef2783e9f4 Merge pull request #1142 from vector-im/feature/fix_upload_error
Fix / correctly update local echo failed state
2020-03-17 09:48:43 +01:00
Valere
8827b4b5ef Fix / correctly update local echo failed state
+ endure Workmanager queues are reset after a clear cache
2020-03-17 09:47:27 +01:00
Valere
7664b716b3 Merge pull request #1146 from vector-im/feature/workaround_crash_select_gif_keyboard
WorkAround / crash android 10 gif from keyboard
2020-03-17 09:20:49 +01:00
Valere
067a22883c WorkAround / crash android 10 gif from keyboard
fixes #1136
2020-03-16 16:01:55 +01:00
Valere
eb74523905 Fix / typo 2020-03-16 15:30:41 +01:00
Valere
18d82b1bea Merge pull request #1138 from vector-im/feature/join_command
Implementation of /join command (#12)
2020-03-16 10:15:25 +01:00
Mathieu Velten
687884431e Refresh the whole notifs when cleaning one so the summary get updated
Fix summary notification staying after "mark as read"
2020-03-13 23:42:28 +01:00
Valere
3c9c2e61d7 missing change log entry 2020-03-13 17:19:00 +01:00
onurays
e3246a1f2c Rename JoinedToAnotherRoom to JoinRoomCommandSucces. 2020-03-13 18:41:04 +03:00
Valere
642651a069 Merge pull request #1133 from vector-im/feature/quick_fix_redecrypt_remote_echo
Fix Message transitions in encrypted rooms
2020-03-13 12:18:59 +01:00
onurays
85a987ca8d Fix typo. 2020-03-13 14:02:42 +03:00
onurays
5cb7e455b1 Implementation of /join command. 2020-03-13 14:00:46 +03:00
Valere
7c1428e097 preserver relations as non encrypted 2020-03-12 10:05:55 +01:00
Valere
32fd4c1be9 save decryption result at encryption 2020-03-11 19:39:40 +01:00
Valere
f53fc205e1 Fix Message transitions in encrypted rooms
Fixes #518
2020-03-11 18:07:18 +01:00
Valere
54eca7525e Version ++ 2020-03-11 16:24:49 +01:00
Valere
005a11b765 Merge branch 'release/0.18.0' into develop 2020-03-11 13:41:48 +01:00
Valere
d5cbcdd4e7 prepare release 0.18.0 2020-03-11 13:41:17 +01:00
Valere
fe1af4e34f Merge pull request #1131 from vector-im/feature/fix_qr_self_verification
Fix / Self verification mode 1 was not working
2020-03-11 13:19:16 +01:00
Valere
49f2064439 Fix / Self verification mode 1 was not working 2020-03-11 11:43:23 +01:00
Valere
ff5b284b2e Try to remove rule that is breaking CI 2020-03-11 11:19:22 +01:00
Valere
d9085b1231 Merge pull request #1128 from vector-im/feature/remove_runblocking_crypto
Remove dangerous runBlocking (and un-needed)
2020-03-11 10:42:48 +01:00
Valere
a9074cdbbb Remove dangerous runBlocking (and un-nedded) 2020-03-10 17:25:04 +01:00
Benoit Marty
09946ecf1b Merge pull request #1117 from vector-im/feature/pusher_fix
Pusher fix
2020-03-10 11:34:11 +01:00
Benoit Marty
d21a536542 Merge pull request #1115 from vector-im/feature/work_manager_script
Add script to dumpsys work manager data
2020-03-06 17:31:19 +01:00
Benoit Marty
937d497a1f Revert the check box in case of error 2020-03-06 17:24:57 +01:00
Benoit Marty
4261b0e78a Fix pusher issue. It was set by mistake when the notification for this device was disabled 2020-03-06 17:19:48 +01:00
Benoit Marty
71446a1a74 Remove useless check 2020-03-06 17:11:23 +01:00
Benoit Marty
a29ec7b0be Pusher: add a menu to force a refresh of the local data 2020-03-06 16:48:48 +01:00
Benoit Marty
13036a5933 Pusher: update javadoc 2020-03-06 16:37:13 +01:00
Benoit Marty
a8e19f3cc9 Understanding things 2020-03-06 15:57:49 +01:00
Benoit Marty
cb4752812a Hide private key 2020-03-06 15:53:55 +01:00
Benoit Marty
ccd9d2961d Cleanup 2020-03-06 15:45:39 +01:00
Benoit Marty
d1db17f244 Add doc on workers 2020-03-06 15:45:26 +01:00
Benoit Marty
aa4327c4da Add doc and log error from the workers 2020-03-06 15:44:55 +01:00
Benoit Marty
35179509f2 Merge pull request #1111 from vector-im/feature/verification_code
Feature/verification code
2020-03-06 15:02:57 +01:00
Benoit Marty
5008524635 Add script to dumpsys work manager data 2020-03-06 14:52:09 +01:00
Benoit Marty
147766176c Merge pull request #1090 from vector-im/feature/notif
Restore the push rule settings
2020-03-06 14:43:33 +01:00
Benoit Marty
23862cb3d0 Merge branch 'develop' into feature/notif 2020-03-06 14:43:23 +01:00
Benoit Marty
2b8e2a312b Avoid use toImmutableList() 2020-03-06 14:39:33 +01:00
Benoit Marty
62fdb4c27a Use getOrPut() 2020-03-06 14:37:30 +01:00
Benoit Marty
b929a2f185 Merge pull request #1099 from vector-im/feature/fix_share_image
Share images from clear and encrypted rooms.
2020-03-06 14:27:47 +01:00
Benoit Marty
fb858bc112 Rename to respect naming convention #3 2020-03-06 14:04:02 +01:00
Benoit Marty
5d0e917f04 Rename to respect naming convention #2 2020-03-06 13:50:00 +01:00
Benoit Marty
e420070066 Rename to respect naming convention 2020-03-06 13:40:35 +01:00
Benoit Marty
4504308f25 Less "!!" 2020-03-06 13:34:12 +01:00
onurays
05683967c0 Code review fixes. 2020-03-06 12:07:38 +01:00
Benoit Marty
23c20acff1 Remove TODO 2020-03-06 10:11:30 +01:00
Benoit Marty
be5e6eaa93 Rename parameter type for code clarity 2020-03-06 10:10:16 +01:00
Onuray Sahin
555863fecc Merge pull request #1112 from vector-im/feature/navigate_to_profile_from_avatar
Open room member profile from avatar of the room member state event.
2020-03-06 09:42:32 +01:00
onurays
b187699a86 Open room member profile from avatar of the room member state event. 2020-03-05 18:44:34 +01:00
Benoit Marty
d891da39e6 Merge pull request #1104 from vector-im/feature/buildkite
Pipeline file for Buildkite is now hosted on another Github repository
2020-03-05 18:20:17 +01:00
Benoit Marty
f37cd8cddc Merge pull request #1110 from vector-im/feature/cleanup
Cleanup
2020-03-05 18:18:49 +01:00
Benoit Marty
2d456d93a7 Common code step 2 2020-03-05 18:16:05 +01:00
Benoit Marty
de36a28541 Common code step 1 2020-03-05 18:00:35 +01:00
Benoit Marty
4634b963a2 Code cleanup 2020-03-05 17:55:13 +01:00
Benoit Marty
b3f887ca28 Code quality 2020-03-05 17:30:34 +01:00
Benoit Marty
3425dd0a63 Make the tests compile and pass 2020-03-05 17:28:35 +01:00
Benoit Marty
2a774833ec More optimization 2020-03-05 17:11:52 +01:00
Benoit Marty
bda4bbb59c More optimization 2020-03-05 16:45:49 +01:00
Benoit Marty
0828f9270e Create asValidObject method - make it works 2020-03-05 16:23:56 +01:00
Benoit Marty
e326631752 Create asValidObject method - make it compiles #2 2020-03-05 15:39:01 +01:00
Benoit Marty
a3f8a53a52 Create asValidObject method - make it compiles. 2020-03-05 15:29:44 +01:00
Benoit Marty
7b5a50ec6e Create asValidObject method - not compiling 2020-03-05 12:06:19 +01:00
Benoit Marty
36c52d24a7 Move method to interface step 3 2020-03-05 11:24:35 +01:00
Benoit Marty
1b29c7bf91 Move method to interface step 2 2020-03-05 11:22:42 +01:00
Benoit Marty
b6aee04e24 Move method to interface step 1 2020-03-05 11:21:44 +01:00
Benoit Marty
a264dcf5c4 Lint: fix TextFields 2020-03-05 11:09:58 +01:00
Benoit Marty
37afc983c3 Fix typos. The typos has been fixed on Weblate by me. 2020-03-05 11:02:14 +01:00
Benoit Marty
b10e9c54b4 Add BinaryOperationInTimber lint rule and fix existing errors 2020-03-05 10:40:36 +01:00
onurays
03d2cd0639 Lint fix. 2020-03-04 17:57:57 +01:00
onurays
b7ad50a3ce Make mimeType private to encourage using getSafeMimeType() method. 2020-03-04 16:52:52 +01:00
onurays
9cbaadedfb Unused context parameter is removed. 2020-03-04 16:52:08 +01:00
Benoit Marty
d6cdcc60d1 Remove unused png files 2020-03-04 16:48:13 +01:00
Onuray Sahin
1680cd8d8e Merge branch 'develop' into feature/fix_share_image 2020-03-04 16:27:01 +01:00
onurays
d4384328fe Use "image/jpeg" instead of "image/jpg" 2020-03-04 16:26:09 +01:00
Benoit Marty
5fd8425289 Remove unused files 2020-03-04 16:09:37 +01:00
Benoit Marty
dcb618c257 Merge pull request #1103 from vector-im/feature/space_in_passwords
Detect spaces in password if user fails to login (#1038)
2020-03-04 14:12:20 +01:00
Benoit Marty
277ad9e042 Merge branch 'develop' into feature/space_in_passwords 2020-03-04 14:12:12 +01:00
onurays
26d387cc12 Support sharing other media types. 2020-03-04 13:47:48 +01:00
Benoit Marty
4aebe6d303 Disable TravisCI checks, now done by Buildkite 2020-03-04 12:23:25 +01:00
Benoit Marty
7eccda6e25 Pipeline file for Buildkite is now hosted on another Github repository
https://github.com/matrix-org/pipelines/blob/master/riotx-android/pipeline.yml
2020-03-04 12:20:09 +01:00
Benoit Marty
78bc2bbaa5 AndroidStudio cleanup 2020-03-04 12:15:33 +01:00
Benoit Marty
cde068f267 Merge pull request #1079 from vector-im/feature/ftue
FTUE: do not display a different color when encrypting message when not in developer mode.
2020-03-04 12:14:24 +01:00
Benoit Marty
c8f43e73e2 Merge branch 'develop' into feature/ftue 2020-03-04 12:14:07 +01:00
Benoit Marty
f106f92d7e Merge pull request #1085 from vector-im/feature/ktlint_upgrade
ktlint 0.36.0, Chromebook support, Camera for QR code scanning
2020-03-04 12:11:19 +01:00
Benoit Marty
fa0e07e146 Merge branch 'develop' into feature/ktlint_upgrade 2020-03-04 12:10:56 +01:00
Benoit Marty
d6df0e451c Detect spaces in password if user fail to login (#1038) 2020-03-04 10:39:10 +01:00
Benoit Marty
0121eee5b8 changelog 2020-03-04 09:37:32 +01:00
Benoit Marty
30e46445ca Add documentation to install environment and run integration tests (#1098)
Add documentation to install environment and run integration tests
2020-03-04 09:35:09 +01:00
onurays
7158554ee2 Add fallback logic only if the mode is thumbnail. 2020-03-03 16:56:22 +01:00
onurays
34c5537436 Fix fallback to full image. 2020-03-03 16:42:33 +01:00
onurays
d09ac8fbce Try to show full image as the fallback of the thumbnail. 2020-03-03 14:54:05 +01:00
onurays
319667096f Return Try.Failure instead of throwing exception. 2020-03-03 13:41:40 +01:00
onurays
c4f2eeeab7 Changelog added. 2020-03-03 10:40:58 +01:00
onurays
5f14516dec Share images from clear and encrypted rooms. 2020-03-03 10:39:24 +01:00
Benoit Marty
5ff670b184 Merge pull request #1093 from vector-im/feature/plain_text
Add support for `/plain` command (#12)
2020-03-02 19:37:05 +01:00
Benoit Marty
b7ff546f66 Add support for /plain command (#12) 2020-03-01 09:59:00 +01:00
Benoit Marty
c13b636bae Code cleanup 2020-02-29 10:05:48 +01:00
Benoit Marty
a05caf6f0e Update the 2 notification settings screens by moving some pref to the root notification screen 2020-02-29 09:49:21 +01:00
Benoit Marty
3462df405c Fix GPlay build issue 2020-02-29 09:42:35 +01:00
Benoit Marty
6009026e2f Notification settings: create a category for troubleshhot 2020-02-29 09:35:26 +01:00
Benoit Marty
06e0af9a5b small mistake 2020-02-28 22:12:30 +01:00
Benoit Marty
3987a68a9a Changelog 2020-02-28 22:10:07 +01:00
Benoit Marty
1228fcda0d Rename class 2020-02-28 19:25:29 +01:00
Benoit Marty
c20de4feb0 Cleanup 2020-02-28 19:13:22 +01:00
Benoit Marty
957b9eee23 Cleanup 2020-02-28 19:06:26 +01:00
Benoit Marty
e5eb36e917 Cleanup 2020-02-28 19:04:30 +01:00
Benoit Marty
551604cdcb Add missing push rules 2020-02-28 19:02:13 +01:00
Benoit Marty
8a2bafec5f Restore push rule settings - fix issues 2020-02-28 18:35:51 +01:00
Benoit Marty
3013e311a4 Restore push rule settings - WIP 2020-02-28 16:51:11 +01:00
Benoit Marty
1c35d07acc PushRuleService.getPushRules() now returns a RuleSet. Use getAllRules() on this object to get all the rules. 2020-02-28 16:29:58 +01:00
Benoit Marty
039924436f Json parsing 2020-02-28 14:51:35 +01:00
Benoit Marty
41b4f412c4 Merge pull request #1089 from vector-im/feature/crash_in_attachment_preview
Fix crash on attachment preview screen (#1088)
2020-02-28 14:49:36 +01:00
Benoit Marty
2abe29300b Merge pull request #1087 from vector-im/feature/verification_cleanup
Verification cleanup
2020-02-28 14:48:27 +01:00
Valere
779026b0af Fix / mark master key as trusted after self verif 2020-02-28 11:46:32 +01:00
Benoit Marty
151fec5ce0 Fix crash on attachment preview screen (#1088) 2020-02-28 11:38:30 +01:00
Benoit Marty
b1b8513da4 Create fromBase64Safe() to parse data received from external source 2020-02-27 19:17:14 +01:00
Benoit Marty
0a9008a73d Be robust if other client sends padded base64 in the reciprocate 2020-02-27 18:35:05 +01:00
Benoit Marty
1ead2778c2 ... and rename the method fromBase64NoPadding() to fromBase64() 2020-02-27 18:33:57 +01:00
Benoit Marty
8299487f6d Avoid using encoder flag to decode Base64 string... 2020-02-27 18:13:42 +01:00
Benoit Marty
ceab0903cf Improve code - TU passed 2020-02-27 18:09:37 +01:00
Benoit Marty
77dd911054 Code quality 2020-02-27 17:42:25 +01:00
Benoit Marty
a914381090 Verification with QrCode: ensure there is a Camera to scan QrCodes. 2020-02-27 17:03:48 +01:00
Benoit Marty
9f28738fd6 Restore availability to Chromebooks (#932) 2020-02-27 15:41:35 +01:00
Benoit Marty
36a848471f Enable other lint check (no change necessary in source) 2020-02-27 15:27:46 +01:00
Benoit Marty
12861aacda lint: check negative margin 2020-02-27 15:11:43 +01:00
Benoit Marty
d85776297d Lint: fix IconDuplicates by remove unused resources 2020-02-27 14:56:18 +01:00
Benoit Marty
50031bef50 Lint: fix IconDipSize and IconDuplicatesConfig error (by removing unused resource) 2020-02-27 14:45:26 +01:00
Benoit Marty
c0d6b9d130 Lint fix IconXmlAndPng error 2020-02-27 14:35:57 +01:00
Benoit Marty
a1466e299b Fix missing recycle call and ensure this mistake will not happen again 2020-02-27 14:30:49 +01:00
Benoit Marty
bc9493d5b9 Upgrade ktlint to version 0.36.0 2020-02-27 12:48:17 +01:00
Benoit Marty
9bb4c7ed25 Version++ 2020-02-27 12:34:33 +01:00
Benoit Marty
65e5a04836 Merge branch 'release/0.17.0' into develop 2020-02-27 12:32:35 +01:00
Benoit Marty
495e4792b1 Prepare release 0.17.0 2020-02-27 12:32:03 +01:00
Benoit Marty
f906fc894b Sync Strings with Riot 2020-02-27 11:59:39 +01:00
Benoit Marty
6e060f63c6 Try to decode QrCode data in the debug Activity 2020-02-27 11:32:59 +01:00
Benoit Marty
9c7f5251b0 Merge pull request #1084 from vector-im/feature/room_key_share_crash
Fix crash after rework. RoomKeyShare is now an interface
2020-02-26 20:45:50 +01:00
Benoit Marty
a296234163 Fix crash after rework. RoomKeyShare is now an interface 2020-02-26 20:35:34 +01:00
Benoit Marty
a4d7b79e3c Merge pull request #1083 from vector-im/feature/last_fixies
Last fixes before release
2020-02-26 18:37:21 +01:00
Benoit Marty
3ac2296464 Disable freestyle crop, usability was not easy 2020-02-26 17:46:33 +01:00
Benoit Marty
b5a402c1e1 Fix crash when editing image 2020-02-26 17:45:39 +01:00
Benoit Marty
b8eeede5fd Safer code 2020-02-26 17:28:27 +01:00
Benoit Marty
d3e7e7e109 Make the small avatar also clickable and little change in the API to factorize code 2020-02-26 17:17:39 +01:00
Benoit Marty
a3af0be103 prevent wildcard for import 2020-02-26 17:01:38 +01:00
Benoit Marty
6349f9828d Optimize import 2020-02-26 16:59:20 +01:00
Benoit Marty
989d396c78 Rename package "sas" to "verification" 2020-02-26 16:52:16 +01:00
Benoit Marty
73ac7ab341 Compact code 2020-02-26 16:48:50 +01:00
Benoit Marty
a3133773a3 generic name for parameter 2020-02-26 16:45:12 +01:00
Benoit Marty
6e67d4749f Merge pull request #1082 from vector-im/feature/fix_rageshakes
Fix crashes reported by rageshakes
2020-02-26 16:10:47 +01:00
Benoit Marty
38c1ef3eb6 Fix lint issue 2020-02-26 16:08:34 +01:00
Benoit Marty
674450ef29 Merge pull request #1076 from vector-im/feature/fullscreen_avatar
Display avatar in fullscreen.
2020-02-26 16:06:13 +01:00
Benoit Marty
5e775298a7 Merge pull request #1081 from vector-im/feature/fix_redacted_event_format
Fix redacted event format on room overview.
2020-02-26 15:57:10 +01:00
onurays
93a687a172 Code review fixes. 2020-02-26 17:55:23 +03:00
Benoit Marty
4ba8a42977 Fix crash reported from rageshake 2020-02-26 15:32:52 +01:00
Benoit Marty
054d7668ef Fix crash reported from rageshake 2020-02-26 15:19:47 +01:00
Benoit Marty
a13fec84b0 Fix crash reported from rageshake 2020-02-26 15:00:25 +01:00
Benoit Marty
4bb3fb128f Fix crash reported from rageshake 2020-02-26 14:54:36 +01:00
onurays
04726a1ace Fix redacted event format on room overview.
Fixes #758
2020-02-26 16:51:01 +03:00
Benoit Marty
ccf72ffaa7 Fix crash reported from rageshake 2020-02-26 14:50:01 +01:00
Onuray Sahin
d2efe0e10c Merge branch 'develop' into feature/fullscreen_avatar 2020-02-26 16:23:02 +03:00
Benoit Marty
054b467caf Fix crash reported from rageshake 2020-02-26 14:18:48 +01:00
Benoit Marty
4280bc0780 Fix crash reported from rageshake 2020-02-26 14:10:51 +01:00
Benoit Marty
e1ea742023 Fix crash reported from rageshake 2020-02-26 13:59:58 +01:00
Benoit Marty
b7cf7e06a7 Merge pull request #1015 from vector-im/feature/new_signin_passphrase
Feature/new signin passphrase
2020-02-26 13:56:31 +01:00
onurays
536dce7929 Code review fixes. 2020-02-26 15:30:03 +03:00
onurays
56fc91a8c3 Code review fixes. 2020-02-26 15:26:53 +03:00
Benoit Marty
6622e0daca Code quality 2020-02-26 12:43:41 +01:00
Benoit Marty
f35b0660ca Rename constant for code readability 2020-02-26 12:37:36 +01:00
Valere
9d1718cda8 post merge clean 2020-02-26 12:20:03 +01:00
Valere
f7c128be3d Fix tests 2020-02-26 12:20:03 +01:00
Valere
c80fb52410 dead code 2020-02-26 12:20:03 +01:00
Valere
32389e1291 Remove wizard stuff 2020-02-26 12:20:03 +01:00
Valere
99f9a9817e Use human readable error (not technical) 2020-02-26 12:20:03 +01:00
Valere
b4a783198b code review 2020-02-26 12:20:03 +01:00
Valere
0cfc9451ca Cleaning 2020-02-26 12:20:03 +01:00
Valere
4b75baf772 Fix / trust was not properly updated after 4S restore 2020-02-26 12:20:03 +01:00
Valere
c579de1033 Fix / Test crash when crypto DB closed
Quick Work around
2020-02-26 12:20:03 +01:00
Valere
d537abc522 Fix / sign current device after entering xsigning passphrase 2020-02-26 12:20:03 +01:00
Valere
030f027516 Fixes #1051
XSigning | Self verification Empty bottomsheet
2020-02-26 12:20:03 +01:00
Valere
cbd7c1aa63 Fix / Bad ordering of active sessions 2020-02-26 12:20:03 +01:00
Valere
bdb1df75d4 Check trust on crypto thread 2020-02-26 12:20:03 +01:00
Valere
817dc19b9a Cleaning 2020-02-26 12:20:03 +01:00
Valere
f9be4fa2bd Fixes #1047 2020-02-26 12:20:03 +01:00
Valere
412aed6dcb Fix / Update title before return 2020-02-26 12:20:03 +01:00
Valere
9fc44c11de Fixes #937
Disabling bounds change animation, as it's messing with fragment change apparition and expanded state of bottomsheet
2020-02-26 12:20:03 +01:00
Valere
bf23094158 Fix / Green shield in conclusion title when verified from private keys 2020-02-26 12:20:03 +01:00
Valere
94d36e0c85 cleaning jni 2020-02-26 12:20:03 +01:00
Valere
0064934db9 Changed Encryption algorithm of 4S 2020-02-26 12:20:03 +01:00
Valere
e2e4ddf5ba Post rebase fix 2020-02-26 12:20:03 +01:00
Valere
9a08f5ec4e WIP / Verify from passphrase UX 2020-02-26 12:19:31 +01:00
Valere
cb669ad881 4S Activity WIP 2020-02-26 12:15:59 +01:00
Valere
3dc89c8d87 Update Self Verification BottomSheet for quads 2020-02-26 12:15:59 +01:00
Benoit Marty
cb73955946 Merge pull request #1050 from vector-im/feature/fix_some_perf
Feature/fix some perf
2020-02-26 12:02:36 +01:00
ganfra
bfe15555a1 Update changes 2020-02-26 11:51:05 +01:00
ganfra
bddeb6cb72 Clean files 2020-02-26 11:50:41 +01:00
ganfra
d57f6838e9 Remove decryption from room summary mapper and make TimelineEventDecryptor scoped to session 2020-02-26 11:50:41 +01:00
ganfra
cf8ffa3a7a Force trust task on crypto dispatcher to use cached realm from crypto store 2020-02-26 11:49:08 +01:00
Benoit Marty
a69049645a FTUE: do not display a different color when encrypting message when not in developer mode. 2020-02-26 11:25:37 +01:00
Benoit Marty
40b4db4a64 Merge pull request #1060 from vector-im/feature/data_class_cleanup
Data class cleanup
2020-02-26 10:57:10 +01:00
Benoit Marty
246b39786c Merge pull request #1073 from vector-im/feature/improve_api
Improve api of CreateRoomParams
2020-02-26 10:55:48 +01:00
onurays
1a273407de Display avatar in fullscreen. 2020-02-26 12:12:49 +03:00
Benoit Marty
633f9d8522 ktlint 2020-02-26 09:55:57 +01:00
Benoit Marty
076ac23b38 Modification done by AndroidStudio 3.6 2020-02-26 07:59:54 +01:00
Benoit Marty
67180fd8db New direct chat: selecting several participants was not adding the room to the direct chats list 2020-02-26 07:38:10 +01:00
Benoit Marty
fc95bf4926 Improve CreateRoomParams API: update some API for better chaining of builder like methods (#1070) 2020-02-26 07:32:22 +01:00
Benoit Marty
e73f138151 Improve CreateRoomParams API: update Javadoc and ensure the return values will not be discarded (#1070) 2020-02-26 07:17:25 +01:00
Benoit Marty
30432cd3f4 Merge pull request #1069 from vector-im/feature/fix_dm
Fix dm chips
2020-02-25 19:28:46 +01:00
Benoit Marty
1072060cbb New direct chat: selecting a participant sometimes results in two breadcrumbs (#1022) 2020-02-25 19:00:38 +01:00
Benoit Marty
a55e0f1af4 Fix crash - workaround 2020-02-25 18:17:40 +01:00
Benoit Marty
b95dfa4473 Create getBestName method for User 2020-02-25 18:14:02 +01:00
Benoit Marty
ec0cba2b23 Merge pull request #1067 from vector-im/feature/roomId
Display internal id of a room section in room profile
2020-02-25 12:22:14 +01:00
Benoit Marty
cfe9c4bb41 Display internal id of a room section in room profile, with copy to clipboard action, only in developer mode 2020-02-25 12:21:04 +01:00
Benoit Marty
68400cce03 Merge pull request #1049 from vector-im/feature/fix_invites
Feature/fix invites
2020-02-25 11:39:35 +01:00
Benoit Marty
17e028178e Code robustness (avoid using !!) 2020-02-25 11:20:11 +01:00
ganfra
19b9617a09 Invite: fix inviterId being overrided 2020-02-25 10:53:47 +01:00
Benoit Marty
08e4b4473c Disable manual rules now checked by ktlint 2020-02-25 09:57:12 +01:00
Benoit Marty
b9b921a4df Code quality 2020-02-25 09:53:17 +01:00
ganfra
483256093a Invite: fix room member not saved 2020-02-24 18:27:18 +01:00
Benoit Marty
d710a59554 Update change log 2020-02-24 17:44:51 +01:00
Benoit Marty
1023982858 Code readability 2020-02-24 17:40:28 +01:00
Benoit Marty
9c566b19f7 Ensure all eventId start with $, even ids for local echo 2020-02-24 17:35:43 +01:00
ganfra
b694721728 Update CHANGES 2020-02-24 17:33:40 +01:00
ganfra
8b0305c91d Clean code 2020-02-24 17:33:40 +01:00
ganfra
133d8d7f14 RoomList: fix joining/rejecting state 2020-02-24 17:33:40 +01:00
ganfra
9cdb1da614 Start fixing notif for invites 2020-02-24 17:33:40 +01:00
ganfra
981c9ac4ac Invite sync: assign eventId and remove the primaryKey constraint 2020-02-24 17:33:40 +01:00
Benoit Marty
3e8a0f7252 Merge pull request #1044 from vector-im/feature/fix_big_image_rotation
Use exif info of the image for correct rotation.
2020-02-24 17:30:33 +01:00
Benoit Marty
281620b88d Merge pull request #1048 from vector-im/feature/profile_share_actions
Share action is added to room profile and room member profile
2020-02-24 17:29:17 +01:00
Benoit Marty
c6b3b1e648 Fix bug on test 2020-02-24 17:27:04 +01:00
Benoit Marty
96af1957f9 Fix bug on progress step, found by integration test testBackupWithPassword() 2020-02-24 16:27:58 +01:00
Benoit Marty
b680e24938 Fix some tests 2020-02-24 16:16:37 +01:00
onurays
dec62a893e Code review fixes. 2020-02-24 18:06:59 +03:00
onurays
b3d4747d97 Code review fixes. 2020-02-24 17:35:57 +03:00
onurays
1124aa25fd Code review fixes. 2020-02-24 17:22:07 +03:00
Benoit Marty
b3c8b5526d Each session now have it's proper crypto store 2020-02-24 15:03:12 +01:00
Benoit Marty
1e44e77503 Make code robust to int received instead of boolean
https://github.com/matrix-org/synapse/issues/6977
2020-02-24 14:42:47 +01:00
Valere
964b611f4e Merge pull request #1053 from vector-im/feature/fix_712
Fixes #712
2020-02-24 14:07:35 +01:00
Valere
3e587af163 klint 2020-02-24 14:07:15 +01:00
Benoit Marty
b03b6bfc37 Fix crash discovered thanks to integration tests 2020-02-24 12:53:18 +01:00
Benoit Marty
1a6d4d0b03 Try to fix XSigningTest 2020-02-21 19:20:40 +01:00
Valere
c41661ece8 Fixes #712 2020-02-21 19:05:20 +01:00
Benoit Marty
1b763fb4c8 Cleanup XSigningTest 2020-02-21 18:52:36 +01:00
Benoit Marty
9ef267cb07 Cleanup after each test 2020-02-21 18:36:13 +01:00
Benoit Marty
d167ff9496 Make KeysBackup test pass (still work to do) 2020-02-21 17:58:04 +01:00
Benoit Marty
ccfa59ad31 Cleanup var -> val 2020-02-21 15:05:48 +01:00
onurays
f650e29ddd Share action is added to room profile and room member profile
Fixes #858
2020-02-21 15:30:01 +03:00
Onuray Sahin
1eefda18e4 Merge branch 'develop' into feature/fix_big_image_rotation 2020-02-21 13:13:02 +03:00
Benoit Marty
d6434654e2 Merge pull request #1043 from vector-im/feature/join_federation
Fix join room over federation
2020-02-21 10:08:05 +01:00
Benoit Marty
b6372df676 Merge pull request #1037 from vector-im/feature/crosssigning_qr
Migrate to binary QR code verification (#994)
2020-02-21 10:01:49 +01:00
Benoit Marty
d7de072155 typo 2020-02-21 09:58:56 +01:00
onurays
a11d70f173 Use exif info of the image for correct rotation. 2020-02-21 00:51:22 +03:00
Benoit Marty
a9909b37ba Update after Valere's review 2020-02-20 19:54:35 +01:00
Benoit Marty
3f9a5a4e54 Leaving a room creates a stuck "leaving room" loading screen. (#1041) 2020-02-20 19:31:33 +01:00
Benoit Marty
198e23c204 Second fix for #808 2020-02-20 19:23:32 +01:00
Benoit Marty
aefffc0c05 RoomPreviewNoPreviewFragment use room alias if there is no name 2020-02-20 19:19:31 +01:00
Benoit Marty
fd05fe36f5 Fix joining rooms from directory via federation isn't working. (#808) 2020-02-20 19:01:36 +01:00
Benoit Marty
b72698d63c Fix another issue when there is no name and no canonical alias on a public room 2020-02-20 18:47:07 +01:00
Benoit Marty
eec65fb622 Join room by roomId or room alias 2020-02-20 18:17:57 +01:00
Benoit Marty
87021dd6ec Rename field 2020-02-20 18:16:10 +01:00
Benoit Marty
b85c76b172 Simplify code 2020-02-20 18:05:53 +01:00
Benoit Marty
d867b1345f Format 2020-02-20 15:15:38 +01:00
Benoit Marty
80ef2192b9 Merge pull request #1036 from vector-im/feature/fix_key_restoring
Fix threading issues while restoring keys backup.
2020-02-20 15:13:13 +01:00
onurays
7d232527c8 Documentation of the API change is added. 2020-02-20 16:39:48 +03:00
Benoit Marty
e61d563589 Split long lines 2020-02-20 10:16:09 +01:00
Benoit Marty
74175ddfa0 Add a test and create extension for Byte to avoid using UByte (still experimental) 2020-02-20 10:12:07 +01:00
Benoit Marty
382fc6f05c Fix issue with long transactionId 2020-02-19 18:59:39 +01:00
Benoit Marty
932c478ed5 Change log 2020-02-19 18:11:23 +01:00
Benoit Marty
e81439d57b Remove v2 suffix 2020-02-19 18:09:33 +01:00
Benoit Marty
f81eb298cb Cleanup QRCode v1 2020-02-19 18:06:51 +01:00
Benoit Marty
859b9e4f8e Migrate to QrCode v2 - TODO: cleanup 2020-02-19 17:50:30 +01:00
Benoit Marty
e00d3ef63d QrCodeV2 WIP (al tests passing) 2020-02-19 17:34:07 +01:00
onurays
a97971dd84 Fix threading issues while restoring keys backup. 2020-02-19 18:30:12 +03:00
Benoit Marty
35b10daef1 Ensure RiotX is able to scan binary QrCodes 2020-02-19 14:26:45 +01:00
Benoit Marty
66a2958c39 Add unit test to check byte array to string conversion 2020-02-19 14:21:41 +01:00
Benoit Marty
571db7da55 Merge pull request #1035 from vector-im/feature/share_text
Fix share text to a single room issue
2020-02-19 10:08:29 +01:00
Benoit Marty
c6b231c0b1 Create toState() fun and use the enum 2020-02-18 14:12:50 +01:00
Benoit Marty
53410789c0 Cleanup 2020-02-18 14:12:50 +01:00
Benoit Marty
f8276e48e3 add kluent for test 2020-02-18 14:09:42 +01:00
Benoit Marty
86c38ebd2d Create Set.toggle() method 2020-02-18 13:33:49 +01:00
Benoit Marty
d730f96c41 Do not show alert when sharing text to a single room 2020-02-18 12:24:27 +01:00
Benoit Marty
7b3fcb7798 When sharing to a room save a draft to pre-fill the composer 2020-02-18 12:11:51 +01:00
Benoit Marty
26e8a60312 Merge pull request #1032 from vector-im/feature/crash
Fix crash in the room directory, when public room has no name (#1023)
2020-02-18 11:48:29 +01:00
Benoit Marty
7133d513b4 Fix crash in the room directory, when public room has no name (#1023) 2020-02-18 10:45:14 +01:00
Benoit Marty
8d1b2b35fd Merge pull request #1010 from vector-im/feature/attachment_process
Attachment process
2020-02-18 09:19:17 +01:00
Benoit Marty
b811bf9e7f Fix issue after merge 2020-02-17 23:21:08 +01:00
Benoit Marty
ebda12dd76 Merge branch 'develop' into feature/attachment_process 2020-02-17 19:22:50 +01:00
Benoit Marty
adc545a93d Merge pull request #1026 from vector-im/feature/crypto_service_renaming
Feature/crypto service renaming
2020-02-17 19:21:02 +01:00
Benoit Marty
fc740ae347 Merge pull request #1016 from vector-im/feature/cleanup_quadS
Cleanup quad s and AccountData service
2020-02-17 18:52:23 +01:00
Benoit Marty
67ed86fee5 Rename KeysBackup to DefaultKeysBackupService 2020-02-17 18:51:06 +01:00
Benoit Marty
f716e9d789 Fix compilation issue 2020-02-17 18:49:45 +01:00
Benoit Marty
141c7d6af0 Update comment 2020-02-17 18:43:04 +01:00
Benoit Marty
7495533edc Use let 2020-02-17 18:16:37 +01:00
Benoit Marty
f2f94c4a93 Reduce code duplication 2020-02-17 17:56:11 +01:00
Benoit Marty
4995c14f69 Add log 2020-02-17 17:46:15 +01:00
Benoit Marty
002e881704 Fix multiple share intent issue 2020-02-17 17:26:19 +01:00
Benoit Marty
51bbee297c Remove useless confirmation when shared data are previewables 2020-02-17 17:06:15 +01:00
Benoit Marty
82bd8a2e2a Ask for write permission before editing media 2020-02-17 16:29:10 +01:00
Benoit Marty
d67cd2cbef Small iteration on UI 2020-02-17 16:21:10 +01:00
ganfra
6d2025b61a Update CHANGES 2020-02-17 15:54:17 +01:00
ganfra
91cbcebf73 Make test compile 2020-02-17 15:50:42 +01:00
ganfra
fd0dceb597 Clean code 2020-02-17 15:23:24 +01:00
Benoit Marty
48a033b3bd Fix navigation issue when sharing text to multiple rooms 2020-02-17 14:58:20 +01:00
Benoit Marty
a3b205b310 No preview for elements sent from the keyboard 2020-02-17 14:48:12 +01:00
Benoit Marty
ca0cd9e97d Better code 2020-02-17 14:38:56 +01:00
Benoit Marty
31d5578063 Media preview: do not propose to edit Gif 2020-02-17 14:35:57 +01:00
Benoit Marty
b6f5e27155 Fix issue after merge of develop 2020-02-17 13:50:36 +01:00
Benoit Marty
13d3aa9ff1 Merge branch 'develop' into feature/attachment_process 2020-02-17 13:48:21 +01:00
Benoit Marty
629ecf786a Merge pull request #1024 from vector-im/feature/wording
Account creation: wrongly hints that an email can be used to create an account (#941)
2020-02-17 13:34:04 +01:00
Benoit Marty
ecf07ff64a Account creation: wrongly hints that an email can be used to create an account (#941) 2020-02-17 10:30:54 +01:00
ganfra
e349a35419 Crypto: expose cryptoService by a getter, removing the session implementation delegation 2020-02-16 15:40:31 +01:00
Benoit Marty
a61f508b5d Fix a nice bug 2020-02-14 22:00:36 +01:00
Benoit Marty
76085a4284 AccountData cleanup and Javadoc 2020-02-14 21:50:37 +01:00
Benoit Marty
446d826dd3 Create tag interface AccountDataContent 2020-02-14 20:53:45 +01:00
Benoit Marty
2d6f57e214 More cleanup/code lisibility 2020-02-14 20:50:21 +01:00
Ganard
a305ce302e Coroutine sequencer: use semaphore 2020-02-14 19:37:51 +01:00
Benoit Marty
7ddea99fc6 Move and improve withOlmDecryption() and withOlmEncryption() 2020-02-14 18:51:27 +01:00
Benoit Marty
4c3b754de4 Use const from DefaultSharedSecretStorageService 2020-02-14 18:33:15 +01:00
Benoit Marty
7878da25b8 Use doSync<>() to reduce boilerplate and add test checks
and more cleanup
2020-02-14 18:18:20 +01:00
Benoit Marty
01597a89dc Avoid code duplication 2020-02-14 17:53:27 +01:00
Valere
b04ee7153a Merge pull request #995 from vector-im/feature/4s_msc1946
Feature/4s msc1946
2020-02-14 17:49:16 +01:00
Benoit Marty
db19ab0531 Merge branch 'develop' into feature/4s_msc1946 2020-02-14 17:45:44 +01:00
Benoit Marty
cad818c341 ktlint 2020-02-14 17:05:14 +01:00
Benoit Marty
1660a0f846 Version++ 2020-02-14 15:16:00 +01:00
Benoit Marty
4987a75039 Merge branch 'release/0.16.0' into develop 2020-02-14 15:14:54 +01:00
Benoit Marty
e20d1724c9 Prepare release 0.16.0 2020-02-14 15:14:48 +01:00
Benoit Marty
f6f9c349ec Add entry in changelog for the 2 mistakes 2020-02-14 14:52:10 +01:00
Benoit Marty
88b8ceaeb5 Merge pull request #1005 from vector-im/feature/fix_event_redaction_prompt
Do not ask for a reason if user wants to delete his own message.
2020-02-14 14:36:01 +01:00
Benoit Marty
e4577d8fef Small cleanup before merge 2020-02-14 14:34:22 +01:00
onurays
030d6824e3 Code review fixes. 2020-02-14 15:04:25 +03:00
Benoit Marty
ab437e249d Update emoji for API change 2020-02-14 12:43:27 +01:00
Valere
35835be03e klint 2020-02-14 12:06:07 +01:00
Valere
f99eca8014 Code review 2020-02-14 10:48:18 +01:00
Valere
e0eede1150 cleaning 2020-02-14 10:48:18 +01:00
Valere
64647cb465 Fix / Save account data after update (local echo) 2020-02-14 10:48:18 +01:00
Valere
def01cca8f Fix test + changes 2020-02-14 10:48:18 +01:00
Valere
61ea4191dc Update json viewer lib 2020-02-14 10:48:18 +01:00
Valere
108ebea84e SSSS service + test 2020-02-14 10:48:18 +01:00
Valere
bf06b57bad Refactor Account Data
Auto stash before rebase of "develop"
2020-02-14 10:48:18 +01:00
Valere
a250a895fe Remove redudant calls to eventBus post 2020-02-14 10:47:34 +01:00
Benoit Marty
2c2bf61727 Update Changelog 2020-02-14 09:40:07 +01:00
Benoit Marty
6c0bddc893 Code quality 2020-02-13 23:20:35 +01:00
Benoit Marty
930d62c87b Restore Breadcrumbs comparator, we can maybe improve this later 2020-02-13 23:00:03 +01:00
Benoit Marty
b66b96899e Better Kotlin code 2020-02-13 22:56:11 +01:00
Benoit Marty
e6bd09859f Compress image before sending 2020-02-13 22:50:55 +01:00
Benoit Marty
385fa317c0 Add a green frame around current small preview 2020-02-13 20:45:03 +01:00
Benoit Marty
ecd547b86c Auto close the room picker and open the first room when data are shared in case of multi selection 2020-02-13 20:10:59 +01:00
Benoit Marty
d87b951403 Improve code 2020-02-13 20:10:59 +01:00
Benoit Marty
06ba478232 Send files to several rooms at a time 2020-02-13 20:10:59 +01:00
Benoit Marty
81de914360 Propose to edit media before sending, when coming form another application 2020-02-13 20:10:59 +01:00
Benoit Marty
b7ec495d6b Add comment 2020-02-13 19:52:11 +01:00
Benoit Marty
a8953568f3 Set custom colors 2020-02-13 19:52:11 +01:00
Benoit Marty
41b20863fb Mention uCrop library copyright 2020-02-13 19:52:11 +01:00
Benoit Marty
94340a49d7 Ask for permission 2020-02-13 19:52:11 +01:00
Benoit Marty
c67fd508e7 Cleanup 2020-02-13 19:52:11 +01:00
Ganard
eccc52fe13 Sharing: start extracting from RoomList as it's getting messy 2020-02-13 19:52:11 +01:00
Ganard
b7a7aa2f15 Attachment: continue working on preview screen 2020-02-13 19:52:11 +01:00
ganfra
6471787232 Share: start managing multi selection and warning 2020-02-13 19:52:11 +01:00
ganfra
41f1ec5d88 Attachments: preview with pager mode 2020-02-13 19:51:20 +01:00
Ganard
a26e959430 Attachements: introduce structure for preview, cropping and compressing 2020-02-13 19:51:20 +01:00
Benoit Marty
5808c1de22 TextView displaying emoji should have text color set to black 2020-02-13 19:50:31 +01:00
Benoit Marty
d21604b791 Merge pull request #989 from vector-im/feature/qr_code_mistake
Fix issue with verification when other client declares it can only show QR code (#988)
2020-02-13 19:41:10 +01:00
onurays
fd135e1eeb Compute message body for encrypted messages too. 2020-02-13 18:09:26 +03:00
onurays
f28e4cf991 Fix comparison of user ids. 2020-02-13 17:57:38 +03:00
Valere
1941862499 Fix / Remove debug code line 2020-02-13 15:50:08 +01:00
onurays
983593d647 getRedactionReason function is refactored. 2020-02-13 17:28:14 +03:00
onurays
1b413934b5 Set redaction reason as message body. 2020-02-13 16:42:13 +03:00
onurays
8a3e93ae96 Do not ask for a reason if user wants to delete his own message.
Fixes (#1003)
2020-02-13 14:59:41 +03:00
Benoit Marty
5191cbaf93 Merge pull request #1001 from vector-im/feature/pusher_service
Cleanup pusher service and improve API
2020-02-13 08:02:33 +01:00
Benoit Marty
f2e6900cfb Move throw line 2020-02-13 07:44:54 +01:00
Benoit Marty
0b7e757f3c Code lisibility: use generic name for parameters in Dagger modules 2020-02-13 07:12:11 +01:00
Benoit Marty
5b2c947af1 Rename internal class 2020-02-13 07:05:46 +01:00
Benoit Marty
6a69c6356d PushersService.pushers() has been renamed to PushersService.getPushers() 2020-02-13 07:04:54 +01:00
Benoit Marty
e492e4318b Do some parameter checks 2020-02-13 06:48:52 +01:00
Benoit Marty
93d38843c3 Add Javadoc 2020-02-13 06:36:21 +01:00
Benoit Marty
7d94519064 Merge pull request #998 from vector-im/feature/msc_2192_update_event_prefix
Use vendor prefix for non merged MSC
2020-02-12 22:41:12 +01:00
Valere
21bac0f867 Fix / typo in poll 2020-02-12 22:31:13 +01:00
Valere
32c4ad9ecb Use vendor prefix for non merged MSC 2020-02-12 19:09:23 +01:00
Valere
e1342d096b Merge pull request #810 from vector-im/feature/msc_2192
Feature/msc 2192
2020-02-12 17:41:50 +01:00
Valere
e91c6c216d code quality 2020-02-12 17:03:21 +01:00
Onuray Sahin
6013e1653b Open room member profile from reactions and read receipts. (#990)
Open room member profile from reactions and read receipts. Fixes #875
2020-02-12 15:57:49 +01:00
Benoit Marty
47f47e40c4 code review and cleanup 2020-02-12 15:09:38 +01:00
Benoit Marty
9016688aec Fix compilation issue after rebase 2020-02-12 13:48:08 +01:00
Valere
d5f8a0c0fc code quality 2020-02-12 13:40:54 +01:00
Valere
33c657bff8 Update change log 2020-02-12 13:40:54 +01:00
Valere
9a7bd35ddc Add m.buttons support (a.k.a bot buttons) 2020-02-12 13:40:54 +01:00
Valere
3ac54c51f6 cleaning 2020-02-12 13:39:30 +01:00
Valere
c4ea2507f8 Add command to send poll 2020-02-12 13:39:30 +01:00
Valere
6001ac60ab klint cleaning 2020-02-12 13:37:16 +01:00
Valere
0cea26ec77 ux tweak on poll result 2020-02-12 13:37:16 +01:00
Valere
3dae220501 Fix / filter edits and poll response form lastPreviewableMessage 2020-02-12 13:37:16 +01:00
Valere
577c5a16b3 Support incremental poll response aggregation + display 2020-02-12 12:47:28 +01:00
Valere
a0aebed3f7 Message Poll UX, and model 2020-02-12 12:42:17 +01:00
Benoit Marty
3a044bd655 Add Javadoc 2020-02-12 11:39:36 +01:00
Benoit Marty
6acfab3242 Rename VerificationListener to Listener 2020-02-12 11:39:36 +01:00
Benoit Marty
bf02746d87 Clenaup VerificationService.VerificationListener 2020-02-12 11:39:36 +01:00
Benoit Marty
377d944228 Cleanup API 2020-02-12 11:39:36 +01:00
Benoit Marty
6ff974b3ea Fix issue with verification when other client declares it can only show QR code (#988) 2020-02-12 11:39:36 +01:00
Onuray Sahin
7c5bb4ff5b Merge pull request #986 from vector-im/feature/fix_clear_cache_notification_click
Fix crash by removing all notifications after clearing cache.
2020-02-11 18:06:16 +03:00
onurays
3573aea600 Fix crash by removing all notifications after clearing cache.
Fixes #878
2020-02-11 16:48:28 +03:00
Benoit Marty
251de0b89c Merge pull request #982 from vector-im/feature/remove_message_step2
Redact message step2
2020-02-11 11:35:16 +01:00
Benoit Marty
6fce2a3066 Change wording adding "..." because there is now confirmation dialog
And make the item red because it is destructive. Also use "redact" terminology
2020-02-11 11:04:21 +01:00
Benoit Marty
b40da4ef0f Disable TextInputLayout instead of TextInputEditText 2020-02-11 11:00:33 +01:00
Benoit Marty
96341df5e7 Format layout 2020-02-11 11:00:01 +01:00
Benoit Marty
7ccc1c559c Merge pull request #977 from vector-im/feature/event_deletion_dialog
Show confirmation dialog before deleting a message
2020-02-11 10:45:17 +01:00
Benoit Marty
35ed22ab2b improve script 2020-02-11 10:38:13 +01:00
onurays
afbd9cff70 Merge branch 'develop' into feature/event_deletion_dialog
# Conflicts:
#	CHANGES.md
#	vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
2020-02-11 12:11:36 +03:00
onurays
ce028f8bd2 Gathering reason input is refactored. 2020-02-11 00:10:24 +03:00
Benoit Marty
a7274b9df0 Version++ 2020-02-10 21:41:59 +01:00
Benoit Marty
a9d6cb7be3 Merge branch 'release/0.15.0' into develop 2020-02-10 21:40:35 +01:00
Benoit Marty
d71797319c Prepare release 0.15.0 2020-02-10 21:40:27 +01:00
onurays
ba0133a047 Reason input for redacting event is added. 2020-02-10 23:03:37 +03:00
Benoit Marty
01a7ea0bd7 Merge branch 'feature/fix_notif' into develop 2020-02-10 19:16:20 +01:00
Benoit Marty
2e7fa23ce7 Fix #980 2020-02-10 19:13:35 +01:00
Benoit Marty
6750237764 Merge pull request #976 from vector-im/feature/viewEvents
Use View events
2020-02-10 16:46:21 +01:00
Benoit Marty
588a644e02 Merge pull request #975 from vector-im/feature/cleanup
Cleanup push rule code
2020-02-10 16:32:24 +01:00
onurays
1bc1c8ec4a Reorder improvements. 2020-02-10 18:17:22 +03:00
Benoit Marty
7e362be568 Convert to ViewEvents -> Cleanup after review 2020-02-10 16:10:57 +01:00
onurays
83d83e0812 Show confirmation dialog before deleting a message
Fixes #967
2020-02-10 17:58:48 +03:00
Benoit Marty
c97d298166 Merge pull request #948 from vector-im/feature/artifacts_downloading
Feature/artifacts downloading
2020-02-10 14:52:25 +01:00
Benoit Marty
81413e49bc Remove '(yet)' 2020-02-10 14:51:35 +01:00
Benoit Marty
b24f133105 Import strings from Riot 2020-02-10 14:50:21 +01:00
Benoit Marty
5b13be6332 Rename 2020-02-07 19:58:14 +01:00
Benoit Marty
abeb741cad Convert to ViewEvents -> RoomDetailViewModel part 5 2020-02-07 19:50:15 +01:00
Benoit Marty
84e1169525 Convert to ViewEvents -> RoomDetailViewModel part 4 2020-02-07 19:45:54 +01:00
Benoit Marty
27e217fce5 Convert to ViewEvents -> RoomDetailViewModel part 3 2020-02-07 19:41:23 +01:00
Benoit Marty
bdb1f850b2 Convert to ViewEvents -> RoomDetailViewModel part 2 2020-02-07 19:37:30 +01:00
Benoit Marty
0338535efa Convert to ViewEvents -> RoomDetailViewModel part 1 2020-02-07 19:27:18 +01:00
Benoit Marty
0dd3894a49 Use handle() pattern 2020-02-07 19:20:02 +01:00
Benoit Marty
c8ff8d3c9e Convert to ViewEvents -> DeviceListBottomSheetViewModel 2020-02-07 18:59:31 +01:00
Benoit Marty
70973c3302 Convert to ViewEvents -> CrossSigningSettingsViewModel 2020-02-07 18:47:54 +01:00
Benoit Marty
a930313bf3 Convert to ViewEvents -> VerificationBottomSheetViewModel 2020-02-07 18:27:13 +01:00
Benoit Marty
35054dc5e8 Convert to ViewEvents -> CreateDirectRoomViewModel 2020-02-07 18:11:53 +01:00
Benoit Marty
33b123f719 Convert to ViewEvents -> GroupListViewModel 2020-02-07 18:02:42 +01:00
Benoit Marty
24667f38b8 Convert to ViewEvents -> RoomMemberProfileViewModel 2020-02-07 17:47:37 +01:00
Benoit Marty
256a6e4322 Convert to ViewEvents -> RoomDetailViewModel 2020-02-07 17:34:26 +01:00
Benoit Marty
7f5cc77ee0 Convert to ViewEvents -> DevicesViewModel 2020-02-07 17:14:03 +01:00
Benoit Marty
c34307ecf7 Convert to ViewEvents -> RoomDirectoryViewModel 2020-02-07 16:32:01 +01:00
Benoit Marty
dd13b6bd99 Add test for DisplayName condition (passing) 2020-02-07 15:44:46 +01:00
Benoit Marty
9df699db59 Reorder tests 2020-02-07 15:35:09 +01:00
Benoit Marty
8bdb2b88fd make the test compile 2020-02-07 15:32:36 +01:00
Benoit Marty
2a534b5874 Handle SenderNotificationPermissionCondition 2020-02-07 15:32:20 +01:00
Benoit Marty
f719da96ed Rename Condition.Kind enum values and add some documentation 2020-02-07 15:02:39 +01:00
Benoit Marty
31e5c0eb1a Improve algorithm 2020-02-07 14:48:08 +01:00
Benoit Marty
34c5f37bbc findAll() does not return null value 2020-02-07 14:30:44 +01:00
Benoit Marty
9aadbbc3c7 Rework DefaultConditionResolver, and create RoomGetter 2020-02-07 14:27:24 +01:00
Benoit Marty
57758af2d7 Merge pull request #974 from vector-im/feature/crosssigning_cleanup
Improve prompt password dialog
2020-02-07 14:02:15 +01:00
Benoit Marty
0a2474ef12 ktlint 2020-02-07 14:01:18 +01:00
Valere
67bc100782 Merge pull request #959 from vector-im/feature/roomshields_perf
Refactor Room Shield / Profile shield
2020-02-06 16:54:17 +01:00
Benoit Marty
5fedfd9286 Cleanup 2020-02-06 16:00:05 +01:00
Valere
1917fbcc93 eventBus private 2020-02-06 13:56:57 +01:00
Valere
a48bf61ad7 quick dispatch to correct thread (will need more work) 2020-02-06 13:56:57 +01:00
Valere
5c1fcc47a1 Catch all decryption fails in mapping 2020-02-06 13:56:57 +01:00
Valere
d80c15f52f Dispatch init on crypto thread to avoid blocking cold start 2020-02-06 13:56:57 +01:00
Valere
3e2219cbb5 Ignore interrupted exception in setupRx 2020-02-06 13:56:57 +01:00
Valere
bf2e01b8c3 More Rx startWithcallable 2020-02-06 13:56:57 +01:00
Valere
75131fdf44 Post merge fix 2020-02-06 13:56:57 +01:00
Valere
911ff8cf16 cleaning (klint) 2020-02-06 13:56:57 +01:00
Valere
4506b7d6e6 Fix / annoying loading to get active sessions
Start with what's known locally
2020-02-06 13:56:57 +01:00
Valere
320dc4accd Refactor Room Shield / Profile shield 2020-02-06 13:56:57 +01:00
Benoit Marty
ffc9a595dd Merge pull request #964 from vector-im/feature/firefox_account_sso
Support SSO login with Firefox account (#606)
2020-02-06 11:28:16 +01:00
Benoit Marty
1602c6544f We have too many strings... 2020-02-05 18:06:39 +01:00
Benoit Marty
79242c8c16 Merge pull request #892 from vector-im/feature/indonesian_check
Import Indonesian resource check from TravisCI to Weblate pipeline
2020-02-05 18:02:00 +01:00
Benoit Marty
7d00aabc85 Share the same Copyright header. Disabled for XML files 2020-02-05 17:48:59 +01:00
Benoit Marty
ef72f2246a Import Indonesian resource check from TravisCI to Weblate pipeline 2020-02-05 17:47:11 +01:00
Benoit Marty
51c2b9e1e9 Import strings from Riot 2020-02-05 17:35:23 +01:00
Benoit Marty
2a4c8b3199 Support SSO login with Firefox account (#606) 2020-02-05 15:21:54 +01:00
Benoit Marty
3189c114dc Merge pull request #945 from vector-im/feature/stabilization_2
Feature/stabilization 2
2020-02-05 15:19:16 +01:00
Benoit Marty
50814dafe9 Update wording 2020-02-05 14:19:04 +01:00
Benoit Marty
dcd7d17ffd Fix compilation issue after merge and update CHANGES.md 2020-02-05 14:13:43 +01:00
Benoit Marty
d9c007d017 Merge branch 'develop' into feature/stabilization_2 2020-02-05 12:57:42 +01:00
Benoit Marty
05dd587fa8 Move FORMAT_MATRIX_HTML to a proper object and so fix a wrong usage issue 2020-02-05 12:44:31 +01:00
Benoit Marty
3384d91adb Rename MessageContent.type to MessageContent.msgType for code clarity and update a few the Javadoc 2020-02-05 12:39:26 +01:00
Benoit Marty
f72e5c1d94 Explain why and when to use EllipsizingTextView 2020-02-05 12:16:43 +01:00
Benoit Marty
a3ec0e03a0 Use NoOpMatrixCallback when it's possible 2020-02-05 12:05:12 +01:00
Benoit Marty
47ee2a24a7 Move NoOpMatrixCallback to MatrixCallback.kt file 2020-02-05 11:58:08 +01:00
Benoit Marty
b8096f21ea Restore Copyright and cleanup 2020-02-05 11:56:07 +01:00
Benoit Marty
a17ec14dd7 Cleanup and little change on Throwable logging 2020-02-05 11:39:23 +01:00
Benoit Marty
062c4559a2 Merge pull request #955 from vector-im/feature/room_history_in_e2e
Feature/room history in e2e
2020-02-04 21:18:26 +01:00
Benoit Marty
f7d511df38 Ganfra's review 2020-02-04 17:48:17 +01:00
Benoit Marty
6bff951c72 Keep MXCryptoConfig, but do a correct usage of it 2020-02-04 15:37:46 +01:00
Benoit Marty
bd033866a8 Encrypt for invited users by default, if the room state allows it (#803) 2020-02-04 14:41:32 +01:00
Benoit Marty
3e9b2e4a06 Use the correct enableEncryption() method 2020-02-04 14:04:48 +01:00
Ganard
ed9c3379bf Rename file 2020-02-04 13:50:10 +01:00
Ganard
1728d31401 Fix some issues and make test passes 2020-02-04 13:19:02 +01:00
Benoit Marty
225a6e00e6 Add doc and reorder 2020-02-04 12:10:51 +01:00
Benoit Marty
96a729ab2b Move file 2020-02-04 11:53:09 +01:00
Benoit Marty
badb4042ce Add sign_apk_unsafe.sh to the repo 2020-02-04 11:53:09 +01:00
Benoit Marty
c3bb421c1e ignore .idea/inspectionProfiles 2020-02-04 11:53:09 +01:00
Benoit Marty
09212a05d0 Add a script to download artifacts from buildkite 2020-02-04 11:53:09 +01:00
Benoit Marty
e02430bcd0 Ask for permission before opening the camera (#934) 2020-02-03 20:06:37 +01:00
Benoit Marty
4335fa4f72 ktlint 2020-02-03 16:26:18 +01:00
Benoit Marty
6df5edbad1 Version++ 2020-02-03 16:20:55 +01:00
Benoit Marty
362799ac08 Merge branch 'release/0.14.3' into develop 2020-02-03 16:15:52 +01:00
Benoit Marty
0049af7980 Prepare version 0.14.3 2020-02-03 16:15:38 +01:00
Ganard
f454078c6b Clean code 2020-02-03 16:14:36 +01:00
Benoit Marty
783a514496 Improve prompt password dialog
Reveal password, inline error when empty
2020-02-03 15:53:44 +01:00
Ganard
88755a79b4 In memory sending: fix broken filtering 2020-02-03 15:18:19 +01:00
Ganard
e6cd8a3a86 Merge develop into feature/stabilization_2 2020-02-03 13:59:20 +01:00
Valere
ce13e824b6 Merge remote-tracking branch 'origin/develop' into develop 2020-02-02 15:28:05 +01:00
Valere
b182a63ea1 fix concurrent co mofification 2020-02-02 15:28:00 +01:00
Benoit Marty
9ced2048d2 Version++ 2020-02-02 14:26:09 +01:00
Benoit Marty
b158729b53 Prepare v0.14.2 2020-02-02 14:05:12 +01:00
Valere
367057cc29 Fix / cold start 2020-02-02 14:01:45 +01:00
Benoit Marty
5fb4f274f9 Version ++ 2020-02-02 08:00:57 +01:00
Benoit Marty
6f60f1c6b4 Merge branch 'release/0.14.1' into develop 2020-02-02 07:56:00 +01:00
Benoit Marty
435d8cbc55 Prepare v0.14.1 2020-02-02 07:55:46 +01:00
Benoit Marty
bb0fafcb2f Merge pull request #929 from vector-im/feature/xsigning_fix_4
Feature/xsigning fix 4
2020-02-02 03:13:54 +01:00
Benoit Marty
1d2928b3fb ktlint 2020-02-02 03:13:15 +01:00
Benoit Marty
40b0f60964 Fix issue in dark theme. Also do not limit subtitles to 2 lines 2020-02-02 03:11:27 +01:00
Valere
96a556f449 Fix / Race causing key requests to be sent to early in xsigning 2020-02-02 01:21:08 +01:00
Valere
d436d3b8d4 Move rx logs to verbose 2020-02-02 00:41:36 +01:00
Valere
845f3f5ad1 FIx / use password textedit 2020-02-02 00:04:15 +01:00
Valere
fb838e5407 Fixes #813 2020-02-01 23:24:05 +01:00
Benoit Marty
40c70f64a8 Merge branch 'feature/to_device_done' into develop 2020-02-01 18:48:34 +01:00
Valere
245b3717b9 Send done in toDevice 2020-02-01 18:25:31 +01:00
Benoit Marty
9e15891053 Version++ 2020-02-01 17:21:41 +01:00
Benoit Marty
649ebf4a34 Merge branch 'release/0.14.0' into develop 2020-02-01 17:20:04 +01:00
Benoit Marty
e9f220cca2 Prepare release 0.14.0 2020-02-01 17:19:53 +01:00
Benoit Marty
8a9bd97a88 Merge pull request #924 from vector-im/feature/crossing_fix_2
Feature/crossing fix 2
2020-02-01 17:17:30 +01:00
Valere
26400e6372 Prompt before resetting keys 2020-02-01 15:20:04 +01:00
Valere
282be29247 temp shield for read only 2020-02-01 15:20:04 +01:00
Benoit Marty
6ee7ee1460 Fix blink effect 2020-02-01 15:04:22 +01:00
Valere
2e0a84ccc9 display profile faster from known info 2020-02-01 15:03:00 +01:00
Valere
9d6e7d7bd0 Learn more shows my devices when keys not trusted 2020-02-01 14:36:17 +01:00
Valere
8f7b18239d Warn on verify when private keys not known 2020-02-01 14:36:17 +01:00
Benoit Marty
10094a212c ktlint 2020-02-01 14:02:51 +01:00
Benoit Marty
53e36dca9c ZXing 3.3.3 because of https://github.com/zxing/zxing/issues/1170 2020-02-01 13:52:33 +01:00
Benoit Marty
6ec2dd8c00 Add startWith and logs 2020-02-01 12:12:40 +01:00
Benoit Marty
f098d6cf5b Add startWith 2020-02-01 11:45:45 +01:00
Benoit Marty
cd606ba8a1 RoomMember decoration 2020-02-01 11:37:16 +01:00
Benoit Marty
59abee10f8 Convert to ConstraintLayout 2020-02-01 11:37:16 +01:00
Valere
64df9e23c2 Room Profile / Just show e2e status remove learn more 2020-02-01 11:03:00 +01:00
Valere
fc4f5faffd Update Room decoration algo 2020-02-01 10:21:29 +01:00
Benoit Marty
256f8b77aa Add Timber to rx module 2020-02-01 10:09:22 +01:00
Benoit Marty
f2f775cb99 Add TODOs 2020-02-01 01:17:18 +01:00
Benoit Marty
2616a889ef Merge pull request #923 from vector-im/feature/xcrossing_fix
Decoration in room profile and improve Rx flow
2020-01-31 20:48:20 +01:00
Benoit Marty
ccd4c1ed86 ktlint 2020-01-31 20:46:33 +01:00
Benoit Marty
bb92882958 (partially) Fix glitch 2020-01-31 20:28:57 +01:00
Benoit Marty
46dd17644f Room decoration - in room profile UI 2020-01-31 20:12:02 +01:00
Benoit Marty
7e34b2a672 Room decoration - convert to ConstraintLayout 2020-01-31 20:02:01 +01:00
Benoit Marty
c3c88c387b Improve Rx chain and cleanup 2020-01-31 19:55:22 +01:00
Valere
51e0f945a7 Quick Room Decoration 2020-01-31 18:52:33 +01:00
Ganard
37230b0614 Fix issues with read marker and jumpToBottom 2020-01-31 18:09:34 +01:00
Benoit Marty
fd3619b100 Merge pull request #770 from vector-im/cross_signing
Cross signing
2020-01-31 17:05:18 +01:00
Benoit Marty
e18b9d5155 Room decoration - UI in room list 2020-01-31 16:10:52 +01:00
Ganard
ec6d78bf96 Merge branch 'develop' into feature/stabilization_2 2020-01-31 15:47:33 +01:00
Ganard
759b680e63 Timeline/Sync: Fix some issues 2020-01-31 15:28:35 +01:00
Benoit Marty
f5ecf4bd90 Room decoration - UI 2020-01-31 15:02:54 +01:00
Valere
27c74c9118 live device in settings 2020-01-31 14:42:00 +01:00
Benoit Marty
4d91bc934b Fix ktlint 2020-01-31 14:12:03 +01:00
Valere
5c547794f2 Merge branch 'develop' into cross_signing 2020-01-31 14:09:40 +01:00
Benoit Marty
43358cd86c Make self verification work! 2020-01-31 12:18:27 +01:00
Benoit Marty
87b76d10dd Format 2020-01-31 11:11:27 +01:00
Benoit Marty
80f4f95f81 QRCode: requestId is not supposed to be an eventId 2020-01-31 11:11:27 +01:00
Valere
8e5c7239cf Settings Sessions / Now live + support devices with no keys 2020-01-31 10:33:53 +01:00
Valere
7b385c3b36 Quick copy change device -> session 2020-01-31 10:00:44 +01:00
Valere
4fb59aadb1 Fix / ensure RoomKeyRequest are made after device is verified 2020-01-31 09:39:31 +01:00
Valere
850c830e1f Fix / auto ready request when waiting bottomsheet on screen 2020-01-31 09:16:03 +01:00
Benoit Marty
9dde43f65b PR Review: var -> val, internal and other cleanup 2020-01-30 23:40:25 +01:00
Benoit Marty
9d566e9352 Merge pull request #918 from vector-im/feature/sort_room_members
Sort room members by display names
2020-01-30 21:06:40 +01:00
Benoit Marty
eb46a4949f Merge pull request #920 from duncanturk/patch-1
Add "get it on F-Droid"
2020-01-30 21:05:53 +01:00
Benoit Marty
506c2dd262 Merge pull request #921 from vector-im/decorations
Add field in QR code and make some optional
2020-01-30 18:48:30 +01:00
Benoit Marty
ccd857016c ktlint 2020-01-30 18:46:08 +01:00
Benoit Marty
225e4e0433 To Device Verification Request 2020-01-30 18:43:50 +01:00
Ganard
5e1b59f9d3 Timeline: handle an in memory local echo to make the UI snappier 2020-01-30 17:13:44 +01:00
Benoit Marty
069bd3c258 use isMe 2020-01-30 16:59:22 +01:00
Benoit Marty
fb98d6ef42 QRCode: add other_device_key field and make it optional, along with other_user_key 2020-01-30 16:46:12 +01:00
Benoit Marty
6282f81bc4 Remove typo 2020-01-30 16:46:12 +01:00
Valere
a5ca2b1d34 Fix / incoming start verif popup should not show when bottomsheet there 2020-01-30 16:36:13 +01:00
Valere
50d5ad3625 Self verification + toDevice Request 2020-01-30 16:35:42 +01:00
Valere
03c5e61b2e Fix / post merge 2020-01-30 16:35:06 +01:00
Valere
4ddd831d7f Prepare support for toDevice .request 2020-01-30 16:11:34 +01:00
Valere
ff95392e10 Fix / Refresh trust state on own keys/device trust change 2020-01-30 16:10:59 +01:00
Benoit Marty
e2c2c2418c Merge pull request #919 from vector-im/qr_step_validate
Qr step validate
2020-01-30 14:14:16 +01:00
Christopher Rossbach
e44dc347c6 Add "get it on F-Droid"
RiotX is on F-Droid now
2020-01-30 12:07:33 +01:00
Benoit Marty
fbd0bbc575 Improve clarity of the algorithm to enable encryption for DMs 2020-01-30 11:24:05 +01:00
ganfra
b848d0530f Update realm to 6.1.0: should fix some of the native crashes 2020-01-30 11:04:37 +01:00
Benoit Marty
2bccd19f84 QRcode: Url encode the keys 2020-01-30 10:17:04 +01:00
Benoit Marty
2111daea52 Add a step to confirm that other user has scanned the SR code 2020-01-30 10:09:59 +01:00
ganfra
9fc3fa7f19 Update some libs and remove incremental from dagger 2020-01-29 21:14:38 +01:00
Benoit Marty
57a13fa30d Sort room members by display names 2020-01-29 18:07:57 +01:00
Benoit Marty
c4649a5824 Merge pull request #916 from vector-im/debug_qr
Negotiate E2E by default for DMs (#907)
2020-01-29 18:02:43 +01:00
ganfra
71a02a58af Sync/Timeline: handle displayName isUnique 2020-01-29 17:30:31 +01:00
Benoit Marty
6f6c3184dd Avoid test if previous result is null 2020-01-29 17:13:41 +01:00
Benoit Marty
d7feb6dd5c Merge pull request #913 from vector-im/feature/rainbow
Rainbow
2020-01-29 16:35:34 +01:00
Benoit Marty
e6c3f7c77b Nicer API 2020-01-29 16:26:19 +01:00
Benoit Marty
8b6ffc2fb1 ktlint 2020-01-29 16:18:33 +01:00
Benoit Marty
ae36846aaf Negotiate E2E by default for DMs (#907) 2020-01-29 16:11:23 +01:00
Benoit Marty
237da5bb16 No need to have mutable list in param 2020-01-29 16:03:28 +01:00
ganfra
7f72af426b Timeline: fix getContext 2020-01-29 16:02:53 +01:00
Benoit Marty
a4abe5f552 Set timeout to 60s when creating a room 2020-01-29 16:00:07 +01:00
Benoit Marty
e1ddde5501 Make CreateRoomParams a regular data class 2020-01-29 14:23:32 +01:00
Valere
754ca3c582 Fix / fail to update usk when dl own keys 2020-01-29 14:00:02 +01:00
Benoit Marty
70b04dbaea Disable not passing test, to avoid waiting too long when running the test suite 2020-01-29 12:36:38 +01:00
Benoit Marty
b44b6726ed Also update the tests 2020-01-29 12:29:19 +01:00
Benoit Marty
80ec199135 Convert VerificationTxState to a sealed class 2020-01-29 12:00:49 +01:00
Benoit Marty
305dfd4c7a Merge pull request #911 from vector-im/feature/encryption_notice
Modify encryption notice
2020-01-29 10:32:23 +01:00
Benoit Marty
73bb4bb785 Merge pull request #912 from vector-im/feature/e2e_opt_out
e2e opt in when creating room (not DM)
2020-01-29 10:29:33 +01:00
Valere
1d84ccd64a Merge pull request #881 from vector-im/xsigning_sdk
Xsigning sdk
2020-01-29 10:26:46 +01:00
Valere
63e36b0403 Remove unused test 2020-01-29 10:16:57 +01:00
Valere
2c568b4de9 clean klint 2020-01-29 09:59:09 +01:00
Benoit Marty
27fe4e3680 Fix build and add tests 2020-01-29 09:44:53 +01:00
Benoit Marty
007b0cabf2 Add a few TUs 2020-01-28 22:43:10 +01:00
Benoit Marty
b2338dfcd3 Make the TU passes 2020-01-28 22:35:40 +01:00
Benoit Marty
6d7d4993a6 Add TUs for RainbowGenerator (not all passing) 2020-01-28 21:56:02 +01:00
Benoit Marty
da9b9f4864 Make the whole cell clickable 2020-01-28 21:31:02 +01:00
Benoit Marty
ef0b438a89 Give the possibility to enable encryption when creating room (#837) 2020-01-28 21:31:02 +01:00
Ganard
a8f783bbfa Add state events to chunks 2020-01-28 18:59:21 +01:00
Valere
9a79297e14 Merge pull request #910 from vector-im/qr_code_step_2
Qr code step 2
2020-01-28 18:11:09 +01:00
Valere
a57393cafa More log + quick fix in settings 2020-01-28 18:09:17 +01:00
Benoit Marty
e12de3fba0 Merge pull request #891 from vector-im/feature/event-unknown
Feature/event unknown
2020-01-28 17:30:02 +01:00
Benoit Marty
2eeeea3377 Encryption is enabled only for MEGOLM. 2020-01-28 17:19:22 +01:00
Benoit Marty
976a8fc568 Hide the algorithm when turning on e2e (#897) 2020-01-28 16:36:28 +01:00
Benoit Marty
b7ecfd997d Fix compilation issue after rebase 2020-01-28 16:02:20 +01:00
Benoit Marty
e0b3ea7e48 QrCode: WIP 2020-01-28 15:55:44 +01:00
Benoit Marty
9c829e62e6 QrCode: WIP 2020-01-28 15:55:44 +01:00
Benoit Marty
20c7e4c3ad QrCode: improve UI 2020-01-28 15:55:44 +01:00
Benoit Marty
69ab5e43d5 QrCode: WIP 2020-01-28 15:55:02 +01:00
Benoit Marty
f46023e84c QrCode: WIP 2020-01-28 15:55:02 +01:00
Benoit Marty
d8d465f70b QrCode: WIP 2020-01-28 15:53:57 +01:00
Benoit Marty
8659216955 QrCode: WIP 2020-01-28 15:53:57 +01:00
Benoit Marty
39e746413a QrCode: WIP 2020-01-28 15:53:57 +01:00
Benoit Marty
0aaba26f17 Rename classes 2020-01-28 15:53:57 +01:00
Benoit Marty
fc04833157 Rename parameter 2020-01-28 15:53:57 +01:00
Benoit Marty
f80861bed8 Add TODO 2020-01-28 15:53:57 +01:00
Benoit Marty
9e796067cc Do not support SHOW or SCAN if cross-signing is not enabled 2020-01-28 15:53:57 +01:00
Benoit Marty
fb5148fd43 Avoid to inject credential (again) 2020-01-28 15:52:17 +01:00
Benoit Marty
be77017209 Avoid injecting credentials. Inject userId and deviceId instead
And cleanup API
2020-01-28 15:48:09 +01:00
Benoit Marty
962b85b041 Add TODO 2020-01-28 15:48:09 +01:00
Benoit Marty
adc2d570eb QR code: handle the case where other user can scan QR codes 2020-01-28 15:48:09 +01:00
Benoit Marty
df49ab8362 QR code: update code which build URL 2020-01-28 15:48:09 +01:00
Benoit Marty
efc8cfb9a1 QR code: modify APIs 2020-01-28 15:48:09 +01:00
Benoit Marty
345824daa2 Keep on renaming 2020-01-28 15:48:09 +01:00
Benoit Marty
050eb0af9d Create dedicated View and Epoxy item for QrCode 2020-01-28 15:48:09 +01:00
Valere
ca4ed6e1bd Fix / Error management and clear keys 2020-01-28 15:35:11 +01:00
Ganard
bf7c53ecab Sync/pagination: get a working version 2020-01-28 14:46:26 +01:00
Valere
f021f8110d post merge 2020-01-28 12:04:19 +01:00
Valere
109ff4f908 Merge branch 'cross_signing' into xsigning_sdk 2020-01-28 11:33:54 +01:00
Valere
c9f0209ebf post merge fix 2020-01-28 11:23:37 +01:00
Valere
7daa088618 Merge branch 'develop' into cross_signing 2020-01-28 11:13:31 +01:00
Valere
83e44ac96e Fix / cross signing info live data not always updated 2020-01-28 11:02:12 +01:00
Ganard
15b0bea870 Use clone for retrofit request to be able to retry 2020-01-28 10:13:36 +01:00
Ganard
e5e62dc4a7 Fix SyncService and Alarm 2020-01-28 10:13:19 +01:00
Benoit Marty
f3e88c75cf Fix typo 2020-01-28 09:42:56 +01:00
Valere
ea6e8a6789 Basic debug screen to setup keys 2020-01-27 23:51:08 +01:00
Valere
6cece03998 Profile detailed device info + verify manually 2020-01-27 17:55:00 +01:00
Ganard
f3db43f317 Ellipsize: introduce EllipsizingTextView 2020-01-27 12:41:43 +01:00
Valere
08ae0b485a Profile Screen / Add show device list trust screen 2020-01-27 09:25:58 +01:00
Valere
665c577747 SDK / update trust on key change + live method in Service 2020-01-27 09:25:16 +01:00
ganfra
3a89a30056 Continue reworking sync/timeline events handling 2020-01-25 18:59:45 +01:00
Valere
d60351bcb7 Verify from RoomMember Profile 2020-01-24 19:15:23 +01:00
Ganard
1d8b81bb04 Try reworking events/timeline process [WIP] 2020-01-24 18:43:35 +01:00
Valere
a758efc018 Renamed room transport classes 2020-01-24 11:32:24 +01:00
Valere
d0addc4c4f Refactored Verification Classes 2020-01-24 11:29:26 +01:00
Valere
bb5179140c Update profile screen for xSigning 2020-01-24 09:14:32 +01:00
Benoit Marty
e9ea69f055 Add support for /rainbow and /rainbowme command (#879) 2020-01-23 23:34:21 +01:00
ganfra
7bcae75314 Remove some code from main thread 2020-01-23 20:31:18 +01:00
ganfra
4331d2ef47 Network: reword the strategy for handling NetworkConnectivity (remove Merlin) 2020-01-23 19:08:55 +01:00
Valere
e47791f290 Merge pull request #888 from vector-im/qr_code
Qr code
2020-01-23 16:41:23 +01:00
Valere
91ae96a153 QuickFix / Do not verify yourself in dm 2020-01-23 16:16:57 +01:00
Valere
0148949a4f Fix / prevent verification toaster to show when in good room 2020-01-23 16:13:46 +01:00
Valere
65cb812fc6 Fix / Unknown transaction when started by other after request 2020-01-23 16:04:29 +01:00
Valere
e8a4f1fb90 Fix: .cancel won't appear in debug show all 2020-01-23 16:04:03 +01:00
Benoit Marty
632832a651 Nearly same code for DefaultItem and NoticeItem 2020-01-23 15:44:41 +01:00
Benoit Marty
d530c64a84 Render defaultItem as other item: display user avatar
Also ensure bottom sheet always has a header, for user avatar and date
2020-01-23 15:35:46 +01:00
Benoit Marty
426e291ce9 i18n for RiotX limitation messages 2020-01-23 14:46:36 +01:00
Valere
1276d1f39d Update My device list + action to verify 2020-01-23 13:57:17 +01:00
Benoit Marty
4a1012cf81 Add TODOs 2020-01-23 11:48:08 +01:00
Benoit Marty
5819790c1b Distinguish Show SR code and Scan QR code capability 2020-01-23 11:25:44 +01:00
Benoit Marty
b3089343ad Support SCAN method (WIP) 2020-01-23 10:47:29 +01:00
ganfra
c65f25d7ae Rx: fix startWith on mainThread 2020-01-23 10:18:22 +01:00
Benoit Marty
37b950897f Base64 no wrap and extension for the reverse operation 2020-01-23 10:17:07 +01:00
ganfra
fee2ec6b66 Scroll when event build come from sync/send + remove use of monarchy writeAsync 2020-01-22 20:33:52 +01:00
Benoit Marty
d2fab91e9d Improve code 2020-01-22 19:08:21 +01:00
Benoit Marty
c323b61575 Ignore typo 2020-01-22 18:27:59 +01:00
Benoit Marty
0e55f81879 Ensure all is escaped properly 2020-01-22 18:26:34 +01:00
Benoit Marty
cbf418c401 Update after MSC change 2020-01-22 18:22:01 +01:00
Benoit Marty
41c691f26c Create QrCodeData class and method to convert to URL and vice versa, with TUs 2020-01-22 17:58:25 +01:00
Benoit Marty
81337d1624 Also keep the same parameter order: (userId, deviceId) to avoid silly errors 2020-01-22 17:00:16 +01:00
Benoit Marty
79df6b8402 Start plugin QR code to the code 2020-01-22 15:56:43 +01:00
Benoit Marty
537b1be0c5 Update wording 2020-01-22 15:26:26 +01:00
Benoit Marty
c1259161e5 QRCode: generate and scan QRCodes 2020-01-22 15:03:56 +01:00
ganfra
76065ac4fc Read: allow setting read marker and read receipt to latest known event independently 2020-01-22 14:43:39 +01:00
ganfra
d93050240a Start reworking networkConnectivityCheck (WIP) 2020-01-22 14:41:42 +01:00
Benoit Marty
75e39535bc Merge pull request #883 from vector-im/feature/share
Improve the room list when sharing to RiotX
2020-01-22 11:49:50 +01:00
Benoit Marty
c971f18fc0 Add section header when displaying room list to share (#771) 2020-01-22 11:49:30 +01:00
Benoit Marty
3c2fa40b58 Sharing things to RiotX: sort list by recent room first (#771) 2020-01-22 11:49:04 +01:00
Benoit Marty
0b74863c6d Merge pull request #877 from vector-im/feature/version_name
F-Droid: fix the "-dev" issue in version name (#815)
2020-01-22 11:45:36 +01:00
Benoit Marty
dca950140d Merge branch 'develop' into feature/version_name 2020-01-22 11:45:27 +01:00
Benoit Marty
a13a78ccc0 Merge pull request #874 from vector-im/feature/authors
Builds repoductibility and Authors file
2020-01-22 11:43:51 +01:00
Benoit Marty
7327dc97b4 Merge pull request #876 from vector-im/feature/room_settings
Room settings, and enable encryption in unencrypted rooms (#212)
2020-01-22 11:40:26 +01:00
ganfra
2bddf61afe Update realm to 6.1.0: should fix some of the native crashes 2020-01-21 15:15:29 +01:00
Benoit Marty
da3e547d82 Create facility extension to observe ViewEvents 2020-01-21 15:08:49 +01:00
Valere
a0aa1f34d3 Quick Fix todevice verif broken
Added dbg screen for cross signing
2020-01-21 14:58:06 +01:00
ganfra
d1b8d81fb1 Fix double read receipts 2020-01-21 14:17:04 +01:00
Benoit Marty
e81c804ed6 Ensure when will be exhaustive 2020-01-21 12:51:28 +01:00
Benoit Marty
be371f9279 Introduce ViewEvents in ViewModel and code harmonization 2020-01-21 12:51:28 +01:00
Valere
a6364f0be5 remove dead code 2020-01-21 10:25:57 +01:00
Valere
390879e3fd Added check self keys + force DL after initialize Xsigning 2020-01-21 10:25:57 +01:00
Valere
6ab540045b Refactoring / deprecation of MXDeviceInfo
introduced TrustLevels
2020-01-21 10:25:57 +01:00
Valere
98ba2d39a8 SAS verif, support signing and verification of Cross Signing 2020-01-21 10:25:57 +01:00
Valere
859c75df98 Initial commit 2020-01-21 10:25:57 +01:00
Valere
ea9166e0c6 Merge pull request #811 from vector-im/verification_toasters
[Cross Signing DM Verif]  Basic Incoming request toast + cleaning
2020-01-21 10:21:24 +01:00
Benoit Marty
d672313649 Room settings: use boolean instead of Async 2020-01-20 17:41:29 +01:00
Benoit Marty
f5e6b4b857 F-Droid: fix the "-dev" issue in version name (#815) 2020-01-20 16:08:57 +01:00
Benoit Marty
28db05e509 Cleanup and copy wording from Riot-Web 2020-01-20 15:39:14 +01:00
Benoit Marty
56b140fcb4 Room settings: rename stuff for genericity 2020-01-20 15:23:40 +01:00
Benoit Marty
eee6969b02 Room settings, and enable encryption in unencrypted rooms (#212) 2020-01-20 15:11:21 +01:00
Benoit Marty
825427b7b0 Add a first content into the AUTHORS file 2020-01-17 16:50:18 +01:00
Benoit Marty
8c32796d5c Ensure builds are reproducible (#842) 2020-01-17 16:06:58 +01:00
Valere
e45c1e6c2a Fix / post merge issues 2020-01-17 15:17:16 +01:00
Benoit Marty
188cd6beff Verification: improve blinking effect (not perfect yet) 2020-01-17 15:05:06 +01:00
Benoit Marty
aaeb54db7c Verification: Introduce VerificationMethod enum 2020-01-17 15:05:06 +01:00
Benoit Marty
92f26bc20a Verification: migrate to Epoxy - Cleanup 2020-01-17 15:05:06 +01:00
Benoit Marty
fc22b7988f Verification: migrate to Epoxy - Add missing icons 2020-01-17 15:05:06 +01:00
Benoit Marty
878bae1c45 Verification: migrate to Epoxy - Choose Fragment 2020-01-17 15:05:06 +01:00
Benoit Marty
a8e81d95cf Verification: migrate to Epoxy - Disable item animation 2020-01-17 15:05:06 +01:00
Benoit Marty
cd1665a8e8 Verification: migrate to Epoxy - Conclusion 2020-01-17 15:05:06 +01:00
Benoit Marty
7170471686 Verification: migrate to Epoxy - create sub packages 2020-01-17 15:05:06 +01:00
Benoit Marty
98020404ff Verification: migrate to Epoxy - rename package 2020-01-17 15:05:06 +01:00
Benoit Marty
b2348427bd Verification: migrate to Epoxy - Emoji Fragment 2020-01-17 15:05:06 +01:00
Benoit Marty
832df59b58 Verification: migrate to Epoxy - Request Fragment 2020-01-17 15:05:06 +01:00
Benoit Marty
32689facc5 Verification: migrate to Epoxy - Request Fragment 2020-01-17 15:05:06 +01:00
Benoit Marty
d3071e5816 Rename layout for consistency 2020-01-17 15:04:36 +01:00
Benoit Marty
83a6f564c3 Ensure BottomSheets call ButterKnife unbinder 2020-01-17 15:04:36 +01:00
Benoit Marty
3b420dbb50 typo 2020-01-17 15:04:36 +01:00
Benoit Marty
9fe155bafd postWork now returns the Cancellable 2020-01-17 15:04:36 +01:00
Benoit Marty
3c982866d8 Restore lost Fragment binding... 2020-01-17 15:04:36 +01:00
Benoit Marty
494ad83704 Inject WorkManagerProvider, to avoid injecting the Android context
Also ensure WorkManager uses a distinct tags for each session (for future multi-sessions support)
2020-01-17 15:04:36 +01:00
Benoit Marty
4543658ae0 Extends SessionWorkerParams 2020-01-17 15:04:36 +01:00
Benoit Marty
689fd1ea90 Fix issue with SessionId for the worker
Also rename some variables
2020-01-17 15:04:36 +01:00
Valere
a95410c118 fix rebase 2020-01-17 15:04:36 +01:00
Valere
8749e49e80 Basic Incoming request toast + cleaning 2020-01-17 15:04:36 +01:00
Valere
8400ab6efe Merge branch 'develop' into cross_signing 2020-01-17 14:57:08 +01:00
Benoit Marty
d1699279fe Version++ 2020-01-17 14:25:25 +01:00
Benoit Marty
115058124c Merge branch 'release/0.13.0' into develop 2020-01-17 14:24:10 +01:00
Benoit Marty
7604748d3f Prepare release 0.13.0 2020-01-17 14:23:58 +01:00
Benoit Marty
d46a3ab87f Update CHANGES.md 2020-01-17 14:10:47 +01:00
Benoit Marty
b375463aec Merge pull request #854 from vector-im/feature/profiles_improvements
Feature/profiles improvements
2020-01-17 12:22:16 +01:00
Benoit Marty
cfb752c220 Merge pull request #851 from vector-im/feature/code_style
Share the same code formatting rules
2020-01-17 12:21:34 +01:00
Benoit Marty
c59712732a Introduce listener type for Epoxy items 2020-01-17 12:14:24 +01:00
Benoit Marty
626ebd9c63 Merge pull request #850 from vector-im/feature/e2e_attachments_cleanup
Feature/e2e attachments cleanup
2020-01-17 12:12:48 +01:00
Benoit Marty
5148d7ab46 Room profile: open it also when clicking on the room avatar 2020-01-17 10:15:04 +01:00
Benoit Marty
8c2a55a5a2 Settings: restore "Show read receipts" setting and create categories of per Riot-Web 2020-01-17 10:10:46 +01:00
Benoit Marty
34b6dd4270 Room profile: open room member profile from Event bottom sheet 2020-01-16 21:48:10 +01:00
Benoit Marty
79a68a36bd Room profile: ensure RoomMemberSummaries order is guaranteed 2020-01-16 21:29:05 +01:00
Benoit Marty
78408fa0ec Room profile: create extension join for Collections 2020-01-16 21:18:14 +01:00
Benoit Marty
b56ee9a377 Room profile: fix issue with divider color 2020-01-16 20:53:38 +01:00
Benoit Marty
9eff459ed6 Room profile: remove an extra divider 2020-01-16 16:43:37 +01:00
Benoit Marty
cd44b60bd5 Room profile: make link in room topic clickable 2020-01-16 16:36:56 +01:00
Benoit Marty
17ed8da57a Room profile: fix issue with icon 2020-01-16 16:27:21 +01:00
Benoit Marty
8ae51a95c5 Add formatting policy in the Contributing guide 2020-01-16 16:02:41 +01:00
Benoit Marty
f80f22fed2 XML formatting rule 2020-01-16 15:58:52 +01:00
Benoit Marty
fa57d0f6d5 160 char max per line 2020-01-16 15:27:00 +01:00
Benoit Marty
1104b5d483 DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION 2020-01-16 14:26:52 +01:00
Benoit Marty
464462022c Kotlin code convention 2020-01-16 14:17:29 +01:00
Benoit Marty
1c63d3f8f0 Add rule 2020-01-16 14:15:50 +01:00
Benoit Marty
a916bd4ba8 Share the same code formatting rules 2020-01-16 14:05:14 +01:00
Benoit Marty
15e2c9f3a3 Fix formatting 2020-01-16 12:55:55 +01:00
Benoit Marty
f1a2fb51f5 Properly configure Snackbar styles 2020-01-16 12:51:33 +01:00
Benoit Marty
b0aa9fbd8f Inform user when the download of a file starts 2020-01-16 12:20:39 +01:00
Benoit Marty
d72f1ac576 Avoid exposing internal classes 2020-01-16 11:36:53 +01:00
Benoit Marty
ca157c7567 Better logs 2020-01-16 10:57:08 +01:00
Benoit Marty
ae26bf3369 Signout also clear cache 2020-01-16 10:57:08 +01:00
Benoit Marty
159c96681f Improve attachment encryption and decryption code 2020-01-16 10:57:08 +01:00
Benoit Marty
96d6b75037 Fix broken link 2020-01-16 10:57:08 +01:00
Benoit Marty
72e6181f00 Merge pull request #839 from vector-im/feature/developer
Show all hidden event in the timeline when the developer settings is ON
2020-01-16 10:56:27 +01:00
Benoit Marty
4ae09b8716 Merge pull request #831 from david1hyman/file-decryption-fix
File decryption path was writing incorrect stream to file
2020-01-16 10:50:15 +01:00
ganfra
f128ed437f Merge pull request #843 from vector-im/feature/room_profile
Feature/room profile
2020-01-15 19:17:50 +01:00
ganfra
11c8c8c2bd Fix fdroid background sync 2020-01-15 19:16:50 +01:00
ganfra
2c331671ee Fix string 2020-01-15 17:44:38 +01:00
ganfra
b44ddcfd61 Clean code after Benoit's review #2 2020-01-15 14:57:21 +01:00
ganfra
7c0f2d6e32 Test: fix import 2020-01-15 11:48:02 +01:00
ganfra
52de14b1b5 Clean code after Benoit's review 2020-01-15 11:46:33 +01:00
ganfra
d6e6092eea Profile: add PowerLevelContent for building future actions + fix divider 2020-01-14 19:14:15 +01:00
ganfra
9671a77e5d Clean code and update CHANGES 2020-01-14 18:48:13 +01:00
ganfra
d3415d345f Merge branch 'develop' into feature/room_profile 2020-01-14 18:35:01 +01:00
ganfra
df4df81ef3 Profile: handle ignore/unignore action + adjust UI 2020-01-14 17:08:21 +01:00
Valere
a7c948815c Merge branch 'develop' into cross_signing 2020-01-14 12:31:29 +01:00
Benoit Marty
9d5197b1c8 Show all hidden event in the timeline when the developer settings is ON 2020-01-13 22:47:41 +01:00
ganfra
162f0949fa Profile: Start fetching profile info from a user 2020-01-13 18:44:01 +01:00
ganfra
ae1a24e948 Room member profile: branch the UI and fix some UI issues 2020-01-13 16:49:14 +01:00
Benoit Marty
b5fead18fe Merge pull request #833 from vector-im/feature/typing
Send and render typing events (#564)
2020-01-13 15:17:43 +01:00
Benoit Marty
3c682430d9 Merge pull request #829 from vector-im/feature/stab
Feature/stab
2020-01-13 15:13:07 +01:00
Benoit Marty
717965bc37 Update comment 2020-01-13 15:12:39 +01:00
Benoit Marty
ecc463e920 Cleanup and fix a bug 2020-01-13 10:13:12 +01:00
Benoit Marty
f3e52b96c0 Cleanup 2020-01-11 22:12:56 +01:00
Benoit Marty
dd81fce8d8 Send and render typing events (#564) 2020-01-11 20:50:09 +01:00
Valere
7354eab061 Post merge fixes 2020-01-11 10:16:09 +01:00
David Hyman
1ae58aa6ad DefaultFileService - code was passing the inputStream to the decryption method
but not storing the output of the method anywhere
then it was writing inputStream to file and returning that file handle
changed inputStream to var and used it to store output of decryption method
2020-01-10 14:53:40 -05:00
Valere
fb9abefe59 Merge branch 'develop' into cross_signing 2020-01-10 18:38:54 +01:00
Benoit Marty
095216349e Exception -> Throwable 2020-01-10 18:35:29 +01:00
Benoit Marty
550908fa70 Render events m.room.encryption and m.room.guest_access in the timeline 2020-01-10 18:30:10 +01:00
Benoit Marty
0dbca829ea Fix crash with RoomCreationParams 2020-01-10 18:07:14 +01:00
Benoit Marty
03b5b098c7 Change the way versionCode is computed (#827) 2020-01-10 17:29:34 +01:00
ganfra
171ec4fbdc Room member list: group by power level 2020-01-10 17:03:11 +01:00
Benoit Marty
32d2daee3c Exclude current user from autocompletion with room members 2020-01-10 16:28:14 +01:00
Benoit Marty
de84bb7535 Use more developerMode() 2020-01-10 11:03:42 +01:00
ganfra
81712ae736 RoomProfile: fix some rendering + change anim 2020-01-09 19:47:54 +01:00
ganfra
289951ea4a RoomMemberList : start showing items 2020-01-09 15:54:36 +01:00
Benoit Marty
8c9c65837d Version++ 2020-01-09 15:32:37 +01:00
Benoit Marty
d486e613d8 Merge branch 'release/0.12.0' into develop 2020-01-09 15:31:29 +01:00
Benoit Marty
598d67234c Prepare release 0.12.0 2020-01-09 15:31:13 +01:00
Benoit Marty
fea4f2e129 Merge pull request #816 from vector-im/feature/integration_tests
Start porting of integration tests - Fix issue with multiple sessions
2020-01-09 15:28:29 +01:00
Benoit Marty
687ea1b5b3 ktlint 2020-01-09 15:28:16 +01:00
Benoit Marty
47e3b8ec46 Ensure foreground notification is always displayed 2020-01-09 15:09:37 +01:00
Benoit Marty
dd8c908dc7 Code cleanup 2020-01-09 15:02:39 +01:00
Benoit Marty
9775e8c32b Fix crash in syncService 2020-01-09 15:01:16 +01:00
Benoit Marty
e3205fb493 Fix compilation issue after rebase 2020-01-09 14:26:36 +01:00
Benoit Marty
35f011ba37 Fix ktlint issues 2020-01-09 14:20:17 +01:00
Benoit Marty
ed773dbb96 TI: Introduce doSync method 2020-01-09 14:20:17 +01:00
Benoit Marty
fa821826d2 TI: Import ExportEncryption test (passing) 2020-01-09 14:20:17 +01:00
Benoit Marty
293e3e3ce6 TI: Import AttachmentEncryption test (passing) 2020-01-09 14:20:17 +01:00
Benoit Marty
4244c0e48d TI: Import SAS Test - WIP 2020-01-09 14:20:17 +01:00
Benoit Marty
76e45431da TI: Import keys backup tests 2020-01-09 14:20:17 +01:00
Benoit Marty
f3fb07079e Cleanup tests 2020-01-09 14:20:17 +01:00
Benoit Marty
3ceac70536 Enable encryption on a room, SDK part (#212) 2020-01-09 14:20:17 +01:00
Benoit Marty
0f7209df1f TI: finish the work to identify a session with a sessionId 2020-01-09 14:20:17 +01:00
Benoit Marty
e177251ec0 TI: inject EventBus to allow multiple sessions - WIP 2020-01-09 14:20:17 +01:00
Benoit Marty
6746f68411 TI: create account 2020-01-09 14:20:17 +01:00
Benoit Marty
fc6d845c0d Import tests from legacy SDK 2020-01-09 14:20:17 +01:00
Benoit Marty
93cdce6c3e Cleanup tests 2020-01-09 14:20:17 +01:00
Benoit Marty
ae3381227c Add Unit tests from legacy SDK 2020-01-09 14:20:17 +01:00
Benoit Marty
b6a1ff1ca4 Import string from Riot legacy 2020-01-09 14:17:17 +01:00
Benoit Marty
7ec0227528 Merge pull request #824 from vector-im/feature/wording
Email domain can be limited on some homeserver, i18n of the displayed error (#754)
2020-01-09 12:26:28 +01:00
ganfra
15639b45cf Introduce RoomMemberProfile files 2020-01-09 12:10:49 +01:00
ganfra
f18ec8d021 Merge branch 'develop' into feature/room_profile 2020-01-09 11:56:09 +01:00
Benoit Marty
898bf234da Merge pull request #792 from vector-im/feature/stabilization
Feature/stabilization
2020-01-09 11:43:52 +01:00
Benoit Marty
3d0d95c371 Email domain can be limited on some homeserver, i18n of the displayed error (#754) 2020-01-09 11:34:57 +01:00
ganfra
bd4a595f96 ChunkEntityTest: make it compile again 2020-01-09 11:19:08 +01:00
Benoit Marty
0f7d59a8c7 Cleanup during PR review 2020-01-09 09:42:34 +01:00
Benoit Marty
e14b9b3b20 Fix test compilation issue 2020-01-09 08:03:14 +01:00
Benoit Marty
43c4e20819 Merge pull request #820 from vector-im/feature/developer_mode_crash
Developer mode: Fail-fast (#745)
2020-01-09 07:56:06 +01:00
Benoit Marty
5312b44359 Merge pull request #821 from vector-im/feature/query_latch
Remove CountDownLatch (inspired from #419)
2020-01-09 07:55:38 +01:00
ganfra
8c4d8763a2 Merge branch 'develop' into feature/stabilization 2020-01-08 22:28:08 +01:00
ganfra
383605274c Introduce a very simple query langage and refact autocomplete 2020-01-08 22:17:32 +01:00
Benoit Marty
8032490606 Remove CountDownLatch (inspired from #419) 2020-01-08 18:58:51 +01:00
Benoit Marty
a458997ce0 Merge pull request #818 from vector-im/feature/oss
Exclude play-services-oss-licenses library from F-Droid build (#814)
2020-01-08 18:28:31 +01:00
Benoit Marty
29f152f349 Fix CI 2020-01-08 18:21:01 +01:00
Benoit Marty
6ca3ba6c9b Merge pull request #806 from Bubu/fix_697
call /join/{roomIdOrAlias} instead of /rooms/{roomId}/join
2020-01-08 18:17:34 +01:00
Benoit Marty
f4492e570d Merge branch 'develop' into fix_697 2020-01-08 18:17:23 +01:00
Benoit Marty
587fefedb5 Merge pull request #809 from Bubu/fix_807
set homeserver field when populating room directory list
2020-01-08 18:12:42 +01:00
Benoit Marty
943be39e1a Merge branch 'develop' into fix_807 2020-01-08 18:12:22 +01:00
Benoit Marty
616f3d3345 Merge pull request #817 from vector-im/feature/fab_scroll
Show skip to bottom FAB while scrolling down (#752)
2020-01-08 18:07:10 +01:00
Benoit Marty
2b8ecae8e3 Fix CI 2020-01-08 18:05:26 +01:00
Benoit Marty
17c4013383 Developer mode: Fail-fast (#745) 2020-01-08 17:58:26 +01:00
Benoit Marty
d662b4a9b4 Exclude play-services-oss-licenses library from F-Droid build (#814) 2020-01-08 15:57:35 +01:00
Benoit Marty
501ac36040 Reduce size of RoomDetailFragment 2020-01-08 15:05:20 +01:00
Benoit Marty
7575cb286e Show skip to bottom FAB while scrolling down (#752) 2020-01-08 15:05:20 +01:00
ganfra
c60b4ddb5a Timeline: don't wait for realm notification to come back, use it right away to init 2020-01-08 13:59:43 +01:00
ganfra
9970d7ffa0 SDK: get some better queries 2020-01-08 11:55:22 +01:00
ganfra
2dd2a8db6c Emoji data source as singleton 2020-01-08 11:54:42 +01:00
Benoit Marty
8ef5c60e2e RageShake is enabled by default 2020-01-08 11:43:21 +01:00
ganfra
03c3c9ae57 Timeline: clear unlinked should use new parameters 2020-01-07 18:15:48 +01:00
ganfra
38c198fe02 Rx: fetch first before returning live data results 2020-01-07 18:15:07 +01:00
ganfra
42c7421b05 Merge branch 'develop' into feature/stabilization 2020-01-07 14:42:38 +01:00
ganfra
19fb3ce032 Merge branch 'develop' into feature/stabilization 2020-01-07 14:28:23 +01:00
Benoit Marty
5a7f4bed43 ktlint 2020-01-07 14:24:26 +01:00
Benoit Marty
03734a7ad5 Merge pull request #802 from vector-im/feature/sessionId
Identify a session with the userId and the deviceId
2020-01-07 14:23:09 +01:00
ganfra
d710106bbb Clean code 2020-01-07 14:09:04 +01:00
ganfra
f09bf61750 Room detail: try to get some better perfs with fetching data. LiveData is slow as we only use one HandlerThread at the time. Might want Realm 7.0 and frozen objects to rework that 2020-01-07 13:31:34 +01:00
ganfra
f9487f8995 Work on timeline 2020-01-06 18:44:04 +01:00
ganfra
99c523b710 Update libs 2020-01-06 18:43:34 +01:00
ganfra
3cc15387ae Realm: compatch on launch 2020-01-06 18:41:09 +01:00
Benoit Marty
6245763577 Merge pull request #789 from vector-im/feature/christmas_fix
Auto completion for emojis
2020-01-06 14:20:44 +01:00
Benoit Marty
448552d287 Move list of Quick Emoji to Emoji Data Source 2020-01-06 13:48:34 +01:00
Benoit Marty
9ecceafb96 Move comment 2020-01-06 13:47:06 +01:00
Benoit Marty
92d7ebe94f Update changes 2020-01-06 13:47:06 +01:00
Benoit Marty
0e5fcd071c Completion on emoji: display the first 50 results 2020-01-06 13:46:37 +01:00
Benoit Marty
c8e67f8ab4 Completion on emoji WIP 2020-01-06 13:46:10 +01:00
Benoit Marty
5fa2acf60b Completion on emoji 2020-01-06 13:46:10 +01:00
Benoit Marty
9e73e95f55 Ensure there is never twice the same emoji 2020-01-06 13:46:10 +01:00
Benoit Marty
8b4c51139d Completion on emoji WIP 2020-01-06 13:46:10 +01:00
Benoit Marty
8597c2b9a2 Improve API 2020-01-06 13:46:10 +01:00
Benoit Marty
d88e5d8af8 DRY 2020-01-06 13:46:10 +01:00
Benoit Marty
c4fe0bdb7f Split into small methods 2020-01-06 13:46:10 +01:00
Benoit Marty
d73a1135ae Extract AutoComplete feature from RoomDetailFragment 2020-01-06 13:46:10 +01:00
Benoit Marty
ed097bcf37 Merge pull request #798 from vector-im/feature/settings_cleanup
Feature/settings cleanup
2020-01-06 13:41:50 +01:00
Benoit Marty
01db856a5d Improve (a bit) the devices list UX/UI 2020-01-06 10:51:30 +01:00
Benoit Marty
a00f51a264 Settings: rename "developer mode" to "advanced settings" 2020-01-06 10:32:36 +01:00
Valere
06b41af467 Merge pull request #793 from vector-im/outgoing_dm_verif
BottomSheet UX for verification
2020-01-06 10:22:27 +01:00
Marcus Hoffmann
9e8217082c set homeserver field when populating room directory list
fixes #807

Signed-off-by: Marcus Hoffmann <bubu@bubu1.eu>
2020-01-06 03:48:53 +01:00
Marcus Hoffmann
ce73007157 call /join/{roomIdOrAlias} instead of /rooms/{roomId}/join
The former endpoint doesn't work for joining over federation, the
server_name parameter is ignored.

Fixes #697

Signed-off-by: Marcus Hoffmann <bubu@bubu1.eu>
2020-01-06 01:01:59 +01:00
Valere
c2cd149299 Fix / accept button was not starting the verify sheet
Was launching start sheet, because request was not known by VerificationService. Due to message observer blocked trying to download keys..
2020-01-03 19:06:23 +01:00
Valere
08ed8d4fa7 Code review 2020-01-03 17:38:33 +01:00
Benoit Marty
f432d15757 Ensure key aliases are always computed the same way 2020-01-03 16:20:43 +01:00
Benoit Marty
215abea10a Introduce @SessionId 2020-01-03 16:20:43 +01:00
Benoit Marty
160927e7b5 Split code into several methods 2020-01-03 16:20:43 +01:00
Benoit Marty
c2e7e33050 Update SessionParamsEntity primaryKey to include deviceId 2020-01-03 16:20:43 +01:00
Benoit Marty
455448806d Merge pull request #799 from vector-im/feature/fix_crash
Fix crash when opening room creation screen from the room filtering screen
2020-01-02 18:57:17 +01:00
Benoit Marty
a969443517 Fix crash when opening room creation screen from the room filtering screen 2020-01-02 18:53:35 +01:00
Benoit Marty
1bd85082c3 Auto-review 2020-01-02 18:45:44 +01:00
Benoit Marty
de1d79b637 Remove Preference divider and cleanup prefs 2020-01-02 18:27:46 +01:00
Benoit Marty
8e478e78e1 Disable pref unused 2020-01-02 18:17:54 +01:00
Benoit Marty
96c9293edc Rageshake: vibrate 2020-01-02 18:15:23 +01:00
Benoit Marty
5c26f66523 Rageshake: settings for sensitivity 2020-01-02 17:42:44 +01:00
Valere
d1233e8470 Fix / tap on accept shows request button instead of start 2020-01-02 17:04:41 +01:00
Benoit Marty
5a24f78c05 Hide non working settings (#751) 2020-01-02 16:24:31 +01:00
Valere
bf28f14b8b Fix / Decline request was not implemented 2020-01-02 16:13:13 +01:00
Benoit Marty
703a1a034d Developer mode: hide show (decrypted) source actions 2020-01-02 16:11:44 +01:00
Benoit Marty
7d744f7d7f Developer mode: UI
And some cleanup
2020-01-02 16:01:47 +01:00
Benoit Marty
8dff196716 Device list: remove the detail dialog: handle the actions directly in the list 2020-01-02 15:44:47 +01:00
Valere
52c25b803f cleaning 2020-01-02 15:16:45 +01:00
Benoit Marty
6b2703f6ce Device list is now on a dedicated Fragment
New request to get info on the current device for VectorSettingsSecurityPrivacyFragment. The whole device list is only retrieved in the new Fragment
2020-01-02 15:05:17 +01:00
Valere
b26318f15c Fix / Cancel messages was not sent 2020-01-02 12:51:12 +01:00
Valere
f541661059 Use workers to send verification messages 2020-01-02 11:52:27 +01:00
ganfra
e32d242e38 Timeline: remove use of isUnlinked method as it slows down the insertion a lot 2019-12-31 12:58:43 +01:00
Valere
5b210df7c5 Manage done states + cleaning 2019-12-31 10:36:10 +01:00
ganfra
787908287c Member events: cache all over the session 2019-12-31 08:07:32 +01:00
Valere
935b3d7f3f cleaning 2019-12-30 20:18:08 +01:00
ganfra
8156b754c1 RecyclerView: introduce view pool 2019-12-30 19:54:39 +01:00
ganfra
03fd474aa8 Member events: try to cache (WIP) 2019-12-30 19:53:36 +01:00
Valere
3c4506cb58 merge madness ?? 2019-12-30 19:52:48 +01:00
Valere
3eed9b5083 cleaning 2019-12-30 18:42:32 +01:00
Valere
6bf3a703df BottomSheet UX 2019-12-30 18:01:06 +01:00
Valere
2152af8851 klint 2019-12-30 17:54:44 +01:00
Valere
5b33a42f8a FIx / missing strings after merge 2019-12-30 17:36:33 +01:00
Valere
a73cd61b96 WIP 2019-12-30 15:16:11 +01:00
Valere
4edd5e3530 Added SAS do not match api 2019-12-30 14:32:58 +01:00
Valere
4c0cbca4cb Support .verification.ready event 2019-12-30 14:32:58 +01:00
Valere
308b15b908 Fix / m.key.verification.key was not sent in toDevice mode 2019-12-30 14:32:04 +01:00
Valere
38906084d1 WIP 2019-12-30 14:32:04 +01:00
Valere
0997d9abf4 Merge branch 'develop' into cross_signing 2019-12-30 14:27:47 +01:00
ganfra
6ad914154a Update some libs 2019-12-30 10:46:25 +01:00
ganfra
cba7e460eb Action bottom sheet: fix deprecated constraints 2019-12-27 18:54:28 +01:00
ganfra
6794173321 Room detail: fix crash with banner 2019-12-27 18:54:07 +01:00
ganfra
92f4288d3e Realm: update realm lib version 2019-12-27 17:16:44 +01:00
ganfra
8109262cbb Home: fix double tab selection 2019-12-27 17:16:30 +01:00
ganfra
037bf45884 Sync: use foreground service on every android version 2019-12-27 17:09:57 +01:00
ganfra
833a5a37a2 Pill: fix blink and clean files 2019-12-27 10:24:58 +01:00
ganfra
00f316ba5d Room members: introduce RoomMemberEntity to be able to query. Still work to do. 2019-12-26 19:51:03 +01:00
ganfra
dfd8181754 Room profile: start creating some classes and use shared action. 2019-12-20 20:28:27 +01:00
Benoit Marty
90f2199eb7 Merge pull request #785 from vector-im/feature/initial_sync
Feature/initial sync
2019-12-20 18:18:32 +01:00
Benoit Marty
63828bc159 Merge branch 'develop' into feature/initial_sync 2019-12-20 17:55:04 +01:00
Benoit Marty
35b4d90e0d ktlint 2019-12-20 17:54:35 +01:00
Benoit Marty
4fe9c52737 Move permission to the main AndroidManifest 2019-12-20 17:54:02 +01:00
Benoit Marty
c54358831f Group throwable extension together 2019-12-20 17:45:32 +01:00
ganfra
a9d016ae79 Merge branch 'develop' into feature/room_profile 2019-12-20 16:43:16 +01:00
Benoit Marty
fcdaf14b01 Merge pull request #786 from vector-im/feature/room_alias_rendering
Autocompletion and pills for rooms and groups
2019-12-20 14:58:38 +01:00
ganfra
83126d5f55 Fix android tests not working 2019-12-20 11:54:59 +01:00
ganfra
e13281dc97 Update CHANGES and clean code 2019-12-20 11:27:26 +01:00
Benoit Marty
3cc65b1e71 ktlint 2019-12-20 11:05:54 +01:00
Benoit Marty
0ccb975d43 Disable MatrixLinkify 2019-12-20 11:04:06 +01:00
Benoit Marty
54f2ac0d8c Better comment 2019-12-20 10:59:41 +01:00
Benoit Marty
3ee5a7f54d Better code 2019-12-20 10:55:08 +01:00
Benoit Marty
3b0624ea40 Fix issue with "in reply to" link 2019-12-20 10:54:48 +01:00
Benoit Marty
c992d32afd Improve algo 2019-12-20 10:23:45 +01:00
Benoit Marty
c5739abe32 Update changes.md 2019-12-20 10:16:17 +01:00
Benoit Marty
3ac473d945 Remove extra blank line 2019-12-20 10:15:53 +01:00
Benoit Marty
c79b35b089 Autocomplete item layout 2019-12-20 10:15:11 +01:00
Benoit Marty
8dce98c538 Autocompletion: group (including pills for groups) 2019-12-20 02:54:48 +01:00
Benoit Marty
543c07fd69 Render pills for room links 2019-12-20 01:23:45 +01:00
Benoit Marty
05a788453f More generic name 2019-12-20 00:47:47 +01:00
Benoit Marty
c31b64771b Autocompletion: disable animation on the recycler view items 2019-12-20 00:42:19 +01:00
Benoit Marty
92f43a591a Autocompletion for room canonical alias 2019-12-20 00:38:42 +01:00
Benoit Marty
3a829bdfe8 Fix command truncation 2019-12-20 00:05:04 +01:00
Benoit Marty
237b22df59 Fix lots of trouble with the completion popup (resize, change mode, etc.) - next step 2019-12-19 20:31:36 +01:00
Benoit Marty
c18be94986 Fix lots of trouble with the completion popup (resize, change mode, etc.) 2019-12-19 20:03:10 +01:00
Benoit Marty
d342356f29 Add missing state events to the list (not sure about the side effects) 2019-12-19 19:48:30 +01:00
Benoit Marty
07817b69c2 Rename some event type 2019-12-19 19:46:09 +01:00
Benoit Marty
e73970d61b Render aliases and canonical alias change in the timeline 2019-12-19 19:39:35 +01:00
ganfra
0eb0870d6c AvatarRenderer: allow to pass GlideRequests too (fix home group avatar) 2019-12-19 18:29:46 +01:00
ganfra
55748a4af4 Merge branch 'develop' into feature/initial_sync 2019-12-19 17:49:45 +01:00
Benoit Marty
51d6b8828d Version++ 2019-12-19 16:46:01 +01:00
Benoit Marty
9a7cd3f270 Merge branch 'release/0.11.0' into develop 2019-12-19 16:44:27 +01:00
ganfra
a6afd2e904 Timeline: handle failure when navigating to an unknown event (+ clean some files) 2019-12-19 16:10:59 +01:00
ganfra
7bb8cb0682 Permalink: fix nav to same room 2019-12-19 13:42:15 +01:00
ganfra
a4ea9a09ad Room factory: add scope to avoid recreate all the dependencies 2019-12-19 13:41:57 +01:00
Valere
94125a0215 Merge branch 'develop' into cross_signing 2019-12-19 10:15:47 +01:00
Valere
d97402f757 Merge pull request #767 from vector-im/dm_verif_incoming_timeline
Dm verif incoming timeline
2019-12-19 10:12:55 +01:00
ganfra
5bde7b9f17 Read marker: fix banner visibility when following permalink 2019-12-19 09:58:05 +01:00
ganfra
c8f0c83cd3 Timeline: don't retry automatically to avoid totally blocking pagination 2019-12-19 09:57:49 +01:00
ganfra
7697278bb2 LiveObservers: launch directly coroutines 2019-12-18 16:59:45 +01:00
ganfra
4c88c12cfe Initial sync, start the sync thread or the sync service 2019-12-17 18:46:19 +01:00
ganfra
2316c98a65 Merge branch 'develop' into feature/initial_sync 2019-12-16 19:11:04 +01:00
Valere
08d005a611 fix merge 2019-12-16 15:44:32 +01:00
Valere
89b414e8fe Merge branch 'develop' into dm_verif_incoming_timeline 2019-12-16 15:30:39 +01:00
ganfra
5dd46e82d7 Sync: make only one big transaction to avoid having bad states 2019-12-13 18:21:44 +01:00
Valere
3727affc15 cleaning 2019-12-13 18:00:04 +01:00
Valere
ff5305ee66 Fix / Verification Msg show fallback text in room summary 2019-12-13 17:56:06 +01:00
Valere
3953022258 Merge branch 'cross_signing' into dm_verif_incoming_timeline 2019-12-13 16:51:53 +01:00
Valere
b473aeb475 Merge pull request #765 from vector-im/sdk_reference_aggregation
Aggregate Event References for DM verifications
2019-12-13 16:45:27 +01:00
Valere
289c03e724 Code review 2019-12-13 16:41:55 +01:00
ganfra
fe2be90002 Sync: use the CoroutineSequencer but need more tests 2019-12-13 15:37:38 +01:00
Valere
210dcca0ee Fix / Handling multi open sessions 2019-12-13 11:22:39 +01:00
Valere
872baacfe4 Fix / verification conclusion not showing in non hidden mode 2019-12-13 11:20:19 +01:00
Valere
975de1dbed Cleaning / klint 2019-12-12 18:48:57 +01:00
Valere
dedc622140 Merge branch 'sdk_reference_aggregation' into dm_verif_incoming_timeline 2019-12-12 15:55:01 +01:00
Valere
9842cac504 More explicit val naming 2019-12-12 15:29:56 +01:00
Valere
35404b9a7f Fix merge 2019-12-12 15:05:13 +01:00
Valere
0afcb60e7d fix rebase 2019-12-12 14:31:01 +01:00
ganfra
eab94b4f03 Sequencer: handle cancellation 2019-12-12 14:30:40 +01:00
Valere
cb595177a9 Fix test compilation 2019-12-12 13:37:17 +01:00
Valere
cb4d52c9fb Aggregate Event References for DM verifications 2019-12-12 13:37:17 +01:00
Valere
d0a3b4663e FIx / room transport was not updating state 2019-12-12 13:37:17 +01:00
Valere
f53b99a423 rebase 2019-12-12 13:37:17 +01:00
Valere
6da0693488 Convert KeyVerificationStart to data class 2019-12-12 13:37:17 +01:00
Valere
ea817ff1c5 fix rebase 2019-12-12 12:04:38 +01:00
Valere
62f0c6edc0 Fix / Use transport to start verification 2019-12-12 12:04:38 +01:00
Valere
e71ad0e515 Simple strategy to Ignore old verification messages 2019-12-12 12:03:59 +01:00
Valere
553604423e Support verification using room transport 2019-12-12 12:03:42 +01:00
Valere
be723256d3 FIx / room transport was not updating state 2019-12-12 10:49:42 +01:00
Valere
819d7182bb rebase 2019-12-12 10:49:42 +01:00
Valere
0a2ffdbdf1 Convert KeyVerificationStart to data class 2019-12-12 10:49:42 +01:00
Valere
4ac7331f3d fix rebase 2019-12-12 10:49:42 +01:00
Valere
7fc57bdf9b Fix / Use transport to start verification 2019-12-12 10:49:42 +01:00
Valere
d370f6d7c8 Simple strategy to Ignore old verification messages 2019-12-12 10:49:42 +01:00
Valere
46ef442139 cleaning 2019-12-12 10:49:42 +01:00
Benoit Marty
5f3dc73440 Code review 2019-12-12 10:49:42 +01:00
Valere
6137a88a6f Support verification using room transport 2019-12-12 10:49:42 +01:00
Valere
82af848c33 Fix / Verification Request Local Echo 2019-12-12 10:27:58 +01:00
ganfra
6b61c95843 Coroutines: introduce a sequencer 2019-12-11 20:39:07 +01:00
Valere
a673bf092d Show untrusted conclusions 2019-12-11 18:19:32 +01:00
Valere
0776a301ea Incoming DM verification handling in timeline 2019-12-11 16:49:34 +01:00
ganfra
3a269be2ef Sync: fix crash on gplay flavor and reschedule when no network instead of showing a potential notification all the time 2019-12-11 16:24:30 +01:00
Valere
02f03e6b23 Fix test compilation 2019-12-11 16:00:53 +01:00
Valere
8305ce67dd Aggregate Event References for DM verifications 2019-12-11 14:44:31 +01:00
Valere
95deeb1be7 Merge pull request #730 from vector-im/feature/sdk_dm_verification
[SDK] MSC2241 / verification in DMs
2019-12-11 11:10:46 +01:00
ganfra
5338f93852 Sync: use a foreground service for initialSync. 2019-12-10 19:52:12 +01:00
Valere
73f0132d5d FIx / room transport was not updating state 2019-12-10 16:37:54 +01:00
Valere
c462d15bcf rebase 2019-12-10 14:23:56 +01:00
Valere
3cdd373368 Convert KeyVerificationStart to data class 2019-12-10 11:14:52 +01:00
Valere
e14602d1dc fix rebase 2019-12-10 11:14:52 +01:00
Valere
2aa9c3ea22 Fix / Use transport to start verification 2019-12-10 11:14:52 +01:00
Valere
bbd9738452 Simple strategy to Ignore old verification messages 2019-12-10 11:14:52 +01:00
Valere
36c5566b07 cleaning 2019-12-10 11:14:52 +01:00
Benoit Marty
ce63332a2f Code review 2019-12-10 11:14:52 +01:00
Valere
26b4b6e194 Support verification using room transport 2019-12-10 11:14:20 +01:00
ganfra
fd18bcb97f Room profile: branch leave and notifications actions 2019-11-26 17:25:26 +01:00
ganfra
ab4cab05cf Room profile: continue working on UI 2019-11-26 13:22:07 +01:00
ganfra
8aab46804b Profile room: continue working on it (try to get a nice animation) [WIP] 2019-11-15 20:37:36 +01:00
ganfra
0edc953a23 Room profile: start creating epoxy items and implementing UI 2019-11-14 20:13:59 +01:00
ganfra
fa67509ac2 Room profile: start initializing all the classes + move some packages 2019-11-14 15:34:50 +01:00
1736 changed files with 77785 additions and 17578 deletions

View File

@@ -1,88 +0,0 @@
# Use Docker file from https://hub.docker.com/r/runmymind/docker-android-sdk
# Last docker plugin version can be found here:
# https://github.com/buildkite-plugins/docker-buildkite-plugin/releases
# We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean)
steps:
- label: "Compile and run Unit tests"
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "medium"
commands:
- "./gradlew clean test --stacktrace"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Compile Android tests"
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "medium"
commands:
- "./gradlew clean assembleAndroidTest --stacktrace"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Assemble GPlay Debug version"
agents:
# We use a xlarge sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "xlarge"
commands:
- "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/gplay/debug/*.apk"
branches: "!master"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Assemble FDroid Debug version"
agents:
# We use a xlarge sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "xlarge"
commands:
- "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/fdroid/debug/*.apk"
branches: "!master"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Build Google Play unsigned APK"
agents:
# We use a xlarge sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "xlarge"
commands:
- "./gradlew clean assembleGplayRelease --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/gplay/release/*.apk"
branches: "master"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
# Code quality
- label: "Code quality"
command:
- "./tools/check/check_code_quality.sh"
- label: "ktlint"
command:
- "curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint"
- "./ktlint --android --experimental -v"
plugins:
- docker#v3.1.0:
image: "openjdk"

View File

@@ -12,7 +12,7 @@ max_line_length=off
# Comma-separated list of rules to disable (Since 0.34.0)
# Note that rules in any ruleset other than the standard ruleset will need to be prefixed
# by the ruleset identifier.
disabled_rules=no-wildcard-imports,no-multi-spaces,colon-spacing,chain-wrapping,import-ordering,experimental:annotation
disabled_rules=no-multi-spaces,colon-spacing,chain-wrapping,import-ordering,experimental:annotation
# The following (so far identified) rules are kept:
# no-blank-line-before-rbrace
@@ -30,3 +30,4 @@ disabled_rules=no-wildcard-imports,no-multi-spaces,colon-spacing,chain-wrapping,
# no-empty-class-body
# experimental:multiline-if-else
# experimental:no-empty-first-line-in-method-block
# no-wildcard-imports

View File

@@ -7,4 +7,4 @@
- [ ] Pull request is based on the develop branch
- [ ] Pull request updates [CHANGES.md](https://github.com/vector-im/riotX-android/blob/develop/CHANGES.md)
- [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst#sign-off)
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md#sign-off)

5
.gitignore vendored
View File

@@ -3,8 +3,8 @@
/local.properties
# idea files: exclude everything except dictionnaries
.idea/caches
.idea/codeStyles
.idea/libraries
.idea/inspectionProfiles
.idea/*.xml
.DS_Store
/build
@@ -14,5 +14,4 @@
/tmp
ktlint
.idea/copyright/New_vector.xml
.idea/copyright/profiles_settings.xml
.idea

156
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,156 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="160" />
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
</value>
</option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="true" />
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="true" />
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="true" />
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="true" />
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="true" />
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="true" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="true" />
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="0" />
<option name="IF_RPAREN_ON_NEW_LINE" value="false" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="RIGHT_MARGIN" value="160" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="RIGHT_MARGIN" value="160" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="CALL_PARAMETERS_WRAP" value="0" />
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
<option name="METHOD_PARAMETERS_WRAP" value="0" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
<option name="EXTENDS_LIST_WRAP" value="0" />
<option name="METHOD_CALL_CHAIN_WRAP" value="0" />
<option name="ASSIGNMENT_WRAP" value="0" />
<option name="CLASS_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="1" />
</codeStyleSettings>
</code_scheme>
</component>

6
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

6
.idea/copyright/NewVector.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) &amp;#36;today.year New Vector Ltd&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="NewVector" />
</copyright>
</component>

8
.idea/copyright/profiles_settings.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<component name="CopyrightManager">
<settings default="NewVector">
<LanguageOptions name="XML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
</settings>
</component>

View File

@@ -9,6 +9,8 @@
<w>decryptor</w>
<w>emoji</w>
<w>emojis</w>
<w>fdroid</w>
<w>gplay</w>
<w>hmac</w>
<w>ktlint</w>
<w>linkified</w>
@@ -17,9 +19,12 @@
<w>msisdn</w>
<w>pbkdf</w>
<w>pkcs</w>
<w>riotx</w>
<w>signin</w>
<w>signout</w>
<w>signup</w>
<w>ssss</w>
<w>threepid</w>
</words>
</dictionary>
</component>

View File

@@ -0,0 +1 @@
{"databases":[{"packageName":"im.vector.matrix.sqldelight.auth","compilationUnits":[{"name":"main","sourceFolders":[{"path":"src/main/sqldelight/auth","dependency":false}]}],"outputDirectory":"build/generated/sqldelight/code/AuthDatabase","className":"AuthDatabase","dependencies":[]},{"packageName":"im.vector.matrix.sqldelight.crypto","compilationUnits":[{"name":"main","sourceFolders":[{"path":"src/main/sqldelight/crypto","dependency":false}]}],"outputDirectory":"build/generated/sqldelight/code/CryptoDatabase","className":"CryptoDatabase","dependencies":[]},{"packageName":"im.vector.matrix.sqldelight.session","compilationUnits":[{"name":"main","sourceFolders":[{"path":"src/main/sqldelight/session","dependency":false}]}],"outputDirectory":"build/generated/sqldelight/code/SessionDatabase","className":"SessionDatabase","dependencies":[]}]}

View File

@@ -23,10 +23,10 @@ android:
- platform-tools
# The BuildTools version used by your project
- build-tools-28.0.3
- build-tools-29.0.3
# The SDK version used to compile your project
- android-28
- android-29
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
@@ -49,12 +49,12 @@ script:
# Build Android test (assembleAndroidTest) (disabled for now)
# Code quality (lintGplayRelease lintFdroidRelease)
# Split into two steps because if a task contain Fdroid, PlayService will be disabled
- ./gradlew clean assembleGplayRelease lintGplayRelease --stacktrace
- ./gradlew clean assembleFdroidRelease lintFdroidRelease --stacktrace
# Done by Buildkite now: - ./gradlew clean assembleGplayRelease lintGplayRelease --stacktrace
# Done by Buildkite now: - ./gradlew clean assembleFdroidRelease lintFdroidRelease --stacktrace
# Run unitary test (Disable for now, see https://travis-ci.org/vector-im/riot-android/builds/502504370)
# - ./gradlew testGplayReleaseUnitTest --stacktrace
# Other code quality check
- ./tools/check/check_code_quality.sh
# Done by Buildkite now: - ./tools/check/check_code_quality.sh
- ./tools/travis/check_pr.sh
# Check that indonesians file are identical. Due to Android issue, the resource folder must be value-in/, and Weblate export data into value-id/.
- diff ./vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-in/strings.xml
# Done by Buildkite now: - diff ./vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-in/strings.xml

View File

@@ -0,0 +1,35 @@
A full developer contributors list can be found [here](https://github.com/vector-im/riotX-android/graphs/contributors).
# Core team:
Even if we try to be able to work on all the functionalities, we have more knowledge about what we have developed ourselves.
## Benoit: Android team leader
[@benoit.marty:matrix.org](https://matrix.to/#/@benoit.marty:matrix.org)
- Android team leader and project leader, Android developer, GitHub community manager.
- Specialist of the account creation, and many other fun features.
- Reviewing and polishing developed features, code quality manager, PRs reviewer, GitHub community manager.
- Release manager on the Play Store
## François: Software architect
[@ganfra:matrix.org](https://matrix.to/#/@ganfra:matrix.org)
- Software architect, Android developer
- First developer on the project.
- Work mainly on the global architecture of the project.
- Specialist of the timeline, and lots of other features.
## Valere: Product manager, Android developer
[@valere35:matrix.org](https://matrix.to/#/@valere35:matrix.org)
- Product manager, Android developer
- Specialist on the crypto implementation.
# Other contributors
First of all, we thank all contributors who use RiotX and report problems on this GitHub project or via the integrated rageshake function.
We do not forget all translators, for their work of translating RiotX into many languages. They are also the authors of RiotX.
Feel free to add your name below, when you contribute to the project!

View File

@@ -1,3 +1,233 @@
Changes in RiotX 0.19.0 (2020-XX-XX)
===================================================
Features ✨:
- Cross-Signing | Support SSSS secret sharing (#944)
- Cross-Signing | Verify new session from existing session (#1134)
- Cross-Signing | Bootstraping cross signing with 4S from mobile (#985)
Improvements 🙌:
- Verification DM / Handle concurrent .start after .ready (#794)
- Cross-Signing | Update Shield Logic for DM (#963)
- Cross-Signing | Complete security new session design update (#1135)
- Cross-Signing | Setup key backup as part of SSSS bootstrapping (#1201)
- Cross-Signing | Gossip key backup recovery key (#1200)
- Show room encryption status as a bubble tile (#1078)
- Cross-Signing | Restore history after recover from passphrase (#1214)
- Cross-Sign | QR code scan confirmation screens design update (#1187)
- Emoji Verification | It's not the same butterfly! (#1220)
Bugfix 🐛:
- Missing avatar/displayname after verification request message (#841)
- Crypto | RiotX sometimes rotate the current device keys (#1170)
- RiotX can't restore cross signing keys saved by web in SSSS (#1174)
- Cross- Signing | After signin in new session, verification paper trail in DM is off (#1191)
- Failed to encrypt message in room (message stays in red), [thanks to pwr22] (#925)
- Cross-Signing | web <-> riotX After QR code scan, gossiping fails (#1210)
Translations 🗣:
-
SDK API changes ⚠️:
- Implementation of SqlCryptoStore on top of SQLDelight
Build 🧱:
-
Other changes:
- Increase File Logger capacities ( + use dev log preferences)
Changes in RiotX 0.18.1 (2020-03-17)
===================================================
Improvements 🙌:
- Implementation of /join command
Bugfix 🐛:
- Message transitions in encrypted rooms are jarring #518
- Images that failed to send are waiting to be sent forever #1145
- Fix / Crashed when trying to send a gif from the Gboard #1136
- Fix / Cannot click on key backup banner when new keys are available
Changes in RiotX 0.18.0 (2020-03-11)
===================================================
Improvements 🙌:
- Share image and other media from e2e rooms (#677)
- Add support for `/plain` command (#12)
- Detect spaces in password if user fail to login (#1038)
- FTUE: do not display a different color when encrypting message when not in developer mode.
- Open room member profile from avatar of the room member state event (#935)
- Restore the push rules configuration in the settings
Bugfix 🐛:
- Fix crash on attachment preview screen (#1088)
- "Share" option is not appearing in encrypted rooms for images (#1031)
- Set "image/jpeg" as MIME type of images instead of "image/jpg" (#1075)
- Self verification via QR code is failing (#1130)
SDK API changes ⚠️:
- PushRuleService.getPushRules() now returns a RuleSet. Use getAllRules() on this object to get all the rules.
Build 🧱:
- Upgrade ktlint to version 0.36.0
- Pipeline file for Buildkite is now hosted on another Github repository: https://github.com/matrix-org/pipelines/blob/master/riotx-android/pipeline.yml
Other changes:
- Restore availability to Chromebooks (#932)
- Add a [documentation](./docs/integration_tests.md) to run integration tests
Changes in RiotX 0.17.0 (2020-02-27)
===================================================
Features ✨:
- Secured Shared Storage Support (#984, #936)
- It's now possible to select several rooms (with a possible mix of clear/encrypted rooms) when sharing elements to RiotX (#1010)
- Media preview: media are previewed before being sent to a room (#1010)
- Image edition: it's now possible to edit image before sending: crop, rotate, and delete actions are supported (#1010)
- Sending image: image are sent to rooms with a reduced size. It's still possible to send original image file (#1010)
Improvements 🙌:
- Migrate to binary QR code verification (#994)
- Share action is added to room profile and room member profile (#858)
- Display avatar in fullscreen (#861)
- Fix some performance issues with crypto
Bugfix 🐛:
- Account creation: wrongly hints that an email can be used to create an account (#941)
- Fix crash in the room directory, when public room has no name (#1023)
- Fix restoring keys backup with passphrase (#526)
- Fix rotation of full-size image (#647)
- Fix joining rooms from directory via federation isn't working. (#808)
- Leaving a room creates a stuck "leaving room" loading screen. (#1041)
- Fix some invitation handling issues (#1013)
- New direct chat: selecting a participant sometimes results in two breadcrumbs (#1022)
- New direct chat: selecting several participants was not adding the room to the direct chats list
- Room overview shows deleted messages as “Encrypted message” (#758)
SDK API changes ⚠️:
- Get crypto methods through Session.cryptoService()
- ProgressListener.onProgress() function will be invoked on the background thread instead of UI thread
- Improve CreateRoomParams API (#1070)
Changes in RiotX 0.16.0 (2020-02-14)
===================================================
Features ✨:
- Polls and Bot Buttons (MSC 2192 matrix-org/matrix-doc#2192)
Improvements 🙌:
- Show confirmation dialog before deleting a message (#967, #1003)
- Open room member profile from reactions list and read receipts list (#875)
Bugfix 🐛:
- Fix crash by removing all notifications after clearing cache (#878)
- Fix issue with verification when other client declares it can only show QR code (#988)
- Fix too errors in the code (1941862499c9ec5268cc80882512ced379cafcfd, a250a895fe0a4acf08c671e03434edcd29ccd84f)
SDK API changes ⚠️:
- Javadoc improved for PushersService
- PushersService.pushers() has been renamed to PushersService.getPushers()
Changes in RiotX 0.15.0 (2020-02-10)
===================================================
Improvements 🙌:
- Improve navigation to the timeline (#789, #862)
- Improve network detection. It is now based on the sync request status (#873, #882)
Other changes:
- Support SSO login with Firefox account (#606)
Bugfix 🐛:
- Ask for permission before opening the camera (#934)
- Encrypt for invited users by default, if the room state allows it (#803)
Changes in RiotX 0.14.3 (2020-02-03)
===================================================
Bugfix 🐛:
- Fix Exception in DeviceListManager
Changes in RiotX 0.14.2 (2020-02-02)
===================================================
Bugfix 🐛:
- Fix RiotX not starting issue
Changes in RiotX 0.14.1 (2020-02-02)
===================================================
Bugfix 🐛:
- Cross-signing: fix UX issue when closing the bottom sheet verification (#813)
- Room and room member profile: fix issues on dark and black themes
Changes in RiotX 0.14.0 (2020-02-01)
===================================================
Features ✨:
- First implementation of Cross-signing
- Enable encryption in unencrypted rooms, from the room settings (#212)
- Negotiate E2E by default for DMs (#907)
Improvements 🙌:
- Sharing things to RiotX: sort list by recent room first (#771)
- Hide the algorithm when turning on e2e (#897)
- Sort room members by display names
Other changes:
- Add support for /rainbow and /rainbowme commands (#879)
Build 🧱:
- Ensure builds are reproducible (#842)
- F-Droid: fix the "-dev" issue in version name (#815)
Changes in RiotX 0.13.0 (2020-01-17)
===================================================
Features ✨:
- Send and render typing events (#564)
- Create Room Profile screen (#54)
- Create Room Member Profile screen (#59)
Improvements 🙌:
- Render events m.room.encryption and m.room.guest_access in the timeline
Bugfix 🐛:
- Fix broken background sync in F-Droid version
- Fix issue with downloaded file on encrypted rooms. The file was not properly decrypted
Build 🧱:
- Change the way versionCode is computed (#827)
Changes in RiotX 0.12.0 (2020-01-09)
===================================================
Improvements 🙌:
- The initial sync is now handled by a foreground service
- Render aliases and canonical alias change in the timeline
- Introduce developer mode in the settings (#745, #796)
- Improve devices list screen
- Add settings for rageshake sensibility
- Fix autocompletion issues and add support for rooms, groups, and emoji (#780)
- Show skip to bottom FAB while scrolling down (#752)
- Enable encryption on a room, SDK part (#212)
Other changes:
- Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800)
- Exclude play-services-oss-licenses library from F-Droid build (#814)
- Email domain can be limited on some homeservers, i18n of the displayed error (#754)
Bugfix 🐛:
- Fix crash when opening room creation screen from the room filtering screen
- Fix avatar image disappearing (#777)
- Fix read marker banner when permalink
- Fix joining upgraded rooms (#697)
- Fix matrix.org room directory not being browsable (#807)
- Hide non working settings (#751)
Changes in RiotX 0.11.0 (2019-12-19)
===================================================
@@ -51,6 +281,7 @@ Changes in RiotX 0.9.0 (2019-12-05)
Features ✨:
- Account creation. It's now possible to create account on any homeserver with RiotX (#34)
- Iteration of the login flow (#613)
- [SDK] MSC2241 / verification in DMs (#707)
Improvements 🙌:
- Send mention Pills from composer
@@ -256,7 +487,7 @@ Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-a
=======================================================
Changes in RiotX 0.0.0 (2019-XX-XX)
Changes in RiotX 0.X.0 (2020-XX-XX)
===================================================
Features ✨:
@@ -265,15 +496,17 @@ Features ✨:
Improvements 🙌:
-
Other changes:
-
Bugfix 🐛:
-
Translations 🗣:
-
SDK API changes ⚠️:
-
Build 🧱:
-
Other changes:
-

View File

@@ -1,6 +1,6 @@
# Contributing code to Matrix
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md
Android support can be found in this [![Riot Android Matrix room #riot-android:matrix.org](https://img.shields.io/matrix/riot-android:matrix.org.svg?label=%23riot-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#riot-android:matrix.org) room.
@@ -11,6 +11,7 @@ Dedicated room for RiotX: [![RiotX Android Matrix room #riot-android:matrix.org]
## Android Studio settings
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
Please ensure that your using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
## Compilation
@@ -81,6 +82,8 @@ Make sure the following commands execute without any error:
RiotX is currently supported on Android KitKat (API 19+): please test your change on an Android device (or Android emulator) running with API 19. Many issues can happen (including crashes) on older devices.
Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient.
You should consider adding Unit tests with your PR, and also integration tests (AndroidTest). Please refer to [this document](./docs/integration_tests.md) to install and run the integration test environment.
### Internationalisation
When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators with a specific tool named [Weblate](https://translate.riot.im/projects/riot-android/).

View File

@@ -12,12 +12,13 @@ RiotX is an Android Matrix Client currently in beta but in active development.
It is a total rewrite of [Riot-Android](https://github.com/vector-im/riot-android) with a new user experience. RiotX will become the official replacement as soon as all features are implemented.
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.riotx)
[<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/app/im.vector.riotx)
Nightly build: [![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)
# New Android SDK
RiotX is based on a new Android SDK fully written in Kotlin (like RiotX). In order to make the early development as fast as possible, RiotX and the new SDK currently share the same git repository. We will make separate repos once the API is stable enough.
RiotX is based on a new Android SDK fully written in Kotlin (like RiotX). In order to make the early development as fast as possible, RiotX and the new SDK currently share the same git repository. We will make separate repos once the SDK is stable enough.
# Roadmap

View File

@@ -16,7 +16,7 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
classpath 'com.google.android.gms:oss-licenses-plugin:0.9.5'
classpath 'com.squareup.sqldelight:gradle-plugin:1.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -34,6 +34,10 @@ allprojects {
includeGroupByRegex "com\\.github\\.jaiselrahman"
// And monarchy
includeGroupByRegex "com\\.github\\.Zhuinden"
// And ucrop
includeGroupByRegex "com\\.github\\.yalantis"
// JsonViewer
includeGroupByRegex 'com\\.github\\.BillCarsonFr'
}
}
maven {
@@ -47,21 +51,9 @@ allprojects {
jcenter()
}
tasks.withType(JavaCompile).all {
options.compilerArgs += [
'-Adagger.gradle.incremental=enabled'
]
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
// Warnings are potential errors, so stop ignoring them
kotlinOptions.allWarningsAsErrors = true
}
afterEvaluate {
extensions.findByName("kapt")?.arguments {
arg("dagger.gradle.incremental", "enabled")
}
kotlinOptions.allWarningsAsErrors = false
}
}

97
docs/integration_tests.md Normal file
View File

@@ -0,0 +1,97 @@
# Integration tests
Integration tests are useful to ensure that the code works well for any use cases.
They can also be used as sample on how to use the Matrix SDK.
In a ideal world, every API of the SDK should be covered by integration tests. For the moment, we have test mainly for the Crypto part, which is the tricky part. But it covers quite a lot of features: accounts creation, login to existing account, send encrypted messages, keys backup, verification, etc.
The Matrix SDK is able to open multiple sessions, for the same user, of for different users. This way we can test communication between several sessions on a single device.
## Pre requirements
Integration tests need a homeserver running on localhost.
The documentation describes what we do to have one, using [Synapse](https://github.com/matrix-org/synapse/), which is the Matrix reference homeserver.
## Install and run Synapse
Steps:
- Install virtualenv
```bash
python3 -m pip install virtualenv
```
- Clone Synapse repository
```bash
git clone -b develop https://github.com/matrix-org/synapse.git
```
or
```bash
git clone -b develop git@github.com:matrix-org/synapse.git
```
You should have the develop branch cloned by default.
- Run synapse, from the Synapse folder you just cloned
```bash
virtualenv -p python3 env
source env/bin/activate
pip install -e .
demo/start.sh --no-rate-limit
```
Alternatively, to install the latest Synapse release package (and not a cloned branch) you can run the following instead of `pip install -e .`:
```bash
pip install matrix-synapse
```
You should now have 3 running federated Synapse instances 🎉, at http://127.0.0.1:8080/, http://127.0.0.1:8081/ and http://127.0.0.1:8082/, which should display a "It Works! Synapse is running" message.
## Run the test
It's recommended to run tests using an Android Emulator and not a real device. First reason for that is that the tests will use http://10.0.2.2:8080 to connect to Synapse, which run locally on your machine.
You can run all the tests in the `androidTest` folders.
## Stop Synapse
To stop Synapse, you can run the following commands:
```bash
./demo/stop.sh
```
And you can deactivate the virtualenv:
```bash
deactivate
```
## Troubleshoot
You'll need python3 to be able to run synapse
### Android Emulator does cannot reach the homeserver
Try on the Emulator browser to open "http://10.0.2.2:8080". You should see the "Synapse is running" message.
### virtualenv command fails
You can try using
```bash
python3 -m venv env
```
or
```bash
python3 -m virtualenv env
```
instead of
```bash
virtualenv -p python3 env
```

View File

@@ -3,11 +3,11 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
@@ -38,9 +38,14 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.3.3'
// Paging
implementation "androidx.paging:paging-runtime-ktx:2.1.0"
// Logging
implementation 'com.jakewharton.timber:timber:4.7.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

View File

@@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import io.reactivex.Observable
import io.reactivex.android.MainThreadDisposable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
private class LiveDataObservable<T>(
@@ -60,3 +61,11 @@ private class LiveDataObservable<T>(
fun <T> LiveData<T>.asObservable(): Observable<T> {
return LiveDataObservable(this).observeOn(Schedulers.computation())
}
internal fun <T> Observable<T>.startWithCallable(supplier: () -> T): Observable<T> {
val startObservable = Observable
.fromCallable(supplier)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
return startWith(startObservable)
}

View File

@@ -22,3 +22,9 @@ import io.reactivex.Observable
fun <T : Any> Observable<Optional<T>>.unwrap(): Observable<T> {
return filter { it.hasValue() }.map { it.get() }
}
fun <T : Any, U : Any> Observable<Optional<T>>.mapOptional(fn: (T) -> U?): Observable<Optional<U>> {
return map {
it.map(fn)
}
}

View File

@@ -16,9 +16,12 @@
package im.vector.matrix.rx
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
import im.vector.matrix.android.api.session.room.send.UserDraft
@@ -26,6 +29,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.util.Optional
import io.reactivex.Observable
import io.reactivex.Single
import kotlinx.coroutines.rx2.asObservable
class RxRoom(private val room: Room) {
@@ -33,18 +37,26 @@ class RxRoom(private val room: Room) {
return room.getRoomSummaryLive().asObservable()
}
fun liveRoomMemberIds(): Observable<List<String>> {
return room.getRoomMemberIdsLive().asObservable()
fun liveRoomMembers(queryParams: RoomMemberQueryParams): Observable<List<RoomMemberSummary>> {
return room.getRoomMembersLive(queryParams).asObservable()
}
fun liveAnnotationSummary(eventId: String): Observable<Optional<EventAnnotationsSummary>> {
return room.getEventSummaryLive(eventId).asObservable()
fun liveRoomMember(userId: String): Observable<Optional<RoomMemberSummary>> {
return room.getRoomMemberLive(userId).asObservable()
}
fun liveAnnotationSummary(eventId: String): Observable<EventAnnotationsSummary> {
return room.getEventAnnotationsSummaryLive(eventId).asObservable()
}
fun liveTimelineEvent(eventId: String): Observable<Optional<TimelineEvent>> {
return room.getTimeLineEventLive(eventId).asObservable()
}
fun liveStateEvent(eventType: String, stateKey: String): Observable<Optional<Event>> {
return room.getStateEventLive(eventType, stateKey).asObservable()
}
fun liveReadMarker(): Observable<Optional<String>> {
return room.getReadMarkerLive().asObservable()
}
@@ -71,7 +83,7 @@ class RxRoom(private val room: Room) {
}
fun liveNotificationState(): Observable<RoomNotificationState> {
return room.getLiveRoomNotificationState().asObservable()
return room.getRoomNotificationStateLive().asObservable()
}
}

View File

@@ -18,52 +18,61 @@ package im.vector.matrix.rx
import androidx.paging.PagedList
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
import im.vector.matrix.android.api.session.group.GroupSummaryQueryParams
import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.session.pushers.Pusher
import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams
import im.vector.matrix.android.api.session.room.model.Breadcrumb
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.api.session.user.model.User
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
import io.reactivex.Observable
import io.reactivex.Single
import kotlinx.coroutines.rx2.asObservable
class RxSession(private val session: Session) {
fun liveRoomSummaries(): Observable<List<RoomSummary>> {
return session.liveRoomSummaries().asObservable()
fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Observable<List<RoomSummary>> {
return session.getRoomSummariesLive(queryParams).asObservable()
}
fun liveGroupSummaries(): Observable<List<GroupSummary>> {
return session.liveGroupSummaries().asObservable()
fun liveGroupSummaries(queryParams: GroupSummaryQueryParams): Observable<List<GroupSummary>> {
return session.getGroupSummariesLive(queryParams).asObservable()
}
fun liveBreadcrumbs(): Observable<List<RoomSummary>> {
return session.liveBreadcrumbs().asObservable()
fun liveBreadcrumbs(): Observable<List<Breadcrumb>> {
return session.getBreadcrumbsLive().asObservable()
}
fun liveSyncState(): Observable<SyncState> {
return session.syncState().asObservable()
return session.getSyncStateLive().asObservable()
}
fun livePushers(): Observable<List<Pusher>> {
return session.livePushers().asObservable()
return session.getPushersLive().asObservable()
}
fun liveUser(userId: String): Observable<Optional<User>> {
return session.liveUser(userId).asObservable().distinctUntilChanged()
return session.getUserLive(userId).asObservable()
}
fun liveUsers(): Observable<List<User>> {
return session.liveUsers().asObservable()
return session.getUsersLive().asObservable()
}
fun liveIgnoredUsers(): Observable<List<User>> {
return session.liveIgnoredUsers().asObservable()
return session.getIgnoredUsersLive().asObservable()
}
fun livePagedUsers(filter: String? = null): Observable<PagedList<User>> {
return session.livePagedUsers(filter).asObservable()
return session.getPagedUsersLive(filter).asObservable()
}
fun createRoom(roomParams: CreateRoomParams): Single<String> = singleBuilder {
@@ -76,16 +85,37 @@ class RxSession(private val session: Session) {
session.searchUsersDirectory(search, limit, excludedUserIds, it)
}
fun joinRoom(roomId: String,
fun joinRoom(roomIdOrAlias: String,
reason: String? = null,
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
session.joinRoom(roomId, reason, viaServers, it)
session.joinRoom(roomIdOrAlias, reason, viaServers, it)
}
fun getRoomIdByAlias(roomAlias: String,
searchOnServer: Boolean): Single<Optional<String>> = singleBuilder {
session.getRoomIdByAlias(roomAlias, searchOnServer, it)
}
fun getProfileInfo(userId: String): Single<JsonDict> = singleBuilder {
session.getProfile(userId, it)
}
fun liveUserCryptoDevices(userId: String): Observable<List<CryptoDeviceInfo>> {
return session.cryptoService().getLiveCryptoDeviceInfo(userId).asObservable().startWithCallable {
session.cryptoService().getCryptoDeviceInfo(userId)
}
}
fun liveCrossSigningInfo(userId: String): Observable<Optional<MXCrossSigningInfo>> {
return session.cryptoService().crossSigningService().getLiveCrossSigningKeys(userId).asObservable()
.startWithCallable {
session.cryptoService().crossSigningService().getUserCrossSigningKeys(userId).toOptional()
}
}
fun liveAccountData(types: Set<String>): Observable<List<UserAccountDataEvent>> {
return session.getLiveAccountDataEvents(types).asObservable()
}
}
fun Session.rx(): RxSession {

View File

@@ -10,7 +10,7 @@ buildscript {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:5.12.0"
classpath "io.realm:realm-gradle-plugin:6.1.0"
}
}
@@ -19,12 +19,12 @@ androidExtensions {
}
android {
compileSdkVersion 28
compileSdkVersion 29
testOptions.unitTests.includeAndroidResources = true
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "0.0.1"
// Multidex is useful for tests
@@ -71,10 +71,14 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
packagingOptions {
pickFirst 'META-INF/kotlinx-coroutines-core.kotlin_module'
}
}
static def gitRevision() {
def cmd = "git rev-parse --short HEAD"
def cmd = "git rev-parse --short=8 HEAD"
return cmd.execute().text.trim()
}
@@ -92,41 +96,47 @@ dependencies {
def arrow_version = "0.8.2"
def moshi_version = '1.8.0'
def lifecycle_version = '2.1.0'
def lifecycle_version = '2.2.0'
def arch_version = '2.1.0'
def coroutines_version = "1.3.2"
def markwon_version = '3.1.0'
def daggerVersion = '2.24'
def daggerVersion = '2.25.4'
def work_version = '2.3.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "androidx.appcompat:appcompat:1.1.0"
implementation "androidx.recyclerview:recyclerview:1.1.0-beta05"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// Network
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-moshi:2.6.2'
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
implementation 'com.novoda:merlin:1.2.0'
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
implementation "ru.noties.markwon:core:$markwon_version"
// Image
implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.3.0-alpha01'
implementation 'id.zelory:compressor:3.0.0'
// Database
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
implementation "com.squareup.sqldelight:android-driver:1.2.2"
implementation 'net.zetetic:android-database-sqlcipher:4.3.0'
implementation project(':matrix-sdk-sqldelight')
implementation "com.squareup.sqldelight:coroutines-extensions:1.2.1"
implementation "com.squareup.sqldelight:android-paging-extensions:1.2.1"
// Work
implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01"
implementation "androidx.work:work-runtime-ktx:$work_version"
// FP
implementation "io.arrow-kt:arrow-core:$arrow_version"
@@ -168,7 +178,7 @@ dependencies {
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12'
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
}

View File

@@ -21,6 +21,7 @@ import androidx.test.core.app.ApplicationProvider
import java.io.File
interface InstrumentedTest {
fun context(): Context {
return ApplicationProvider.getApplicationContext()
}

View File

@@ -19,4 +19,4 @@ package im.vector.matrix.android
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.Dispatchers.Main
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main)
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main, Main, Main)

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.account
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.common.SessionTestParams
import im.vector.matrix.android.common.TestConstants
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class AccountCreationTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
@Test
fun createAccountTest() {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
commonTestHelper.signOutAndClose(session)
}
@Test
fun createAccountAndLoginAgainTest() {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
// Log again to the same account
val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
commonTestHelper.signOutAndClose(session)
commonTestHelper.signOutAndClose(session2)
}
@Test
fun simpleE2eTest() {
val res = cryptoTestHelper.doE2ETestWithAliceInARoom()
res.cleanUp(commonTestHelper)
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.auth
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.OkReplayRuleChainNoActivity
import im.vector.matrix.android.api.auth.AuthenticationService
import okreplay.*
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class AuthenticationServiceTest : InstrumentedTest {
lateinit var authenticationService: AuthenticationService
lateinit var okReplayInterceptor: OkReplayInterceptor
private val okReplayConfig = OkReplayConfig.Builder()
.tapeRoot(AndroidTapeRoot(
context(), javaClass))
.defaultMode(TapeMode.READ_WRITE) // or TapeMode.READ_ONLY
.sslEnabled(true)
.interceptor(okReplayInterceptor)
.build()
@get:Rule
val testRule = OkReplayRuleChainNoActivity(okReplayConfig).get()
@Test
@UiThreadTest
@OkReplay(tape = "auth", mode = TapeMode.READ_WRITE)
fun auth() {
}
companion object {
@ClassRule
@JvmField
val grantExternalStoragePermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}

View File

@@ -0,0 +1,320 @@
/*
* Copyright 2016 OpenMarket Ltd
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.content.Context
import android.net.Uri
import androidx.lifecycle.Observer
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.MatrixConfiguration
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.LoginFlowResult
import im.vector.matrix.android.api.auth.registration.RegistrationResult
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.LocalEcho
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
import im.vector.matrix.android.api.session.sync.SyncState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import java.util.ArrayList
import java.util.UUID
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
/**
* This class exposes methods to be used in common cases
* Registration, login, Sync, Sending messages...
*/
class CommonTestHelper(context: Context) {
val matrix: Matrix
init {
Matrix.initialize(context, MatrixConfiguration("TestFlavor"))
matrix = Matrix.getInstance(context)
}
fun createAccount(userNamePrefix: String, testParams: SessionTestParams): Session {
return createAccount(userNamePrefix, TestConstants.PASSWORD, testParams)
}
fun logIntoAccount(userId: String, testParams: SessionTestParams): Session {
return logIntoAccount(userId, TestConstants.PASSWORD, testParams)
}
/**
* Create a Home server configuration, with Http connection allowed for test
*/
fun createHomeServerConfig(): HomeServerConnectionConfig {
return HomeServerConnectionConfig.Builder()
.withHomeServerUri(Uri.parse(TestConstants.TESTS_HOME_SERVER_URL))
.build()
}
/**
* This methods init the event stream and check for initial sync
*
* @param session the session to sync
*/
fun syncSession(session: Session) {
val lock = CountDownLatch(1)
session.open()
session.startSync(true)
val syncLiveData = runBlocking(Dispatchers.Main) {
session.getSyncStateLive()
}
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) {
lock.countDown()
syncLiveData.removeObserver(this)
}
}
}
GlobalScope.launch(Dispatchers.Main) { syncLiveData.observeForever(syncObserver) }
await(lock)
}
/**
* Sends text messages in a room
*
* @param room the room where to send the messages
* @param message the message to send
* @param nbOfMessages the number of time the message will be sent
*/
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int): List<TimelineEvent> {
val sentEvents = ArrayList<TimelineEvent>(nbOfMessages)
val latch = CountDownLatch(nbOfMessages)
val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val newMessages = snapshot
.filter { LocalEcho.isLocalEchoId(it.eventId).not() }
.filter { it.root.getClearType() == EventType.MESSAGE }
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
if (newMessages.size == nbOfMessages) {
sentEvents.addAll(newMessages)
latch.countDown()
}
}
}
val timeline = room.createTimeline(null, TimelineSettings(10))
timeline.start()
timeline.addListener(timelineListener)
for (i in 0 until nbOfMessages) {
room.sendTextMessage(message + " #" + (i + 1))
}
await(latch)
timeline.removeListener(timelineListener)
timeline.dispose()
// Check that all events has been created
assertEquals(nbOfMessages.toLong(), sentEvents.size.toLong())
return sentEvents
}
// PRIVATE METHODS *****************************************************************************
/**
* Creates a unique account
*
* @param userNamePrefix the user name prefix
* @param password the password
* @param testParams test params about the session
* @return the session associated with the newly created account
*/
private fun createAccount(userNamePrefix: String,
password: String,
testParams: SessionTestParams): Session {
val session = createAccountAndSync(
userNamePrefix + "_" + System.currentTimeMillis() + UUID.randomUUID(),
password,
testParams
)
assertNotNull(session)
return session
}
/**
* Logs into an existing account
*
* @param userId the userId to log in
* @param password the password to log in
* @param testParams test params about the session
* @return the session associated with the existing account
*/
private fun logIntoAccount(userId: String,
password: String,
testParams: SessionTestParams): Session {
val session = logAccountAndSync(userId, password, testParams)
assertNotNull(session)
return session
}
/**
* Create an account and a dedicated session
*
* @param userName the account username
* @param password the password
* @param sessionTestParams parameters for the test
*/
private fun createAccountAndSync(userName: String,
password: String,
sessionTestParams: SessionTestParams): Session {
val hs = createHomeServerConfig()
doSync<LoginFlowResult> {
matrix.authenticationService
.getLoginFlow(hs, it)
}
doSync<RegistrationResult> {
matrix.authenticationService
.getRegistrationWizard()
.createAccount(userName, password, null, it)
}
// Preform dummy step
val registrationResult = doSync<RegistrationResult> {
matrix.authenticationService
.getRegistrationWizard()
.dummy(it)
}
assertTrue(registrationResult is RegistrationResult.Success)
val session = (registrationResult as RegistrationResult.Success).session
if (sessionTestParams.withInitialSync) {
syncSession(session)
}
return session
}
/**
* Start an account login
*
* @param userName the account username
* @param password the password
* @param sessionTestParams session test params
*/
private fun logAccountAndSync(userName: String,
password: String,
sessionTestParams: SessionTestParams): Session {
val hs = createHomeServerConfig()
doSync<LoginFlowResult> {
matrix.authenticationService
.getLoginFlow(hs, it)
}
val session = doSync<Session> {
matrix.authenticationService
.getLoginWizard()
.login(userName, password, "myDevice", it)
}
if (sessionTestParams.withInitialSync) {
syncSession(session)
}
return session
}
/**
* Await for a latch and ensure the result is true
*
* @param latch
* @throws InterruptedException
*/
fun await(latch: CountDownLatch, timout: Long? = TestConstants.timeOutMillis) {
assertTrue(latch.await(timout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
}
fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
GlobalScope.launch {
while (true) {
delay(1000)
if (condition()) {
latch.countDown()
return@launch
}
}
}
}
fun waitWithLatch(timout: Long? = TestConstants.timeOutMillis, block: (CountDownLatch) -> Unit) {
val latch = CountDownLatch(1)
block(latch)
await(latch, timout)
}
// Transform a method with a MatrixCallback to a synchronous method
inline fun <reified T> doSync(block: (MatrixCallback<T>) -> Unit): T {
val lock = CountDownLatch(1)
var result: T? = null
val callback = object : TestMatrixCallback<T>(lock) {
override fun onSuccess(data: T) {
result = data
super.onSuccess(data)
}
}
block.invoke(callback)
await(lock)
assertNotNull(result)
return result!!
}
/**
* Clear all provided sessions
*/
fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) }
fun signOutAndClose(session: Session) {
doSync<Unit> { session.signOut(true, it) }
session.close()
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import im.vector.matrix.android.api.session.Session
data class CryptoTestData(val firstSession: Session,
val roomId: String,
val secondSession: Session? = null,
val thirdSession: Session? = null) {
fun cleanUp(testHelper: CommonTestHelper) {
testHelper.signOutAndClose(firstSession)
secondSession?.let { testHelper.signOutAndClose(it) }
thirdSession?.let { testHelper.signOutAndClose(it) }
}
}

View File

@@ -0,0 +1,302 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.os.SystemClock
import androidx.lifecycle.Observer
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import java.util.HashMap
import java.util.concurrent.CountDownLatch
class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
private val defaultSessionParams = SessionTestParams(true)
/**
* @return alice session
*/
fun doE2ETestWithAliceInARoom(): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
val roomId = mTestHelper.doSync<String> {
aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), it)
}
val room = aliceSession.getRoom(roomId)!!
mTestHelper.doSync<Unit> {
room.enableEncryption(callback = it)
}
return CryptoTestData(aliceSession, roomId)
}
/**
* @return alice and bob sessions
*/
fun doE2ETestWithAliceAndBobInARoom(): CryptoTestData {
val cryptoTestData = doE2ETestWithAliceInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
val aliceRoom = aliceSession.getRoom(aliceRoomId)!!
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val lock1 = CountDownLatch(1)
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
}
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (t?.isNotEmpty() == true) {
lock1.countDown()
bobRoomSummariesLive.removeObserver(this)
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
mTestHelper.doSync<Unit> {
aliceRoom.invite(bobSession.myUserId, callback = it)
}
mTestHelper.await(lock1)
val lock = CountDownLatch(1)
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId)
?.getRoomMember(aliceSession.myUserId)
?.membership == Membership.JOIN) {
lock.countDown()
bobRoomSummariesLive.removeObserver(this)
}
}
}
GlobalScope.launch(Dispatchers.Main) {
bobRoomSummariesLive.observeForever(roomJoinedObserver)
}
mTestHelper.doSync<Unit> { bobSession.joinRoom(aliceRoomId, callback = it) }
mTestHelper.await(lock)
// Ensure bob can send messages to the room
// val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
// assertNotNull(roomFromBobPOV.powerLevels)
// assertTrue(roomFromBobPOV.powerLevels.maySendMessage(bobSession.myUserId))
return CryptoTestData(aliceSession, aliceRoomId, bobSession)
}
/**
* @return Alice, Bob and Sam session
*/
fun doE2ETestWithAliceAndBobAndSamInARoom(): CryptoTestData {
val statuses = HashMap<String, String>()
val cryptoTestData = doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
val room = aliceSession.getRoom(aliceRoomId)!!
val samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
val lock1 = CountDownLatch(2)
// val samEventListener = object : MXEventListener() {
// override fun onNewRoom(roomId: String) {
// if (TextUtils.equals(roomId, aliceRoomId)) {
// if (!statuses.containsKey("onNewRoom")) {
// statuses["onNewRoom"] = "onNewRoom"
// lock1.countDown()
// }
// }
// }
// }
//
// samSession.dataHandler.addListener(samEventListener)
room.invite(samSession.myUserId, null, object : TestMatrixCallback<Unit>(lock1) {
override fun onSuccess(data: Unit) {
statuses["invite"] = "invite"
super.onSuccess(data)
}
})
mTestHelper.await(lock1)
assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom"))
// samSession.dataHandler.removeListener(samEventListener)
val lock2 = CountDownLatch(1)
samSession.joinRoom(aliceRoomId, null, object : TestMatrixCallback<Unit>(lock2) {
override fun onSuccess(data: Unit) {
statuses["joinRoom"] = "joinRoom"
super.onSuccess(data)
}
})
mTestHelper.await(lock2)
assertTrue(statuses.containsKey("joinRoom"))
// wait the initial sync
SystemClock.sleep(1000)
// samSession.dataHandler.removeListener(samEventListener)
return CryptoTestData(aliceSession, aliceRoomId, cryptoTestData.secondSession, samSession)
}
/**
* @return Alice and Bob sessions
*/
fun doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(): CryptoTestData {
val cryptoTestData = doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
val bobSession = cryptoTestData.secondSession!!
bobSession.cryptoService().setWarnOnUnknownDevices(false)
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
val lock = CountDownLatch(1)
val bobEventsListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
// noop
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val messages = snapshot.filter { it.root.getClearType() == EventType.MESSAGE }
.groupBy { it.root.senderId!! }
// Alice has sent 2 messages and Bob has sent 3 messages
if (messages[aliceSession.myUserId]?.size == 2 && messages[bobSession.myUserId]?.size == 3) {
lock.countDown()
}
}
}
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(20))
bobTimeline.start()
bobTimeline.addListener(bobEventsListener)
// Alice sends a message
roomFromAlicePOV.sendTextMessage(messagesFromAlice[0])
// Bob send 3 messages
roomFromBobPOV.sendTextMessage(messagesFromBob[0])
roomFromBobPOV.sendTextMessage(messagesFromBob[1])
roomFromBobPOV.sendTextMessage(messagesFromBob[2])
// Alice sends a message
roomFromAlicePOV.sendTextMessage(messagesFromAlice[1])
mTestHelper.await(lock)
bobTimeline.removeListener(bobEventsListener)
bobTimeline.dispose()
return cryptoTestData
}
fun checkEncryptedEvent(event: Event, roomId: String, clearMessage: String, senderSession: Session) {
assertEquals(EventType.ENCRYPTED, event.type)
assertNotNull(event.content)
val eventWireContent = event.content.toContent()
assertNotNull(eventWireContent)
assertNull(eventWireContent.get("body"))
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM, eventWireContent.get("algorithm"))
assertNotNull(eventWireContent.get("ciphertext"))
assertNotNull(eventWireContent.get("session_id"))
assertNotNull(eventWireContent.get("sender_key"))
assertEquals(senderSession.sessionParams.credentials.deviceId, eventWireContent.get("device_id"))
assertNotNull(event.eventId)
assertEquals(roomId, event.roomId)
assertEquals(EventType.MESSAGE, event.getClearType())
// TODO assertTrue(event.getAge() < 10000)
val eventContent = event.toContent()
assertNotNull(eventContent)
assertEquals(clearMessage, eventContent.get("body"))
assertEquals(senderSession.myUserId, event.senderId)
}
fun createFakeMegolmBackupAuthData(): MegolmBackupAuthData {
return MegolmBackupAuthData(
publicKey = "abcdefg",
signatures = mapOf("something" to mapOf("ed25519:something" to "hijklmnop"))
)
}
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
return MegolmBackupCreationInfo(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
authData = createFakeMegolmBackupAuthData()
)
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import javax.net.ssl.HttpsURLConnection
/**
* Allows to intercept network requests for test purpose by
* - re-writing the response
* - changing the response code (200/404/etc..).
* - Test delays..
*
* Basic usage:
* <code>
* val mockInterceptor = MockOkHttpInterceptor()
* mockInterceptor.addRule(MockOkHttpInterceptor.SimpleRule(".well-known/matrix/client", 200, "{}"))
*
* RestHttpClientFactoryProvider.defaultProvider = RestClientHttpClientFactory(mockInterceptor)
* AutoDiscovery().findClientConfig("matrix.org", <callback>)
* </code>
*/
class MockOkHttpInterceptor : Interceptor {
private var rules: ArrayList<Rule> = ArrayList()
fun addRule(rule: Rule) {
rules.add(rule)
}
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
rules.forEach { rule ->
if (originalRequest.url.toString().contains(rule.match)) {
rule.process(originalRequest)?.let {
return it
}
}
}
return chain.proceed(originalRequest)
}
abstract class Rule(val match: String) {
abstract fun process(originalRequest: Request): Response?
}
/**
* Simple rule that reply with the given body for any request that matches the match param
*/
class SimpleRule(match: String,
private val code: Int = HttpsURLConnection.HTTP_OK,
private val body: String = "{}") : Rule(match) {
override fun process(originalRequest: Request): Response? {
return Response.Builder()
.protocol(Protocol.HTTP_1_1)
.request(originalRequest)
.message("mocked answer")
.body(body.toResponseBody(null))
.code(code)
.build()
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
data class SessionTestParams @JvmOverloads constructor(val withInitialSync: Boolean = false)

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.fail
/**
* Compare two lists and their content
*/
fun assertListEquals(list1: List<Any>?, list2: List<Any>?) {
if (list1 == null) {
assertNull(list2)
} else {
assertNotNull(list2)
assertEquals("List sizes must match", list1.size, list2!!.size)
for (i in list1.indices) {
assertEquals("Elements at index $i are not equal", list1[i], list2[i])
}
}
}
/**
* Compare two maps and their content
*/
fun assertDictEquals(dict1: Map<String, Any>?, dict2: Map<String, Any>?) {
if (dict1 == null) {
assertNull(dict2)
} else {
assertNotNull(dict2)
assertEquals("Map sizes must match", dict1.size, dict2!!.size)
for (i in dict1.keys) {
assertEquals("Values for key $i are not equal", dict1[i], dict2[i])
}
}
}
/**
* Compare two byte arrays content.
* Note that if the arrays have not the same size, it also fails.
*/
fun assertByteArrayNotEqual(a1: ByteArray, a2: ByteArray) {
if (a1.size != a2.size) {
fail("Arrays have not the same size.")
}
for (index in a1.indices) {
if (a1[index] != a2[index]) {
// Difference found!
return
}
}
fail("Arrays are equals.")
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.os.Debug
object TestConstants {
const val TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"
// Time out to use when waiting for server response. 20s
private const val AWAIT_TIME_OUT_MILLIS = 20_000
// Time out to use when waiting for server response, when the debugger is connected. 10 minutes
private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60_000
const val USER_ALICE = "Alice"
const val USER_BOB = "Bob"
const val USER_SAM = "Sam"
const val PASSWORD = "password"
val timeOutMillis: Long
get() = if (Debug.isDebuggerConnected()) {
// Wait more
AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS.toLong()
} else {
AWAIT_TIME_OUT_MILLIS.toLong()
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import androidx.annotation.CallSuper
import im.vector.matrix.android.api.MatrixCallback
import org.junit.Assert.fail
import timber.log.Timber
import java.util.concurrent.CountDownLatch
/**
* Simple implementation of MatrixCallback, which count down the CountDownLatch on each API callback
* @param onlySuccessful true to fail if an error occurs. This is the default behavior
* @param <T>
*/
open class TestMatrixCallback<T>(private val countDownLatch: CountDownLatch,
private val onlySuccessful: Boolean = true) : MatrixCallback<T> {
@CallSuper
override fun onSuccess(data: T) {
countDownLatch.countDown()
}
@CallSuper
override fun onFailure(failure: Throwable) {
Timber.e(failure, "TestApiCallback")
if (onlySuccessful) {
fail("onFailure " + failure.localizedMessage)
}
countDownLatch.countDown()
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import android.os.MemoryFile
import android.util.Base64
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileKey
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.io.ByteArrayInputStream
import java.io.InputStream
/**
* Unit tests AttachmentEncryptionTest.
*/
@Suppress("SpellCheckingInspection")
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AttachmentEncryptionTest {
private fun checkDecryption(input: String, encryptedFileInfo: EncryptedFileInfo): String {
val `in` = Base64.decode(input, Base64.DEFAULT)
val inputStream: InputStream
inputStream = if (`in`.isEmpty()) {
ByteArrayInputStream(`in`)
} else {
val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size)
memoryFile.outputStream.write(`in`)
memoryFile.inputStream
}
val decryptedStream = MXEncryptedAttachments.decryptAttachment(inputStream, encryptedFileInfo)
assertNotNull(decryptedStream)
val buffer = ByteArray(100)
val len = decryptedStream!!.read(buffer)
decryptedStream.close()
return Base64.encodeToString(buffer, 0, len, Base64.DEFAULT).replace("\n".toRegex(), "").replace("=".toRegex(), "")
}
@Test
fun checkDecrypt1() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "AAAAAAAAAAAAAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("", checkDecryption("", encryptedFileInfo))
}
@Test
fun checkDecrypt2() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "YzF08lARDdOCzJpzuSwsjTNlQc4pHxpdHcXiD/wpK6k"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "//////////8AAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("SGVsbG8sIFdvcmxk", checkDecryption("5xJZTt5cQicm+9f4", encryptedFileInfo))
}
@Test
fun checkDecrypt3() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "IOq7/dHHB+mfHfxlRY5XMeCWEwTPmlf4cJcgrkf6fVU"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "//////////8AAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("YWxwaGFudW1lcmljYWxseWFscGhhbnVtZXJpY2FsbHlhbHBoYW51bWVyaWNhbGx5YWxwaGFudW1lcmljYWxseQ",
checkDecryption("zhtFStAeFx0s+9L/sSQO+WQMtldqYEHqTxMduJrCIpnkyer09kxJJuA4K+adQE4w+7jZe/vR9kIcqj9rOhDR8Q",
encryptedFileInfo))
}
@Test
fun checkDecrypt4() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "LYG/orOViuFwovJpv2YMLSsmVKwLt7pY3f8SYM7KU5E"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "/////////////////////w",
url = "dummyUrl"
)
assertNotEquals("YWxwaGFudW1lcmljYWxseWFscGhhbnVtZXJpY2FsbHlhbHBoYW51bWVyaWNhbGx5YWxwaGFudW1lcmljYWxseQ",
checkDecryption("tJVNBVJ/vl36UQt4Y5e5m84bRUrQHhcdLPvS/7EkDvlkDLZXamBB6k8THbiawiKZ5Mnq9PZMSSbgOCvmnUBOMA",
encryptedFileInfo))
}
}

View File

@@ -16,20 +16,35 @@
package im.vector.matrix.android.internal.crypto
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import org.junit.Assert.*
import io.realm.Realm
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmSession
private const val DUMMY_DEVICE_KEY = "DeviceKey"
class CryptoStoreTest {
@RunWith(AndroidJUnit4::class)
class CryptoStoreTest : InstrumentedTest {
private val cryptoStoreHelper = CryptoStoreHelper()
@Before
fun setup() {
Realm.init(context())
}
@Test
fun test_metadata_realm_ok() {
val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore()

View File

@@ -0,0 +1,208 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
/**
* Unit tests ExportEncryptionTest.
*/
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ExportEncryptionTest {
@Test
fun checkExportError1() {
val password = "password"
val input = "-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportError2() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\n" + "-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportError3() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\n" +
" AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
" cissyYBxjsfsAn\n" +
" -----END MEGOLM SESSION DATA-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportDecrypt1() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"
val expectedString = "plain"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt1() failed : " + e.message)
}
assertEquals("## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportDecrypt2() {
val password = "betterpassword"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"
val expectedString = "Hello, World"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt2() failed : " + e.message)
}
assertEquals("## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportDecrypt3() {
val password = "SWORDFISH"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt3() failed : " + e.message)
}
assertEquals("## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt1() {
val password = "password"
val expectedString = "plain"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt1() failed : " + e.message)
}
assertEquals("## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt2() {
val password = "betterpassword"
val expectedString = "Hello, World"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt2() failed : " + e.message)
}
assertEquals("## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt3() {
val password = "SWORDFISH"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt3() failed : " + e.message)
}
assertEquals("## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt4() {
val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt4() failed : " + e.message)
}
assertEquals("## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.crosssigning
import org.amshove.kluent.shouldBeNull
import org.amshove.kluent.shouldBeTrue
import org.junit.Test
@Suppress("SpellCheckingInspection")
class ExtensionsKtTest {
@Test
fun testComparingBase64StringWithOrWithoutPadding() {
// Without padding
"NMJyumnhMic".fromBase64().contentEquals("NMJyumnhMic".fromBase64()).shouldBeTrue()
// With padding
"NMJyumnhMic".fromBase64().contentEquals("NMJyumnhMic=".fromBase64()).shouldBeTrue()
}
@Test
fun testBadBase64() {
"===".fromBase64Safe().shouldBeNull()
}
}

View File

@@ -0,0 +1,161 @@
package im.vector.matrix.android.internal.crypto.crosssigning
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.common.SessionTestParams
import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class XSigningTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
@Test
fun test_InitializeAndStoreKeys() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
mTestHelper.doSync<Unit> {
aliceSession.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
), it)
}
val myCrossSigningKeys = aliceSession.cryptoService().crossSigningService().getMyCrossSigningKeys()
val masterPubKey = myCrossSigningKeys?.masterKey()
assertNotNull("Master key should be stored", masterPubKey?.unpaddedBase64PublicKey)
val selfSigningKey = myCrossSigningKeys?.selfSigningKey()
assertNotNull("SelfSigned key should be stored", selfSigningKey?.unpaddedBase64PublicKey)
val userKey = myCrossSigningKeys?.userKey()
assertNotNull("User key should be stored", userKey?.unpaddedBase64PublicKey)
assertTrue("Signing Keys should be trusted", myCrossSigningKeys?.isTrusted() == true)
assertTrue("Signing Keys should be trusted", aliceSession.cryptoService().crossSigningService().checkUserTrust(aliceSession.myUserId).isVerified())
mTestHelper.signOutAndClose(aliceSession)
}
@Test
fun test_CrossSigningCheckBobSeesTheKeys() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceAuthParams = UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
)
val bobAuthParams = UserPasswordAuth(
user = bobSession!!.myUserId,
password = TestConstants.PASSWORD
)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) }
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) }
// Check that alice can see bob keys
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobSession.myUserId)
assertNotNull("Alice can see bob Master key", bobKeysFromAlicePOV!!.masterKey())
assertNull("Alice should not see bob User key", bobKeysFromAlicePOV.userKey())
assertNotNull("Alice can see bob SelfSigned key", bobKeysFromAlicePOV.selfSigningKey())
assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.masterKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey)
assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.selfSigningKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.selfSigningKey()?.unpaddedBase64PublicKey)
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
}
@Test
fun test_CrossSigningTestAliceTrustBobNewDevice() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceAuthParams = UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
)
val bobAuthParams = UserPasswordAuth(
user = bobSession!!.myUserId,
password = TestConstants.PASSWORD
)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) }
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) }
// Check that alice can see bob keys
val bobUserId = bobSession.myUserId
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobUserId)
assertTrue("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV?.isTrusted() == false)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
// Now bobs logs in on a new device and verifies it
// We will want to test that in alice POV, this new device would be trusted by cross signing
val bobSession2 = mTestHelper.logIntoAccount(bobUserId, SessionTestParams(true))
val bobSecondDeviceId = bobSession2.sessionParams.credentials.deviceId!!
// Check that bob first session sees the new login
val data = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
bobSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
if (data.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId) == false) {
fail("Bob should see the new device")
}
val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getDeviceInfo(bobUserId, bobSecondDeviceId)
assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice)
// Manually mark it as trusted from first session
mTestHelper.doSync<Unit> {
bobSession.cryptoService().crossSigningService().trustDevice(bobSecondDeviceId, it)
}
// Now alice should cross trust bob's second device
val data2 = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
// check that the device is seen
if (data2.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId) == false) {
fail("Alice should see the new device")
}
val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
mTestHelper.signOutAndClose(bobSession2)
}
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.gossiping
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.SessionTestParams
import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.internal.crypto.GossipingRequestState
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestState
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNotNull
import junit.framework.TestCase.assertTrue
import junit.framework.TestCase.fail
import org.junit.Assert
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class KeyShareTests : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
@Test
fun test_DoNotSelfShareIfNotTrusted() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
// Create an encrypted room and add a message
val roomId = mTestHelper.doSync<String> {
aliceSession.createRoom(
CreateRoomParams(RoomDirectoryVisibility.PRIVATE).enableEncryptionWithAlgorithm(true),
it
)
}
val room = aliceSession.getRoom(roomId)
assertNotNull(room)
Thread.sleep(4_000)
assertTrue(room?.isEncrypted() == true)
val sentEventId = mTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId
// Open a new sessionx
val aliceSession2 = mTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
val roomSecondSessionPOV = aliceSession2.getRoom(roomId)
val receivedEvent = roomSecondSessionPOV?.getTimeLineEvent(sentEventId)
assertNotNull(receivedEvent)
assert(receivedEvent!!.isEncrypted())
try {
aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
fail("should fail")
} catch (failure: Throwable) {
}
val outgoingRequestBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
// Try to request
aliceSession2.cryptoService().requestRoomKeyForEvent(receivedEvent.root)
val waitLatch = CountDownLatch(1)
val eventMegolmSessionId = receivedEvent.root.content.toModel<EncryptedEventContent>()?.sessionId
var outGoingRequestId: String? = null
mTestHelper.retryPeriodicallyWithLatch(waitLatch) {
aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
.filter { req ->
// filter out request that was known before
!outgoingRequestBefore.any { req.requestId == it.requestId }
}
.let {
val outgoing = it.firstOrNull { it.sessionId == eventMegolmSessionId }
outGoingRequestId = outgoing?.requestId
outgoing != null
}
}
mTestHelper.await(waitLatch)
Log.v("TEST", "=======> Outgoing requet Id is $outGoingRequestId")
val outgoingRequestAfter = aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
// We should have a new request
Assert.assertTrue(outgoingRequestAfter.size > outgoingRequestBefore.size)
Assert.assertNotNull(outgoingRequestAfter.first { it.sessionId == eventMegolmSessionId })
// The first session should see an incoming request
// the request should be refused, because the device is not trusted
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
// DEBUG LOGS
aliceSession.cryptoService().getIncomingRoomKeyRequest().let {
Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
Log.v("TEST", "=========================")
it.forEach { keyRequest ->
Log.v("TEST", "[ts${keyRequest.localCreationTimestamp}] requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId} is ${keyRequest.state}")
}
Log.v("TEST", "=========================")
}
val incoming = aliceSession.cryptoService().getIncomingRoomKeyRequest().firstOrNull { it.requestId == outGoingRequestId }
incoming?.state == GossipingRequestState.REJECTED
}
}
try {
aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
fail("should fail")
} catch (failure: Throwable) {
}
// Mark the device as trusted
aliceSession.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId,
aliceSession2.sessionParams.credentials.deviceId ?: "")
// Re request
aliceSession2.cryptoService().reRequestRoomKeyForEvent(receivedEvent.root)
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
aliceSession.cryptoService().getIncomingRoomKeyRequest().let {
Log.v("TEST", "Incoming request Session 1")
Log.v("TEST", "=========================")
it.forEach {
Log.v("TEST", "requestId ${it.requestId}, for sessionId ${it.requestBody?.sessionId} is ${it.state}")
}
Log.v("TEST", "=========================")
it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == GossipingRequestState.ACCEPTED }
}
}
}
Thread.sleep(6_000)
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
aliceSession2.cryptoService().getOutgoingRoomKeyRequest().let {
it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == OutgoingGossipingRequestState.CANCELLED }
}
}
}
try {
aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
} catch (failure: Throwable) {
fail("should have been able to decrypt")
}
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(aliceSession2)
}
@Test
fun test_ShareSSSSSecret() {
val aliceSession1 = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
mTestHelper.doSync<Unit> {
aliceSession1.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession1.myUserId,
password = TestConstants.PASSWORD
), it)
}
// Also bootstrap keybackup on first session
val creationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
aliceSession1.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it)
}
val version = mTestHelper.doSync<KeysVersion> {
aliceSession1.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it)
}
// Save it for gossiping
aliceSession1.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
val aliceSession2 = mTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true))
val aliceVerificationService1 = aliceSession1.cryptoService().verificationService()
val aliceVerificationService2 = aliceSession2.cryptoService().verificationService()
// force keys download
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession1.cryptoService().downloadKeys(listOf(aliceSession1.myUserId), true, it)
}
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession2.cryptoService().downloadKeys(listOf(aliceSession2.myUserId), true, it)
}
var session1ShortCode: String? = null
var session2ShortCode: String? = null
aliceVerificationService1.addListener(object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.d("#TEST", "AA: tx incoming?:${tx.isIncoming} state ${tx.state}")
if (tx is SasVerificationTransaction) {
if (tx.state == VerificationTxState.OnStarted) {
(tx as IncomingSasVerificationTransaction).performAccept()
}
if (tx.state == VerificationTxState.ShortCodeReady) {
session1ShortCode = tx.getDecimalCodeRepresentation()
tx.userHasVerifiedShortCode()
}
}
}
})
aliceVerificationService2.addListener(object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.d("#TEST", "BB: tx incoming?:${tx.isIncoming} state ${tx.state}")
if (tx is SasVerificationTransaction) {
if (tx.state == VerificationTxState.ShortCodeReady) {
session2ShortCode = tx.getDecimalCodeRepresentation()
tx.userHasVerifiedShortCode()
}
}
}
})
val txId: String = "m.testVerif12"
aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.credentials.deviceId
?: "", txId)
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.credentials.deviceId ?: "")?.isVerified == true
}
}
assertNotNull(session1ShortCode)
Log.d("#TEST", "session1ShortCode: $session1ShortCode")
assertNotNull(session2ShortCode)
Log.d("#TEST", "session2ShortCode: $session2ShortCode")
assertEquals(session1ShortCode, session2ShortCode)
// SSK and USK private keys should have been shared
mTestHelper.waitWithLatch(60_000) { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
Log.d("#TEST", "CAN XS :${aliceSession2.cryptoService().crossSigningService().getMyCrossSigningKeys()}")
aliceSession2.cryptoService().crossSigningService().canCrossSign()
}
}
// Test that key backup key has been shared to
mTestHelper.waitWithLatch(60_000) { latch ->
val keysBackupService = aliceSession2.cryptoService().keysBackupService()
mTestHelper.retryPeriodicallyWithLatch(latch) {
Log.d("#TEST", "Recovery :${ keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}")
keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey == creationInfo.recoveryKey
}
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.common.assertByteArrayNotEqual
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmPkDecryption
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class KeysBackupPasswordTest : InstrumentedTest {
@Before
fun ensureLibLoaded() {
OlmManager()
}
/**
* Check KeysBackupPassword utilities
*/
@Test
fun passwordConverter_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check generatePrivateKeyWithPassword progress listener behavior
*/
@Test
fun passwordConverter_progress_ok() {
val progressValues = ArrayList<Int>(101)
var lastTotal = 0
generatePrivateKeyWithPassword(PASSWORD, object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
if (!progressValues.contains(progress)) {
progressValues.add(progress)
}
lastTotal = total
}
})
assertEquals(100, lastTotal)
// Ensure all values are here
assertEquals(101, progressValues.size)
for (i in 0..100) {
assertTrue(progressValues[i] == i)
}
}
/**
* Check KeysBackupPassword utilities, with bad password
*/
@Test
fun passwordConverter_badPassword_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad password
val retrievedPrivateKey = retrievePrivateKeyWithPassword(BAD_PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check KeysBackupPassword utilities, with bad password
*/
@Test
fun passwordConverter_badIteration_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
generatePrivateKeyResult.salt,
500_001)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check KeysBackupPassword utilities, with bad salt
*/
@Test
fun passwordConverter_badSalt_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
BAD_SALT,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check [retrievePrivateKeyWithPassword] with data coming from another platform (RiotWeb).
*/
@Test
fun passwordConverter_crossPlatform_ok() {
val password = "This is a passphrase!"
val salt = "TO0lxhQ9aYgGfMsclVWPIAublg8h9Nlu"
val iteration = 500_000
val retrievedPrivateKey = retrievePrivateKeyWithPassword(password, salt, iteration)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
// Data from RiotWeb
val privateKeyBytes = byteArrayOf(
116.toByte(), 224.toByte(), 229.toByte(), 224.toByte(), 9.toByte(), 3.toByte(), 178.toByte(), 162.toByte(),
120.toByte(), 23.toByte(), 108.toByte(), 218.toByte(), 22.toByte(), 61.toByte(), 241.toByte(), 200.toByte(),
235.toByte(), 173.toByte(), 236.toByte(), 100.toByte(), 115.toByte(), 247.toByte(), 33.toByte(), 132.toByte(),
195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte())
assertArrayEquals(privateKeyBytes, retrievedPrivateKey)
}
companion object {
private const val PASSWORD = "password"
private const val BAD_PASSWORD = "passw0rd"
private const val BAD_SALT = "AA0lxhQ9aYgGfMsclVWPIAublg8h9Nlu"
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.keysbackup
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import java.util.concurrent.CountDownLatch
/**
* This class observe the state change of a KeysBackup object and provide a method to check the several state change
* It checks all state transitions and detected forbidden transition
*/
internal class StateObserver(private val keysBackup: KeysBackupService,
private val latch: CountDownLatch? = null,
private val expectedStateChange: Int = -1) : KeysBackupStateListener {
private val allowedStateTransitions = listOf(
KeysBackupState.BackingUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.BackingUp to KeysBackupState.WrongBackUpVersion,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.Disabled,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.NotTrusted,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.ReadyToBackUp,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.Unknown,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.WrongBackUpVersion,
KeysBackupState.Disabled to KeysBackupState.Enabling,
KeysBackupState.Enabling to KeysBackupState.Disabled,
KeysBackupState.Enabling to KeysBackupState.ReadyToBackUp,
KeysBackupState.NotTrusted to KeysBackupState.CheckingBackUpOnHomeserver,
// This transition happens when we trust the device
KeysBackupState.NotTrusted to KeysBackupState.ReadyToBackUp,
KeysBackupState.ReadyToBackUp to KeysBackupState.WillBackUp,
KeysBackupState.Unknown to KeysBackupState.CheckingBackUpOnHomeserver,
KeysBackupState.WillBackUp to KeysBackupState.BackingUp,
KeysBackupState.WrongBackUpVersion to KeysBackupState.CheckingBackUpOnHomeserver,
// FIXME These transitions are observed during test, and I'm not sure they should occur. Don't have time to investigate now
KeysBackupState.ReadyToBackUp to KeysBackupState.BackingUp,
KeysBackupState.ReadyToBackUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.WillBackUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.WillBackUp to KeysBackupState.Unknown
)
private val stateList = ArrayList<KeysBackupState>()
private var lastTransitionError: String? = null
init {
keysBackup.addListener(this)
}
// TODO Make expectedStates mandatory to enforce test
fun stopAndCheckStates(expectedStates: List<KeysBackupState>?) {
keysBackup.removeListener(this)
expectedStates?.let {
assertEquals(it.size, stateList.size)
for (i in it.indices) {
assertEquals("The state $i is not correct. states: " + stateList.joinToString(separator = " "), it[i], stateList[i])
}
}
assertNull("states: " + stateList.joinToString(separator = " "), lastTransitionError)
}
override fun onStateChange(newState: KeysBackupState) {
stateList.add(newState)
// Check that state transition is valid
if (stateList.size >= 2
&& !allowedStateTransitions.contains(stateList[stateList.size - 2] to newState)) {
// Forbidden transition detected
lastTransitionError = "Forbidden transition detected from " + stateList[stateList.size - 2] + " to " + newState
}
if (expectedStateChange == stateList.size) {
latch?.countDown()
}
}
}

View File

@@ -0,0 +1,363 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.ssss
import androidx.lifecycle.Observer
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.securestorage.EncryptedSecretContent
import im.vector.matrix.android.api.session.securestorage.KeySigner
import im.vector.matrix.android.api.session.securestorage.RawBytesKeySpec
import im.vector.matrix.android.api.session.securestorage.SecretStorageKeyContent
import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService
import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.SessionTestParams
import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.common.TestMatrixCallback
import im.vector.matrix.android.internal.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2
import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding
import im.vector.matrix.android.internal.crypto.secrets.DefaultSharedSecretStorageService
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.shouldBe
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class QuadSTests : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val emptyKeySigner = object : KeySigner {
override fun sign(canonicalJson: String): Map<String, Map<String, String>>? {
return null
}
}
@Test
fun test_Generate4SKey() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val quadS = aliceSession.sharedSecretStorageService
val TEST_KEY_ID = "my.test.Key"
mTestHelper.doSync<SsssKeyCreationInfo> {
quadS.generateKey(TEST_KEY_ID, null, "Test Key", emptyKeySigner, it)
}
// Assert Account data is updated
val accountDataLock = CountDownLatch(1)
var accountData: UserAccountDataEvent? = null
val liveAccountData = runBlocking(Dispatchers.Main) {
aliceSession.getLiveAccountDataEvent("${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID")
}
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
if (t?.getOrNull()?.type == "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID") {
accountData = t.getOrNull()
accountDataLock.countDown()
}
}
GlobalScope.launch(Dispatchers.Main) { liveAccountData.observeForever(accountDataObserver) }
mTestHelper.await(accountDataLock)
assertNotNull("Key should be stored in account data", accountData)
val parsed = SecretStorageKeyContent.fromJson(accountData!!.content)
assertNotNull("Key Content cannot be parsed", parsed)
assertEquals("Unexpected Algorithm", SSSS_ALGORITHM_AES_HMAC_SHA2, parsed!!.algorithm)
assertEquals("Unexpected key name", "Test Key", parsed.name)
assertNull("Key was not generated from passphrase", parsed.passphrase)
// Set as default key
quadS.setDefaultKey(TEST_KEY_ID, object : MatrixCallback<Unit> {})
var defaultKeyAccountData: UserAccountDataEvent? = null
val defaultDataLock = CountDownLatch(1)
val liveDefAccountData = runBlocking(Dispatchers.Main) {
aliceSession.getLiveAccountDataEvent(DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
}
val accountDefDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
if (t?.getOrNull()?.type == DefaultSharedSecretStorageService.DEFAULT_KEY_ID) {
defaultKeyAccountData = t.getOrNull()!!
defaultDataLock.countDown()
}
}
GlobalScope.launch(Dispatchers.Main) { liveDefAccountData.observeForever(accountDefDataObserver) }
mTestHelper.await(defaultDataLock)
assertNotNull(defaultKeyAccountData?.content)
assertEquals("Unexpected default key ${defaultKeyAccountData?.content}", TEST_KEY_ID, defaultKeyAccountData?.content?.get("key"))
mTestHelper.signOutAndClose(aliceSession)
}
@Test
fun test_StoreSecret() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val keyId = "My.Key"
val info = generatedSecret(aliceSession, keyId, true)
val keySpec = RawBytesKeySpec.fromRecoveryKey(info.recoveryKey)
// Store a secret
val clearSecret = "42".toByteArray().toBase64NoPadding()
mTestHelper.doSync<Unit> {
aliceSession.sharedSecretStorageService.storeSecret(
"secret.of.life",
clearSecret,
listOf(SharedSecretStorageService.KeyRef(null, keySpec)), // default key
it
)
}
val secretAccountData = assertAccountData(aliceSession, "secret.of.life")
val encryptedContent = secretAccountData.content.get("encrypted") as? Map<*, *>
assertNotNull("Element should be encrypted", encryptedContent)
assertNotNull("Secret should be encrypted with default key", encryptedContent?.get(keyId))
val secret = EncryptedSecretContent.fromJson(encryptedContent?.get(keyId))
assertNotNull(secret?.ciphertext)
assertNotNull(secret?.mac)
assertNotNull(secret?.initializationVector)
// Try to decrypt??
val decryptedSecret = mTestHelper.doSync<String> {
aliceSession.sharedSecretStorageService.getSecret(
"secret.of.life",
null, // default key
keySpec!!,
it
)
}
assertEquals("Secret mismatch", clearSecret, decryptedSecret)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
fun test_SetDefaultLocalEcho() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val quadS = aliceSession.sharedSecretStorageService
val TEST_KEY_ID = "my.test.Key"
mTestHelper.doSync<SsssKeyCreationInfo> {
quadS.generateKey(TEST_KEY_ID, null, "Test Key", emptyKeySigner, it)
}
// Test that we don't need to wait for an account data sync to access directly the keyid from DB
mTestHelper.doSync<Unit> {
quadS.setDefaultKey(TEST_KEY_ID, it)
}
mTestHelper.signOutAndClose(aliceSession)
}
@Test
fun test_StoreSecretWithMultipleKey() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val keyId1 = "Key.1"
val key1Info = generatedSecret(aliceSession, keyId1, true)
val keyId2 = "Key2"
val key2Info = generatedSecret(aliceSession, keyId2, true)
val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
mTestHelper.doSync<Unit> {
aliceSession.sharedSecretStorageService.storeSecret(
"my.secret",
mySecretText.toByteArray().toBase64NoPadding(),
listOf(
SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)),
SharedSecretStorageService.KeyRef(keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey))
),
it
)
}
val accountDataEvent = aliceSession.getAccountDataEvent("my.secret")
val encryptedContent = accountDataEvent?.content?.get("encrypted") as? Map<*, *>
assertEquals("Content should contains two encryptions", 2, encryptedContent?.keys?.size ?: 0)
assertNotNull(encryptedContent?.get(keyId1))
assertNotNull(encryptedContent?.get(keyId2))
// Assert that can decrypt with both keys
mTestHelper.doSync<String> {
aliceSession.sharedSecretStorageService.getSecret("my.secret",
keyId1,
RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)!!,
it
)
}
mTestHelper.doSync<String> {
aliceSession.sharedSecretStorageService.getSecret("my.secret",
keyId2,
RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!!,
it
)
}
mTestHelper.signOutAndClose(aliceSession)
}
@Test
fun test_GetSecretWithBadPassphrase() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val keyId1 = "Key.1"
val passphrase = "The good pass phrase"
val key1Info = generatedSecretFromPassphrase(aliceSession, passphrase, keyId1, true)
val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
mTestHelper.doSync<Unit> {
aliceSession.sharedSecretStorageService.storeSecret(
"my.secret",
mySecretText.toByteArray().toBase64NoPadding(),
listOf(SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey))),
it
)
}
val decryptCountDownLatch = CountDownLatch(1)
var error = false
aliceSession.sharedSecretStorageService.getSecret("my.secret",
keyId1,
RawBytesKeySpec.fromPassphrase(
"A bad passphrase",
key1Info.content?.passphrase?.salt ?: "",
key1Info.content?.passphrase?.iterations ?: 0,
null),
object : MatrixCallback<String> {
override fun onSuccess(data: String) {
decryptCountDownLatch.countDown()
}
override fun onFailure(failure: Throwable) {
error = true
decryptCountDownLatch.countDown()
}
}
)
mTestHelper.await(decryptCountDownLatch)
error shouldBe true
// Now try with correct key
mTestHelper.doSync<String> {
aliceSession.sharedSecretStorageService.getSecret("my.secret",
keyId1,
RawBytesKeySpec.fromPassphrase(
passphrase,
key1Info.content?.passphrase?.salt ?: "",
key1Info.content?.passphrase?.iterations ?: 0,
null),
it
)
}
mTestHelper.signOutAndClose(aliceSession)
}
private fun assertAccountData(session: Session, type: String): UserAccountDataEvent {
val accountDataLock = CountDownLatch(1)
var accountData: UserAccountDataEvent? = null
val liveAccountData = runBlocking(Dispatchers.Main) {
session.getLiveAccountDataEvent(type)
}
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
if (t?.getOrNull()?.type == type) {
accountData = t.getOrNull()
accountDataLock.countDown()
}
}
GlobalScope.launch(Dispatchers.Main) { liveAccountData.observeForever(accountDataObserver) }
mTestHelper.await(accountDataLock)
assertNotNull("Account Data type:$type should be found", accountData)
return accountData!!
}
private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
val quadS = session.sharedSecretStorageService
val creationInfo = mTestHelper.doSync<SsssKeyCreationInfo> {
quadS.generateKey(keyId, null, keyId, emptyKeySigner, it)
}
assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
if (asDefault) {
mTestHelper.doSync<Unit> {
quadS.setDefaultKey(keyId, it)
}
assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
}
return creationInfo
}
private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
val quadS = session.sharedSecretStorageService
val creationInfo = mTestHelper.doSync<SsssKeyCreationInfo> {
quadS.generateKeyWithPassphrase(
keyId,
keyId,
passphrase,
emptyKeySigner,
null,
it)
}
assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
if (asDefault) {
val setDefaultLatch = CountDownLatch(1)
quadS.setDefaultKey(keyId, TestMatrixCallback(setDefaultLatch))
mTestHelper.await(setDefaultLatch)
assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
}
return creationInfo
}
}

View File

@@ -0,0 +1,615 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.verification.CancelCode
import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.OutgoingSasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.SasMode
import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationCancel
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.model.rest.toValue
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SASTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
@Test
fun test_aliceStartThenAliceCancel() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession!!.cryptoService().verificationService()
val bobTxCreatedLatch = CountDownLatch(1)
val bobListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
bobTxCreatedLatch.countDown()
}
}
bobVerificationService.addListener(bobListener)
val txID = aliceVerificationService.beginKeyVerification(VerificationMethod.SAS,
bobSession.myUserId,
bobSession.cryptoService().getMyDevice().deviceId,
null)
assertNotNull("Alice should have a started transaction", txID)
val aliceKeyTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID!!)
assertNotNull("Alice should have a started transaction", aliceKeyTx)
mTestHelper.await(bobTxCreatedLatch)
bobVerificationService.removeListener(bobListener)
val bobKeyTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID)
assertNotNull("Bob should have started verif transaction", bobKeyTx)
assertTrue(bobKeyTx is SASDefaultVerificationTransaction)
assertNotNull("Bob should have starting a SAS transaction", bobKeyTx)
assertTrue(aliceKeyTx is SASDefaultVerificationTransaction)
assertEquals("Alice and Bob have same transaction id", aliceKeyTx!!.transactionId, bobKeyTx!!.transactionId)
val aliceSasTx = aliceKeyTx as SASDefaultVerificationTransaction?
val bobSasTx = bobKeyTx as SASDefaultVerificationTransaction?
assertEquals("Alice state should be started", VerificationTxState.Started, aliceSasTx!!.state)
assertEquals("Bob state should be started by alice", VerificationTxState.OnStarted, bobSasTx!!.state)
// Let's cancel from alice side
val cancelLatch = CountDownLatch(1)
val bobListener2 = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
if (tx.transactionId == txID) {
val immutableState = (tx as SASDefaultVerificationTransaction).state
if (immutableState is VerificationTxState.Cancelled && !immutableState.byMe) {
cancelLatch.countDown()
}
}
}
}
bobVerificationService.addListener(bobListener2)
aliceSasTx.cancel(CancelCode.User)
mTestHelper.await(cancelLatch)
assertTrue("Should be cancelled on alice side", aliceSasTx.state is VerificationTxState.Cancelled)
assertTrue("Should be cancelled on bob side", bobSasTx.state is VerificationTxState.Cancelled)
val aliceCancelState = aliceSasTx.state as VerificationTxState.Cancelled
val bobCancelState = bobSasTx.state as VerificationTxState.Cancelled
assertTrue("Should be cancelled by me on alice side", aliceCancelState.byMe)
assertFalse("Should be cancelled by other on bob side", bobCancelState.byMe)
assertEquals("Should be User cancelled on alice side", CancelCode.User, aliceCancelState.cancelCode)
assertEquals("Should be User cancelled on bob side", CancelCode.User, bobCancelState.cancelCode)
assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID))
assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID))
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_key_agreement_protocols_must_include_curve25519() {
fail("Not passing for the moment")
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val protocols = listOf("meh_dont_know")
val tid = "00000000"
// Bob should receive a cancel
var cancelReason: CancelCode? = null
val cancelLatch = CountDownLatch(1)
val bobListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
if (tx.transactionId == tid && tx.state is VerificationTxState.Cancelled) {
cancelReason = (tx.state as VerificationTxState.Cancelled).cancelCode
cancelLatch.countDown()
}
}
}
bobSession.cryptoService().verificationService().addListener(bobListener)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.cryptoService().getMyDevice().deviceId
val aliceListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
if ((tx as IncomingSasVerificationTransaction).uxState === IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) {
(tx as IncomingSasVerificationTransaction).performAccept()
}
}
}
aliceSession.cryptoService().verificationService().addListener(aliceListener)
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, protocols = protocols)
mTestHelper.await(cancelLatch)
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason)
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_key_agreement_macs_Must_include_hmac_sha256() {
fail("Not passing for the moment")
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val mac = listOf("shaBit")
val tid = "00000000"
// Bob should receive a cancel
var canceledToDeviceEvent: Event? = null
val cancelLatch = CountDownLatch(1)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.cryptoService().getMyDevice().deviceId
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, mac = mac)
mTestHelper.await(cancelLatch)
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_key_agreement_short_code_include_decimal() {
fail("Not passing for the moment")
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val codes = listOf("bin", "foo", "bar")
val tid = "00000000"
// Bob should receive a cancel
var canceledToDeviceEvent: Event? = null
val cancelLatch = CountDownLatch(1)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.cryptoService().getMyDevice().deviceId
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, codes = codes)
mTestHelper.await(cancelLatch)
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.cleanUp(mTestHelper)
}
private fun fakeBobStart(bobSession: Session,
aliceUserID: String?,
aliceDevice: String?,
tid: String,
protocols: List<String> = SASDefaultVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS,
hashes: List<String> = SASDefaultVerificationTransaction.KNOWN_HASHES,
mac: List<String> = SASDefaultVerificationTransaction.KNOWN_MACS,
codes: List<String> = SASDefaultVerificationTransaction.KNOWN_SHORT_CODES) {
val startMessage = KeyVerificationStart(
fromDevice = bobSession.cryptoService().getMyDevice().deviceId,
method = VerificationMethod.SAS.toValue(),
transactionId = tid,
keyAgreementProtocols = protocols,
hashes = hashes,
messageAuthenticationCodes = mac,
shortAuthenticationStrings = codes
)
val contentMap = MXUsersDevicesMap<Any>()
contentMap.setObject(aliceUserID, aliceDevice, startMessage)
// TODO val sendLatch = CountDownLatch(1)
// TODO bobSession.cryptoRestClient.sendToDevice(
// TODO EventType.KEY_VERIFICATION_START,
// TODO contentMap,
// TODO tid,
// TODO TestMatrixCallback<Void>(sendLatch)
// TODO )
}
// any two devices may only have at most one key verification in flight at a time.
// If a device has two verifications in progress with the same device, then it should cancel both verifications.
@Test
fun test_aliceStartTwoRequests() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val aliceCreatedLatch = CountDownLatch(2)
val aliceCancelledLatch = CountDownLatch(2)
val createdTx = mutableListOf<SASDefaultVerificationTransaction>()
val aliceListener = object : VerificationService.Listener {
override fun transactionCreated(tx: VerificationTransaction) {
createdTx.add(tx as SASDefaultVerificationTransaction)
aliceCreatedLatch.countDown()
}
override fun transactionUpdated(tx: VerificationTransaction) {
if ((tx as SASDefaultVerificationTransaction).state is VerificationTxState.Cancelled && !(tx.state as VerificationTxState.Cancelled).byMe) {
aliceCancelledLatch.countDown()
}
}
}
aliceVerificationService.addListener(aliceListener)
val bobUserId = bobSession!!.myUserId
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
mTestHelper.await(aliceCreatedLatch)
mTestHelper.await(aliceCancelledLatch)
cryptoTestData.cleanUp(mTestHelper)
}
/**
* Test that when alice starts a 'correct' request, bob agrees.
*/
@Test
fun test_aliceAndBobAgreement() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession!!.cryptoService().verificationService()
var accepted: ValidVerificationInfoAccept? = null
var startReq: ValidVerificationInfoStart.SasVerificationInfoStart? = null
val aliceAcceptedLatch = CountDownLatch(1)
val aliceListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.v("TEST", "== aliceTx state ${tx.state} => ${(tx as? OutgoingSasVerificationTransaction)?.uxState}")
if ((tx as SASDefaultVerificationTransaction).state === VerificationTxState.OnAccepted) {
val at = tx as SASDefaultVerificationTransaction
accepted = at.accepted
startReq = at.startReq
aliceAcceptedLatch.countDown()
}
}
}
aliceVerificationService.addListener(aliceListener)
val bobListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.v("TEST", "== bobTx state ${tx.state} => ${(tx as? IncomingSasVerificationTransaction)?.uxState}")
if ((tx as IncomingSasVerificationTransaction).uxState === IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) {
bobVerificationService.removeListener(this)
val at = tx as IncomingSasVerificationTransaction
at.performAccept()
}
}
}
bobVerificationService.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
mTestHelper.await(aliceAcceptedLatch)
assertTrue("Should have receive a commitment", accepted!!.commitment?.trim()?.isEmpty() == false)
// check that agreement is valid
assertTrue("Agreed Protocol should be Valid", accepted != null)
assertTrue("Agreed Protocol should be known by alice", startReq!!.keyAgreementProtocols.contains(accepted!!.keyAgreementProtocol))
assertTrue("Hash should be known by alice", startReq!!.hashes.contains(accepted!!.hash))
assertTrue("Hash should be known by alice", startReq!!.messageAuthenticationCodes.contains(accepted!!.messageAuthenticationCode))
accepted!!.shortAuthenticationStrings.forEach {
assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings.contains(it))
}
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_aliceAndBobSASCode() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession!!.cryptoService().verificationService()
val aliceSASLatch = CountDownLatch(1)
val aliceListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
val uxState = (tx as OutgoingSasVerificationTransaction).uxState
when (uxState) {
OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> {
aliceSASLatch.countDown()
}
else -> Unit
}
}
}
aliceVerificationService.addListener(aliceListener)
val bobSASLatch = CountDownLatch(1)
val bobListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
val uxState = (tx as IncomingSasVerificationTransaction).uxState
when (uxState) {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
tx.performAccept()
}
else -> Unit
}
if (uxState === IncomingSasVerificationTransaction.UxState.SHOW_SAS) {
bobSASLatch.countDown()
}
}
}
bobVerificationService.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
val verificationSAS = aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
mTestHelper.await(aliceSASLatch)
mTestHelper.await(bobSASLatch)
val aliceTx = aliceVerificationService.getExistingTransaction(bobUserId, verificationSAS!!) as SASDefaultVerificationTransaction
val bobTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SASDefaultVerificationTransaction
assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_happyPath() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession!!.cryptoService().verificationService()
val aliceSASLatch = CountDownLatch(1)
val aliceListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
val uxState = (tx as OutgoingSasVerificationTransaction).uxState
when (uxState) {
OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> {
tx.userHasVerifiedShortCode()
}
OutgoingSasVerificationTransaction.UxState.VERIFIED -> {
aliceSASLatch.countDown()
}
else -> Unit
}
}
}
aliceVerificationService.addListener(aliceListener)
val bobSASLatch = CountDownLatch(1)
val bobListener = object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
val uxState = (tx as IncomingSasVerificationTransaction).uxState
when (uxState) {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
tx.performAccept()
}
IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
tx.userHasVerifiedShortCode()
}
IncomingSasVerificationTransaction.UxState.VERIFIED -> {
bobSASLatch.countDown()
}
else -> Unit
}
}
}
bobVerificationService.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
mTestHelper.await(aliceSASLatch)
mTestHelper.await(bobSASLatch)
// Assert that devices are verified
val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
// latch wait a bit again
Thread.sleep(1000)
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_ConcurrentStart() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession!!.cryptoService().verificationService()
val req = aliceVerificationService.requestKeyVerificationInDMs(
listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
bobSession.myUserId,
cryptoTestData.roomId
)
var requestID : String? = null
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
requestID = prAlicePOV?.transactionId
Log.v("TEST", "== alicePOV is $prAlicePOV")
prAlicePOV?.transactionId != null && prAlicePOV.localId == req.localId
}
}
Log.v("TEST", "== requestID is $requestID")
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prBobPOV = bobVerificationService.getExistingVerificationRequest(aliceSession.myUserId)?.firstOrNull()
Log.v("TEST", "== prBobPOV is $prBobPOV")
prBobPOV?.transactionId == requestID
}
}
bobVerificationService.readyPendingVerification(
listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
aliceSession.myUserId,
requestID!!
)
// wait for alice to get the ready
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
Log.v("TEST", "== prAlicePOV is $prAlicePOV")
prAlicePOV?.transactionId == requestID && prAlicePOV?.isReady != null
}
}
// Start concurrent!
aliceVerificationService.beginKeyVerificationInDMs(
VerificationMethod.SAS,
requestID!!,
cryptoTestData.roomId,
bobSession.myUserId,
bobSession.sessionParams.credentials.deviceId!!,
null)
bobVerificationService.beginKeyVerificationInDMs(
VerificationMethod.SAS,
requestID!!,
cryptoTestData.roomId,
aliceSession.myUserId,
aliceSession.sessionParams.credentials.deviceId!!,
null)
// we should reach SHOW SAS on both
var alicePovTx: SasVerificationTransaction?
var bobPovTx: SasVerificationTransaction?
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
alicePovTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, requestID!!) as? SasVerificationTransaction
Log.v("TEST", "== alicePovTx is $alicePovTx")
alicePovTx?.state == VerificationTxState.ShortCodeReady
}
}
// wait for alice to get the ready
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
bobPovTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, requestID!!) as? SasVerificationTransaction
Log.v("TEST", "== bobPovTx is $bobPovTx")
bobPovTx?.state == VerificationTxState.ShortCodeReady
}
}
cryptoTestData.cleanUp(mTestHelper)
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification.qrcode
fun hexToByteArray(hex: String): ByteArray {
// Remove all spaces
return hex.replace(" ", "")
.let {
if (it.length % 2 != 0) "0$it" else it
}
.let {
ByteArray(it.length / 2)
.apply {
for (i in this.indices) {
val index = i * 2
val v = it.substring(index, index + 2).toInt(16)
this[i] = v.toByte()
}
}
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification.qrcode
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import org.amshove.kluent.shouldBeNull
import org.amshove.kluent.shouldEqual
import org.amshove.kluent.shouldEqualTo
import org.amshove.kluent.shouldNotBeNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class QrCodeTest : InstrumentedTest {
private val qrCode1 = QrCodeData.VerifyingAnotherUser(
transactionId = "MaTransaction",
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
otherUserMasterCrossSigningPublicKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
sharedSecret = "MTIzNDU2Nzg"
)
private val value1 = "MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val qrCode2 = QrCodeData.SelfVerifyingMasterKeyTrusted(
transactionId = "MaTransaction",
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
otherDeviceKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
sharedSecret = "MTIzNDU2Nzg"
)
private val value2 = "MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val qrCode3 = QrCodeData.SelfVerifyingMasterKeyNotTrusted(
transactionId = "MaTransaction",
deviceKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
sharedSecret = "MTIzNDU2Nzg"
)
private val value3 = "MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008B\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
private val sharedSecretByteArray = "12345678".toByteArray(Charsets.ISO_8859_1)
private val tlx_byteArray = hexToByteArray("4d 79 6e 64 a4 d9 2e f4 91 58 e4 cf 94 ea 8b ab 9d f8 6c 0f bf 2b 8c cb 14 a4 ae f5 c1 8b 41 a5")
private val kte_byteArray = hexToByteArray("92 d1 30 71 43 fa b2 ed 71 87 e1 ae 13 e0 98 91 0d c7 e9 6f c3 22 5f b2 6c 71 5d 68 43 ab a2 55")
@Test
fun testEncoding1() {
qrCode1.toEncodedString() shouldEqual value1
}
@Test
fun testEncoding2() {
qrCode2.toEncodedString() shouldEqual value2
}
@Test
fun testEncoding3() {
qrCode3.toEncodedString() shouldEqual value3
}
@Test
fun testSymmetry1() {
qrCode1.toEncodedString().toQrCodeData() shouldEqual qrCode1
}
@Test
fun testSymmetry2() {
qrCode2.toEncodedString().toQrCodeData() shouldEqual qrCode2
}
@Test
fun testSymmetry3() {
qrCode3.toEncodedString().toQrCodeData() shouldEqual qrCode3
}
@Test
fun testCase1() {
val url = qrCode1.toEncodedString()
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
checkHeader(byteArray)
// Mode
byteArray[7] shouldEqualTo 0
checkSizeAndTransaction(byteArray)
compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray)
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), tlx_byteArray)
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
}
@Test
fun testCase2() {
val url = qrCode2.toEncodedString()
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
checkHeader(byteArray)
// Mode
byteArray[7] shouldEqualTo 1
checkSizeAndTransaction(byteArray)
compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray)
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), tlx_byteArray)
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
}
@Test
fun testCase3() {
val url = qrCode3.toEncodedString()
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
checkHeader(byteArray)
// Mode
byteArray[7] shouldEqualTo 2
checkSizeAndTransaction(byteArray)
compareArray(byteArray.copyOfRange(23, 23 + 32), tlx_byteArray)
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), kte_byteArray)
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
}
@Test
fun testLongTransactionId() {
// Size on two bytes (2_000 = 0x07D0)
val longTransactionId = "PatternId_".repeat(200)
val qrCode = qrCode1.copy(transactionId = longTransactionId)
val result = qrCode.toEncodedString()
val expected = value1.replace("\u0000\u000DMaTransaction", "\u0007\u00D0$longTransactionId")
result shouldEqual expected
// Reverse operation
expected.toQrCodeData() shouldEqual qrCode
}
@Test
fun testAnyTransactionId() {
for (qty in 0 until 0x1FFF step 200) {
val longTransactionId = "a".repeat(qty)
val qrCode = qrCode1.copy(transactionId = longTransactionId)
// Symmetric operation
qrCode.toEncodedString().toQrCodeData() shouldEqual qrCode
}
}
// Error cases
@Test
fun testErrorHeader() {
value1.replace("MATRIX", "MOTRIX").toQrCodeData().shouldBeNull()
value1.replace("MATRIX", "MATRI").toQrCodeData().shouldBeNull()
value1.replace("MATRIX", "").toQrCodeData().shouldBeNull()
}
@Test
fun testErrorVersion() {
value1.replace("MATRIX\u0002", "MATRIX\u0000").toQrCodeData().shouldBeNull()
value1.replace("MATRIX\u0002", "MATRIX\u0001").toQrCodeData().shouldBeNull()
value1.replace("MATRIX\u0002", "MATRIX\u0003").toQrCodeData().shouldBeNull()
value1.replace("MATRIX\u0002", "MATRIX").toQrCodeData().shouldBeNull()
}
@Test
fun testErrorSecretTooShort() {
value1.replace("12345678", "1234567").toQrCodeData().shouldBeNull()
}
@Test
fun testErrorNoTransactionNoKeyNoSecret() {
// But keep transaction length
"MATRIX\u0002\u0000\u0000\u000D".toQrCodeData().shouldBeNull()
}
@Test
fun testErrorNoKeyNoSecret() {
"MATRIX\u0002\u0000\u0000\u000DMaTransaction".toQrCodeData().shouldBeNull()
}
@Test
fun testErrorTransactionLengthTooShort() {
// In this case, the secret will be longer, so this is not an error, but it will lead to keys mismatch
value1.replace("\u000DMaTransaction", "\u000CMaTransaction").toQrCodeData().shouldNotBeNull()
}
@Test
fun testErrorTransactionLengthTooBig() {
value1.replace("\u000DMaTransaction", "\u000EMaTransaction").toQrCodeData().shouldBeNull()
}
private fun compareArray(actual: ByteArray, expected: ByteArray) {
actual.size shouldEqual expected.size
for (i in actual.indices) {
actual[i] shouldEqualTo expected[i]
}
}
private fun checkHeader(byteArray: ByteArray) {
// MATRIX
byteArray[0] shouldEqualTo 'M'.toByte()
byteArray[1] shouldEqualTo 'A'.toByte()
byteArray[2] shouldEqualTo 'T'.toByte()
byteArray[3] shouldEqualTo 'R'.toByte()
byteArray[4] shouldEqualTo 'I'.toByte()
byteArray[5] shouldEqualTo 'X'.toByte()
// Version
byteArray[6] shouldEqualTo 2
}
private fun checkSizeAndTransaction(byteArray: ByteArray) {
// Size
byteArray[8] shouldEqualTo 0
byteArray[9] shouldEqualTo 13
// Transaction
byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldEqual "MaTransaction"
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification.qrcode
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldNotBeEqualTo
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class SharedSecretTest : InstrumentedTest {
@Test
fun testSharedSecretLengthCase() {
repeat(100) {
generateSharedSecretV2().length shouldBe 11
}
}
@Test
fun testSharedDiffCase() {
val sharedSecret1 = generateSharedSecretV2()
val sharedSecret2 = generateSharedSecretV2()
sharedSecret1 shouldNotBeEqualTo sharedSecret2
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification.qrcode
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.session.crypto.verification.PendingVerificationRequest
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
import org.amshove.kluent.shouldBe
import org.junit.Assert.assertEquals
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class VerificationTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
data class ExpectedResult(
val sasIsSupported: Boolean = false,
val otherCanScanQrCode: Boolean = false,
val otherCanShowQrCode: Boolean = false
)
private val sas = listOf(
VerificationMethod.SAS
)
private val sasShow = listOf(
VerificationMethod.SAS,
VerificationMethod.QR_CODE_SHOW
)
private val sasScan = listOf(
VerificationMethod.SAS,
VerificationMethod.QR_CODE_SCAN
)
private val sasShowScan = listOf(
VerificationMethod.SAS,
VerificationMethod.QR_CODE_SHOW,
VerificationMethod.QR_CODE_SCAN
)
@Test
fun test_aliceAndBob_sas_sas() = doTest(
sas,
sas,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_sas_show() = doTest(
sas,
sasShow,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_show_sas() = doTest(
sasShow,
sas,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_sas_scan() = doTest(
sas,
sasScan,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_scan_sas() = doTest(
sasScan,
sas,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_scan_scan() = doTest(
sasScan,
sasScan,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_show_show() = doTest(
sasShow,
sasShow,
ExpectedResult(sasIsSupported = true),
ExpectedResult(sasIsSupported = true)
)
@Test
fun test_aliceAndBob_show_scan() = doTest(
sasShow,
sasScan,
ExpectedResult(sasIsSupported = true, otherCanScanQrCode = true),
ExpectedResult(sasIsSupported = true, otherCanShowQrCode = true)
)
@Test
fun test_aliceAndBob_scan_show() = doTest(
sasScan,
sasShow,
ExpectedResult(sasIsSupported = true, otherCanShowQrCode = true),
ExpectedResult(sasIsSupported = true, otherCanScanQrCode = true)
)
@Test
fun test_aliceAndBob_all_all() = doTest(
sasShowScan,
sasShowScan,
ExpectedResult(sasIsSupported = true, otherCanShowQrCode = true, otherCanScanQrCode = true),
ExpectedResult(sasIsSupported = true, otherCanShowQrCode = true, otherCanScanQrCode = true)
)
// TODO Add tests without SAS
private fun doTest(aliceSupportedMethods: List<VerificationMethod>,
bobSupportedMethods: List<VerificationMethod>,
expectedResultForAlice: ExpectedResult,
expectedResultForBob: ExpectedResult) {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession!!
mTestHelper.doSync<Unit> { callback ->
aliceSession.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
), callback)
}
mTestHelper.doSync<Unit> { callback ->
bobSession.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = bobSession.myUserId,
password = TestConstants.PASSWORD
), callback)
}
val aliceVerificationService = aliceSession.cryptoService().verificationService()
val bobVerificationService = bobSession.cryptoService().verificationService()
var aliceReadyPendingVerificationRequest: PendingVerificationRequest? = null
var bobReadyPendingVerificationRequest: PendingVerificationRequest? = null
val latch = CountDownLatch(2)
val aliceListener = object : VerificationService.Listener {
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
// Step 4: Alice receive the ready request
if (pr.isReady) {
aliceReadyPendingVerificationRequest = pr
latch.countDown()
}
}
}
aliceVerificationService.addListener(aliceListener)
val bobListener = object : VerificationService.Listener {
override fun verificationRequestCreated(pr: PendingVerificationRequest) {
// Step 2: Bob accepts the verification request
bobVerificationService.readyPendingVerificationInDMs(
bobSupportedMethods,
aliceSession.myUserId,
cryptoTestData.roomId,
pr.transactionId!!
)
}
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
// Step 3: Bob is ready
if (pr.isReady) {
bobReadyPendingVerificationRequest = pr
latch.countDown()
}
}
}
bobVerificationService.addListener(bobListener)
val bobUserId = bobSession.myUserId
// Step 1: Alice starts a verification request
aliceVerificationService.requestKeyVerificationInDMs(aliceSupportedMethods, bobUserId, cryptoTestData.roomId)
mTestHelper.await(latch)
aliceReadyPendingVerificationRequest!!.let { pr ->
pr.isSasSupported() shouldBe expectedResultForAlice.sasIsSupported
pr.otherCanShowQrCode() shouldBe expectedResultForAlice.otherCanShowQrCode
pr.otherCanScanQrCode() shouldBe expectedResultForAlice.otherCanScanQrCode
}
bobReadyPendingVerificationRequest!!.let { pr ->
pr.isSasSupported() shouldBe expectedResultForBob.sasIsSupported
pr.otherCanShowQrCode() shouldBe expectedResultForBob.otherCanShowQrCode
pr.otherCanScanQrCode() shouldBe expectedResultForBob.otherCanScanQrCode
}
cryptoTestData.cleanUp(mTestHelper)
}
@Test
fun test_alice_sends_text_message_and_bob_can_decrypt() {
val lock = CountDownLatch(1)
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession!!
val roomFromBobPOV = bobSession.getRoom(cryptoTestData.roomId)!!
aliceSession.getRoom(cryptoTestData.roomId)!!.sendTextMessage("test")
val bobEventsListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
// noop
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
if (snapshot.isNotEmpty() && snapshot.first().root.isEncrypted()) {
lock.countDown()
}
}
}
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(20))
bobTimeline.start()
bobTimeline.addListener(bobEventsListener)
mTestHelper.await(lock)
bobTimeline.getTimelineEventAtIndex(0)?.root?.let {
val decryptionResult = bobSession.cryptoService().decryptEvent(it, "")
val text = (decryptionResult.clearEvent["content"] as Map<*, *>)["body"]
assertEquals("test", text)
}
}
}

View File

@@ -19,16 +19,19 @@ package im.vector.matrix.android.session.room.timeline
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.internal.database.helper.*
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.internal.database.helper.addTimelineEvent
import im.vector.matrix.android.internal.database.helper.merge
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.SessionRealmModule
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeMessageEvent
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeRoomMemberEvent
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.amshove.kluent.shouldEqual
import org.junit.Before
@@ -43,7 +46,11 @@ internal class ChunkEntityTest : InstrumentedTest {
@Before
fun setup() {
Realm.init(context())
val testConfig = RealmConfiguration.Builder().inMemory().name("test-realm").build()
val testConfig = RealmConfiguration.Builder()
.inMemory()
.name("test-realm")
.modules(SessionRealmModule())
.build()
monarchy = Monarchy.Builder().setRealmConfiguration(testConfig).build()
}
@@ -51,8 +58,11 @@ internal class ChunkEntityTest : InstrumentedTest {
fun add_shouldAdd_whenNotAlreadyIncluded() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.timelineEvents.size shouldEqual 1
}
}
@@ -61,65 +71,23 @@ internal class ChunkEntityTest : InstrumentedTest {
fun add_shouldNotAdd_whenAlreadyIncluded() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.timelineEvents.size shouldEqual 1
}
}
@Test
fun add_shouldStateIndexIncremented_whenStateEventIsAddedForward() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeRoomMemberEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual 1
}
}
@Test
fun add_shouldStateIndexNotIncremented_whenNoStateEventIsAdded() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual 0
}
}
@Test
fun addAll_shouldStateIndexIncremented_whenStateEventsAreAddedForward() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvents = createFakeListOfEvents(30)
val numberOfStateEvents = fakeEvents.filter { it.isStateEvent() }.size
chunk.addAll("roomId", fakeEvents, PaginationDirection.FORWARDS)
chunk.lastStateIndex(PaginationDirection.FORWARDS) shouldEqual numberOfStateEvents
}
}
@Test
fun addAll_shouldStateIndexDecremented_whenStateEventsAreAddedBackward() {
monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject()
val fakeEvents = createFakeListOfEvents(30)
val numberOfStateEvents = fakeEvents.filter { it.isStateEvent() }.size
val lastIsState = fakeEvents.last().isStateEvent()
val expectedStateIndex = if (lastIsState) -numberOfStateEvents + 1 else -numberOfStateEvents
chunk.addAll("roomId", fakeEvents, PaginationDirection.BACKWARDS)
chunk.lastStateIndex(PaginationDirection.BACKWARDS) shouldEqual expectedStateIndex
}
}
@Test
fun merge_shouldAddEvents_whenMergingBackward() {
monarchy.runTransactionSync { realm ->
val chunk1: ChunkEntity = realm.createObject()
val chunk2: ChunkEntity = realm.createObject()
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.timelineEvents.size shouldEqual 60
}
}
@@ -133,38 +101,14 @@ internal class ChunkEntityTest : InstrumentedTest {
val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
chunk1.isLastForward = true
chunk2.isLastForward = false
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.timelineEvents.size shouldEqual 40
chunk1.isLastForward.shouldBeTrue()
}
}
@Test
fun merge_shouldEventsBeLinked_whenMergingLinkedWithUnlinked() {
monarchy.runTransactionSync { realm ->
val chunk1: ChunkEntity = realm.createObject()
val chunk2: ChunkEntity = realm.createObject()
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = false)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.isUnlinked().shouldBeFalse()
}
}
@Test
fun merge_shouldEventsBeUnlinked_whenMergingUnlinkedWithUnlinked() {
monarchy.runTransactionSync { realm ->
val chunk1: ChunkEntity = realm.createObject()
val chunk2: ChunkEntity = realm.createObject()
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.isUnlinked().shouldBeTrue()
}
}
@Test
fun merge_shouldPrevTokenMerged_whenMergingForwards() {
monarchy.runTransactionSync { realm ->
@@ -172,9 +116,9 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk2: ChunkEntity = realm.createObject()
val prevToken = "prev_token"
chunk1.prevToken = prevToken
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk1.merge("roomId", chunk2, PaginationDirection.FORWARDS)
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
chunk1.prevToken shouldEqual prevToken
}
}
@@ -186,10 +130,25 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk2: ChunkEntity = realm.createObject()
val nextToken = "next_token"
chunk1.nextToken = nextToken
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS, isUnlinked = true)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.nextToken shouldEqual nextToken
}
}
private fun ChunkEntity.addAll(roomId: String,
events: List<Event>,
direction: PaginationDirection) {
events.forEach { event ->
val fakeEvent = event.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
addTimelineEvent(roomId, fakeEvent, direction, emptyMap())
}
}
companion object {
private const val ROOM_ID = "roomId"
}
}

View File

@@ -16,21 +16,14 @@
package im.vector.matrix.android.session.room.timeline
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
import im.vector.matrix.android.api.session.room.model.message.MessageType
import im.vector.matrix.android.internal.database.helper.addAll
import im.vector.matrix.android.internal.database.helper.addOrUpdate
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import io.realm.kotlin.createObject
import kotlin.random.Random
object RoomDataHelper {
@@ -70,22 +63,7 @@ object RoomDataHelper {
}
fun createFakeRoomMemberEvent(): Event {
val roomMember = RoomMember(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent()
val roomMember = RoomMemberSummary(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent()
return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember)
}
fun fakeInitialSync(monarchy: Monarchy, roomId: String) {
monarchy.runTransactionSync { realm ->
val roomEntity = realm.createObject<RoomEntity>(roomId)
roomEntity.membership = Membership.JOIN
val eventList = createFakeListOfEvents(10)
val chunkEntity = realm.createObject<ChunkEntity>().apply {
nextToken = null
prevToken = Random.nextLong(System.currentTimeMillis()).toString()
isLastForward = true
}
chunkEntity.addAll(roomId, eventList, PaginationDirection.FORWARDS)
roomEntity.addOrUpdate(chunkEntity)
}
}
}

View File

@@ -66,7 +66,7 @@ internal class TimelineTest : InstrumentedTest {
// val latch = CountDownLatch(2)
// var timelineEvents: List<TimelineEvent> = emptyList()
// timeline.listener = object : Timeline.Listener {
// override fun onUpdated(snapshot: List<TimelineEvent>) {
// override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
// if (snapshot.isNotEmpty()) {
// if (initialLoad == 0) {
// initialLoad = snapshot.size

View File

@@ -6,9 +6,10 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<application android:networkSecurityConfig="@xml/network_security_config">
<provider android:name="androidx.work.impl.WorkManagerInitializer"
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />

View File

@@ -23,16 +23,22 @@ import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.BuildConfig
import im.vector.matrix.android.api.auth.AuthenticationService
import im.vector.matrix.android.api.crypto.MXCryptoConfig
import im.vector.matrix.android.internal.SessionManager
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
import im.vector.matrix.android.internal.di.DaggerMatrixComponent
import im.vector.matrix.android.internal.network.UserAgentHolder
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import org.matrix.olm.OlmManager
import java.io.InputStream
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.Executors
import javax.inject.Inject
data class MatrixConfiguration(
val applicationFlavor: String = "Default-application-flavor"
val applicationFlavor: String = "Default-application-flavor",
val cryptoConfig: MXCryptoConfig = MXCryptoConfig()
) {
interface Provider {
@@ -54,12 +60,11 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
init {
Monarchy.init(context)
DaggerMatrixComponent.factory().create(context).inject(this)
DaggerMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
if (context.applicationContext !is Configuration.Provider) {
WorkManager.initialize(context, Configuration.Builder().build())
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
}
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
userAgentHolder.setApplicationFlavor(matrixConfiguration.applicationFlavor)
}
fun getUserAgent() = userAgentHolder.userAgent
@@ -96,5 +101,9 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
fun getSdkVersion(): String {
return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")"
}
fun decryptStream(inputStream: InputStream?, elementToDecrypt: ElementToDecrypt): InputStream? {
return MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt)
}
}
}

View File

@@ -38,3 +38,8 @@ interface MatrixCallback<in T> {
// no-op
}
}
/**
* Basic no op implementation
*/
class NoOpMatrixCallback<T>: MatrixCallback<T>

View File

@@ -122,9 +122,9 @@ object MatrixPatterns {
*/
fun isEventId(str: String?): Boolean {
return str != null
&& (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
&& (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
}
/**
@@ -144,14 +144,6 @@ object MatrixPatterns {
* @return null if not found or if matrixId is null
*/
fun extractServerNameFromId(matrixId: String?): String? {
if (matrixId == null) {
return null
}
val index = matrixId.indexOf(":")
return if (index == -1) {
null
} else matrixId.substring(index + 1)
return matrixId?.substringAfter(":", missingDelimiterValue = "")?.takeIf { it.isNotEmpty() }
}
}

View File

@@ -18,6 +18,7 @@ package im.vector.matrix.android.api.auth.data
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.util.md5
/**
* This data class hold credentials user data.
@@ -34,3 +35,7 @@ data class Credentials(
// Optional data that may contain info to override home server and/or identity server
@Json(name = "well_known") val wellKnown: WellKnown? = null
)
internal fun Credentials.sessionId(): String {
return (if (deviceId.isNullOrBlank()) userId else "$userId|$deviceId").md5()
}

View File

@@ -46,13 +46,13 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class WellKnown(
@Json(name = "m.homeserver")
var homeServer: WellKnownBaseConfig? = null,
val homeServer: WellKnownBaseConfig? = null,
@Json(name = "m.identity_server")
var identityServer: WellKnownBaseConfig? = null,
val identityServer: WellKnownBaseConfig? = null,
@Json(name = "m.integrations")
var integrations: Map<String, @JvmSuppressWildcards Any>? = null
val integrations: Map<String, @JvmSuppressWildcards Any>? = null
) {
/**
* Returns the list of integration managers proposed

View File

@@ -16,7 +16,7 @@
package im.vector.matrix.android.api.crypto
import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
import im.vector.matrix.android.api.session.crypto.verification.EmojiRepresentation
import im.vector.matrix.android.internal.crypto.verification.getEmojiForCode
/**

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.crypto
/**
* Class to define the parameters used to customize or configure the end-to-end crypto.
*/
data class MXCryptoConfig(
// Tell whether the encryption of the event content is enabled for the invited members.
// SDK clients can disable this by settings it to false.
// Note that the encryption for the invited members will be blocked if the history visibility is "joined".
var enableEncryptionForInvitedMembers: Boolean = true,
/**
* If set to true, the SDK will automatically ignore room key request (gossiping)
* coming from your other untrusted sessions (or blocked).
* If set to false, the request will be forwarded to the application layer; in this
* case the application can decide to prompt the user.
*/
var discardRoomKeyRequestsFromUntrustedDevices : Boolean = true
)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 New Vector Ltd
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,18 @@
* limitations under the License.
*/
package im.vector.riotx.core.rx
import im.vector.riotx.BuildConfig
import io.reactivex.plugins.RxJavaPlugins
import timber.log.Timber
package im.vector.matrix.android.api.crypto
/**
* Make sure unhandled Rx error does not crash the app in production
* RoomEncryptionTrustLevel represents the trust level in an encrypted room.
*/
fun setupRxPlugin() {
RxJavaPlugins.setErrorHandler { throwable ->
Timber.e(throwable, "RxError")
enum class RoomEncryptionTrustLevel {
// No one in the room has been verified -> Black shield
Default,
// Avoid crash in production
if (BuildConfig.DEBUG) {
throw throwable
}
}
// There are one or more device un-verified -> the app should display a red shield
Warning,
// All devices in the room are verified -> the app should display a green shield
Trusted
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.extensions
fun Boolean?.orTrue() = this ?: true
fun Boolean?.orFalse() = this ?: false

View File

@@ -16,18 +16,21 @@
package im.vector.matrix.android.api.extensions
import im.vector.matrix.android.api.comparators.DatedObjectComparators
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
/* ==========================================================================================
* MXDeviceInfo
* ========================================================================================== */
fun MXDeviceInfo.getFingerprintHumanReadable() = fingerprint()
fun CryptoDeviceInfo.getFingerprintHumanReadable() = fingerprint()
?.chunked(4)
?.joinToString(separator = " ")
fun MutableList<DeviceInfo>.sortByLastSeen() {
sortWith(DatedObjectComparators.descComparator)
/* ==========================================================================================
* DeviceInfo
* ========================================================================================== */
fun List<DeviceInfo>.sortByLastSeen(): List<DeviceInfo> {
return this.sortedByDescending { it.lastSeenTs ?: 0 }
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.extensions
inline fun <A> tryThis(operation: () -> A): A? {
return try {
operation()
} catch (any: Throwable) {
null
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.failure
import javax.net.ssl.HttpsURLConnection
fun Throwable.is401() =
this is Failure.ServerError
&& httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED /* 401 */
&& error.code == MatrixError.M_UNAUTHORIZED
fun Throwable.isTokenError() =
this is Failure.ServerError
&& (error.code == MatrixError.M_UNKNOWN_TOKEN || error.code == MatrixError.M_MISSING_TOKEN)
fun Throwable.shouldBeRetried(): Boolean {
return this is Failure.NetworkConnection
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
}
fun Throwable.isInvalidPassword(): Boolean {
return this is Failure.ServerError
&& error.code == MatrixError.M_FORBIDDEN
&& error.message == "Invalid password"
}

View File

@@ -21,6 +21,7 @@ package im.vector.matrix.android.api.listeners
*/
interface ProgressListener {
/**
* Will be invoked on the background thread, not in UI thread.
* @param progress from 0 to total by contract
* @param total
*/

View File

@@ -17,7 +17,6 @@
package im.vector.matrix.android.api.permalinks
import android.text.Spannable
import im.vector.matrix.android.api.MatrixPatterns
/**
* MatrixLinkify take a piece of text and turns all of the
@@ -30,7 +29,13 @@ object MatrixLinkify {
*
* @param spannable the text in which the matrix items has to be clickable.
*/
@Suppress("UNUSED_PARAMETER")
fun addLinks(spannable: Spannable, callback: MatrixPermalinkSpan.Callback?): Boolean {
/**
* I disable it because it mess up with pills, and even with pills, it does not work correctly:
* The url is not correct. Ex: for @user:matrix.org, the url will be @user:matrix.org, instead of a matrix.to
*/
/*
// sanity checks
if (spannable.isEmpty()) {
return false
@@ -50,5 +55,7 @@ object MatrixLinkify {
}
}
return hasMatch
*/
return false
}
}

View File

@@ -19,7 +19,7 @@ package im.vector.matrix.android.api.permalinks
import im.vector.matrix.android.api.session.events.model.Event
/**
* Useful methods to create Matrix permalink.
* Useful methods to create Matrix permalink (matrix.to links).
*/
object PermalinkFactory {
@@ -84,7 +84,17 @@ object PermalinkFactory {
* @param id the id to escape
* @return the escaped id
*/
private fun escape(id: String): String {
internal fun escape(id: String): String {
return id.replace("/", "%2F")
}
/**
* Unescape '/' in id
*
* @param id the id to escape
* @return the escaped id
*/
internal fun unescape(id: String): String {
return id.replace("%2F", "/")
}
}

View File

@@ -56,23 +56,23 @@ object PermalinkParser {
val identifier = params.getOrNull(0)
val extraParameter = params.getOrNull(1)
if (identifier.isNullOrEmpty()) {
return PermalinkData.FallbackLink(uri)
}
return when {
identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
MatrixPatterns.isRoomId(identifier) -> {
val eventId = extraParameter.takeIf {
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
}
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = false, eventId = eventId)
PermalinkData.RoomLink(
roomIdOrAlias = identifier,
isRoomAlias = false,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
)
}
MatrixPatterns.isRoomAlias(identifier) -> {
val eventId = extraParameter.takeIf {
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
}
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = true, eventId = eventId)
PermalinkData.RoomLink(
roomIdOrAlias = identifier,
isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
)
}
else -> PermalinkData.FallbackLink(uri)
}

View File

@@ -15,30 +15,32 @@
*/
package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.session.events.model.Event
abstract class Condition(val kind: Kind) {
enum class Kind(val value: String) {
event_match("event_match"),
contains_display_name("contains_display_name"),
room_member_count("room_member_count"),
sender_notification_permission("sender_notification_permission"),
UNRECOGNIZE("");
EventMatch("event_match"),
ContainsDisplayName("contains_display_name"),
RoomMemberCount("room_member_count"),
SenderNotificationPermission("sender_notification_permission"),
Unrecognised("");
companion object {
fun fromString(value: String): Kind {
return when (value) {
"event_match" -> event_match
"contains_display_name" -> contains_display_name
"room_member_count" -> room_member_count
"sender_notification_permission" -> sender_notification_permission
else -> UNRECOGNIZE
"event_match" -> EventMatch
"contains_display_name" -> ContainsDisplayName
"room_member_count" -> RoomMemberCount
"sender_notification_permission" -> SenderNotificationPermission
else -> Unrecognised
}
}
}
}
abstract fun isSatisfied(conditionResolver: ConditionResolver): Boolean
abstract fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean
open fun technicalDescription(): String {
return "Kind: $kind"

View File

@@ -15,14 +15,22 @@
*/
package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.session.events.model.Event
/**
* Acts like a visitor on Conditions.
* This class as all required context needed to evaluate rules
*/
interface ConditionResolver {
fun resolveEventMatchCondition(event: Event,
condition: EventMatchCondition): Boolean
fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean
fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean
fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean
fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition) : Boolean
fun resolveRoomMemberCountCondition(event: Event,
condition: RoomMemberCountCondition): Boolean
fun resolveSenderNotificationPermissionCondition(event: Event,
condition: SenderNotificationPermissionCondition): Boolean
fun resolveContainsDisplayNameCondition(event: Event,
condition: ContainsDisplayNameCondition): Boolean
}

View File

@@ -21,10 +21,10 @@ import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import timber.log.Timber
class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) {
class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) {
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveContainsDisplayNameCondition(this)
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveContainsDisplayNameCondition(event, this)
}
override fun technicalDescription(): String {

View File

@@ -19,10 +19,20 @@ import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber
class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind.event_match) {
class EventMatchCondition(
/**
* The dot-separated field of the event to match, e.g. content.body
*/
val key: String,
/**
* The glob-style pattern to match against. Patterns with no special glob characters should
* be treated as having asterisks prepended and appended when testing the condition.
*/
val pattern: String
) : Condition(Kind.EventMatch) {
override fun isSatisfied(conditionResolver: ConditionResolver) : Boolean {
return conditionResolver.resolveEventMatchCondition(this)
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveEventMatchCondition(event, this)
}
override fun technicalDescription(): String {

View File

@@ -17,25 +17,24 @@ package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.api.pushrules.rest.RuleSet
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.util.Cancelable
interface PushRuleService {
/**
* Fetch the push rules from the server
*/
fun fetchPushRules(scope: String = RuleScope.GLOBAL)
// TODO get push rule set
fun getPushRules(scope: String = RuleScope.GLOBAL): List<PushRule>
// TODO update rule
fun getPushRules(scope: String = RuleScope.GLOBAL): RuleSet
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
fun addPushRuleListener(listener: PushRuleListener)

View File

@@ -16,25 +16,32 @@
package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.internal.session.room.RoomGetter
import timber.log.Timber
private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$")
class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) {
class RoomMemberCountCondition(
/**
* A decimal integer optionally prefixed by one of ==, <, >, >= or <=.
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth.
* If no prefix is present, this parameter defaults to ==.
*/
val iz: String
) : Condition(Kind.RoomMemberCount) {
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveRoomMemberCountCondition(this)
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveRoomMemberCountCondition(event, this)
}
override fun technicalDescription(): String {
return "Room member count is $iz"
}
fun isSatisfied(event: Event, session: RoomService?): Boolean {
// sanity check^
internal fun isSatisfied(event: Event, roomGetter: RoomGetter): Boolean {
// sanity checks
val roomId = event.roomId ?: return false
val room = session?.getRoom(roomId) ?: return false
val room = roomGetter.getRoom(roomId) ?: return false
// Parse the is field into prefix and number the first time
val (prefix, count) = parseIsField() ?: return false
@@ -59,7 +66,7 @@ class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_coun
val (prefix, count) = match.destructured
return prefix to count.toInt()
} catch (t: Throwable) {
Timber.d(t)
Timber.e(t, "Unable to parse 'is' field")
}
return null
}

View File

@@ -16,19 +16,29 @@
package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.model.PowerLevels
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) {
class SenderNotificationPermissionCondition(
/**
* A string that determines the power level the sender must have to trigger notifications of a given type,
* such as room. Refer to the m.room.power_levels event schema for information about what the defaults are
* and how to interpret the event. The key is used to look up the power level required to send a notification
* type from the notifications object in the power level event content.
*/
val key: String
) : Condition(Kind.SenderNotificationPermission) {
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveSenderNotificationPermissionCondition(this)
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveSenderNotificationPermissionCondition(event, this)
}
override fun technicalDescription(): String {
return "User power level <$key>"
}
fun isSatisfied(event: Event, powerLevels: PowerLevels): Boolean {
return event.senderId != null && powerLevels.getUserPowerLevel(event.senderId) >= powerLevels.notificationLevel(key)
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
return event.senderId != null && powerLevelsHelper.getUserPowerLevel(event.senderId) >= powerLevelsHelper.notificationLevel(key)
}
}

View File

@@ -20,18 +20,19 @@ import com.squareup.moshi.JsonClass
/**
* All push rulesets for a user.
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
*/
@JsonClass(generateAdapter = true)
data class GetPushRulesResponse(
internal data class GetPushRulesResponse(
/**
* Global rules, account level applying to all devices
*/
@Json(name = "global")
val global: Ruleset,
val global: RuleSet,
/**
* Device specific rules, apply only to current device
*/
@Json(name = "device")
val device: Ruleset? = null
val device: RuleSet? = null
)

View File

@@ -17,60 +17,76 @@ package im.vector.matrix.android.api.pushrules.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.pushrules.*
import im.vector.matrix.android.api.pushrules.Condition
import im.vector.matrix.android.api.pushrules.ContainsDisplayNameCondition
import im.vector.matrix.android.api.pushrules.EventMatchCondition
import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition
import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition
import timber.log.Timber
/**
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
*/
@JsonClass(generateAdapter = true)
data class PushCondition(
/**
* Required. The kind of condition to apply.
*/
@Json(name = "kind")
val kind: String,
/**
* Required for event_match conditions. The dot- separated field of the event to match.
*/
@Json(name = "key")
val key: String? = null,
/**
*Required for event_match conditions.
*/
/**
* Required for event_match conditions.
*/
@Json(name = "pattern")
val pattern: String? = null,
/**
* Required for room_member_count conditions.
* A decimal integer optionally prefixed by one of, ==, <, >, >= or <=.
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth.
* If no prefix is present, this parameter defaults to ==.
*/
@Json(name = "is") val iz: String? = null
@Json(name = "is")
val iz: String? = null
) {
fun asExecutableCondition(): Condition? {
return when (Condition.Kind.fromString(this.kind)) {
Condition.Kind.event_match -> {
if (this.key != null && this.pattern != null) {
return when (Condition.Kind.fromString(kind)) {
Condition.Kind.EventMatch -> {
if (key != null && pattern != null) {
EventMatchCondition(key, pattern)
} else {
Timber.e("Malformed Event match condition")
null
}
}
Condition.Kind.contains_display_name -> {
Condition.Kind.ContainsDisplayName -> {
ContainsDisplayNameCondition()
}
Condition.Kind.room_member_count -> {
if (this.iz.isNullOrBlank()) {
Condition.Kind.RoomMemberCount -> {
if (iz.isNullOrEmpty()) {
Timber.e("Malformed ROOM_MEMBER_COUNT condition")
null
} else {
RoomMemberCountCondition(this.iz)
RoomMemberCountCondition(iz)
}
}
Condition.Kind.sender_notification_permission -> {
this.key?.let { SenderNotificationPermissionCondition(it) }
Condition.Kind.SenderNotificationPermission -> {
if (key == null) {
Timber.e("Malformed Sender Notification Permission condition")
null
} else {
SenderNotificationPermissionCondition(key)
}
}
Condition.Kind.UNRECOGNIZE -> {
Condition.Kind.Unrecognised -> {
Timber.e("Unknown kind $kind")
null
}

View File

@@ -18,31 +18,158 @@ package im.vector.matrix.android.api.pushrules.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.pushrules.Action
import im.vector.matrix.android.api.pushrules.getActions
import im.vector.matrix.android.api.pushrules.toJson
/**
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
*/
@JsonClass(generateAdapter = true)
data class PushRule(
/**
* Required. The actions to perform when this rule is matched.
*/
@Json(name = "actions")
val actions: List<Any>,
/**
* Required. Whether this is a default rule, or has been set explicitly.
*/
@Json(name = "default")
val default: Boolean? = false,
/**
* Required. Whether the push rule is enabled or not.
*/
@Json(name = "enabled")
val enabled: Boolean,
/**
* Required. The ID of this rule.
*/
@Json(name = "rule_id") val ruleId: String,
@Json(name = "rule_id")
val ruleId: String,
/**
* The conditions that must hold true for an event in order for a rule to be applied to an event
*/
@Json(name = "conditions")
val conditions: List<PushCondition>? = null,
/**
* The glob-style pattern to match against. Only applicable to content rules.
*/
@Json(name = "pattern")
val pattern: String? = null
)
) {
/**
* Add the default notification sound.
*/
fun setNotificationSound(): PushRule {
return setNotificationSound(ACTION_VALUE_DEFAULT)
}
fun getNotificationSound(): String? {
return (getActions().firstOrNull { it is Action.Sound } as? Action.Sound)?.sound
}
/**
* Set the notification sound
*
* @param sound notification sound
*/
fun setNotificationSound(sound: String): PushRule {
return copy(
actions = (getActions().filter { it !is Action.Sound } + Action.Sound(sound)).toJson()
)
}
/**
* Remove the notification sound
*/
fun removeNotificationSound(): PushRule {
return copy(
actions = getActions().filter { it !is Action.Sound }.toJson()
)
}
/**
* Set the highlight status.
*
* @param highlight the highlight status
*/
fun setHighlight(highlight: Boolean): PushRule {
return copy(
actions = (getActions().filter { it !is Action.Highlight } + Action.Highlight(highlight)).toJson()
)
}
/**
* Set the notification status.
*
* @param notify true to notify
*/
fun setNotify(notify: Boolean): PushRule {
val mutableActions = actions.toMutableList()
mutableActions.remove(ACTION_DONT_NOTIFY)
mutableActions.remove(ACTION_NOTIFY)
if (notify) {
mutableActions.add(ACTION_NOTIFY)
} else {
mutableActions.add(ACTION_DONT_NOTIFY)
}
return copy(actions = mutableActions)
}
/**
* Return true if the rule should highlight the event.
*
* @return true if the rule should play sound
*/
fun shouldNotify() = actions.contains(ACTION_NOTIFY)
/**
* Return true if the rule should not highlight the event.
*
* @return true if the rule should not play sound
*/
fun shouldNotNotify() = actions.contains(ACTION_DONT_NOTIFY)
companion object {
/* ==========================================================================================
* Rule id
* ========================================================================================== */
const val RULE_ID_DISABLE_ALL = ".m.rule.master"
const val RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name"
const val RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name"
const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"
const val RULE_ID_INVITE_ME = ".m.rule.invite_for_me"
const val RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event"
const val RULE_ID_CALL = ".m.rule.call"
const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices"
const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
const val RULE_ID_AT_ROOMS = ".m.rule.roomnotif"
const val RULE_ID_TOMBSTONE = ".m.rule.tombstone"
const val RULE_ID_E2E_ONE_TO_ONE_ROOM = ".m.rule.encrypted_room_one_to_one"
const val RULE_ID_E2E_GROUP = ".m.rule.encrypted"
const val RULE_ID_REACTION = ".m.rule.reaction"
const val RULE_ID_FALLBACK = ".m.rule.fallback"
/* ==========================================================================================
* Actions
* ========================================================================================== */
const val ACTION_NOTIFY = "notify"
const val ACTION_DONT_NOTIFY = "dont_notify"
const val ACTION_COALESCE = "coalesce"
const val ACTION_SET_TWEAK_SOUND_VALUE = "sound"
const val ACTION_SET_TWEAK_HIGHLIGHT_VALUE = "highlight"
const val ACTION_PARAMETER_SET_TWEAK = "set_tweak"
const val ACTION_PARAMETER_VALUE = "value"
const val ACTION_VALUE_DEFAULT = "default"
const val ACTION_VALUE_RING = "ring"
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.pushrules.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.pushrules.RuleSetKey
/**
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
*/
@JsonClass(generateAdapter = true)
data class RuleSet(
@Json(name = "content")
val content: List<PushRule>? = null,
@Json(name = "override")
val override: List<PushRule>? = null,
@Json(name = "room")
val room: List<PushRule>? = null,
@Json(name = "sender")
val sender: List<PushRule>? = null,
@Json(name = "underride")
val underride: List<PushRule>? = null
) {
fun getAllRules(): List<PushRule> {
// Ref. for the order: https://matrix.org/docs/spec/client_server/latest#push-rules
return override.orEmpty() + content.orEmpty() + room.orEmpty() + sender.orEmpty() + underride.orEmpty()
}
/**
* Find a rule from its ruleID.
*
* @param ruleId a RULE_ID_XX value
* @return the matched bing rule or null it doesn't exist.
*/
fun findDefaultRule(ruleId: String?): PushRuleAndKind? {
var result: PushRuleAndKind? = null
// sanity check
if (null != ruleId) {
if (PushRule.RULE_ID_CONTAIN_USER_NAME == ruleId) {
result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) }
} else {
// assume that the ruleId is unique.
result = findRule(override, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.OVERRIDE) }
if (null == result) {
result = findRule(underride, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.UNDERRIDE) }
}
}
}
return result
}
/**
* Find a rule from its rule Id.
*
* @param rules the rules list.
* @param ruleId the rule Id.
* @return the bing rule if it exists, else null.
*/
private fun findRule(rules: List<PushRule>?, ruleId: String): PushRule? {
return rules?.firstOrNull { it.ruleId == ruleId }
}
}
data class PushRuleAndKind(
val pushRule: PushRule,
val kind: RuleSetKey
)

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.query
/**
* Basic query language. All these cases are mutually exclusive.
*/
sealed class QueryStringValue {
object NoCondition : QueryStringValue()
object IsNull : QueryStringValue()
object IsNotNull : QueryStringValue()
object IsEmpty : QueryStringValue()
object IsNotEmpty : QueryStringValue()
data class Equals(val string: String, val case: Case) : QueryStringValue()
data class Contains(val string: String, val case: Case) : QueryStringValue()
enum class Case {
SENSITIVE,
INSENSITIVE
}
}

View File

@@ -21,6 +21,8 @@ import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.failure.GlobalError
import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.session.account.AccountService
import im.vector.matrix.android.api.session.accountdata.AccountDataService
import im.vector.matrix.android.api.session.cache.CacheService
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
import im.vector.matrix.android.api.session.content.ContentUrlResolver
@@ -28,10 +30,12 @@ import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.file.FileService
import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService
import im.vector.matrix.android.api.session.profile.ProfileService
import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.api.session.room.RoomDirectoryService
import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService
import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState
@@ -46,16 +50,18 @@ interface Session :
RoomDirectoryService,
GroupService,
UserService,
CryptoService,
CacheService,
SignOutService,
FilterService,
FileService,
ProfileService,
PushRuleService,
PushersService,
InitialSyncProgressService,
HomeServerCapabilitiesService,
SecureStorageService {
SecureStorageService,
AccountDataService,
AccountService {
/**
* The params associated to the session
@@ -73,6 +79,11 @@ interface Session :
val myUserId: String
get() = sessionParams.credentials.userId
/**
* The sessionId
*/
val sessionId: String
/**
* This method allow to open a session. It does start some service on the background.
*/
@@ -107,7 +118,12 @@ interface Session :
* This method allows to listen the sync state.
* @return a [LiveData] of [SyncState].
*/
fun syncState(): LiveData<SyncState>
fun getSyncStateLive(): LiveData<SyncState>
/**
* This methods return true if an initial sync has been processed
*/
fun hasAlreadySynced(): Boolean
/**
* This method allow to close a session. It does stop some services.
@@ -124,6 +140,11 @@ interface Session :
*/
fun contentUploadProgressTracker(): ContentUploadStateTracker
/**
* Returns the cryptoService associated with the session
*/
fun cryptoService(): CryptoService
/**
* Add a listener to the session.
* @param listener the listener to add.
@@ -147,4 +168,6 @@ interface Session :
*/
fun onGlobalError(globalError: GlobalError)
}
val sharedSecretStorageService: SharedSecretStorageService
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.account
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Cancelable
/**
* This interface defines methods to manage the account. It's implemented at the session level.
*/
interface AccountService {
/**
* Ask the homeserver to change the password.
* @param password Current password.
* @param newPassword New password
*/
fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.account.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
/**
* Class to pass request parameters to update the password.
*/
@JsonClass(generateAdapter = true)
internal data class ChangePasswordParams(
@Json(name = "auth")
val auth: UserPasswordAuth? = null,
@Json(name = "new_password")
val newPassword: String? = null
) {
companion object {
fun create(userId: String, oldPassword: String, newPassword: String): ChangePasswordParams {
return ChangePasswordParams(
auth = UserPasswordAuth(user = userId, password = oldPassword),
newPassword = newPassword
)
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.accountdata
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
import kotlinx.coroutines.flow.Flow
interface AccountDataService {
/**
* Retrieve the account data with the provided type or null if not found
*/
fun getAccountDataEvent(type: String): UserAccountDataEvent?
/**
* Observe the account data with the provided type
*/
fun getLiveAccountDataEvent(type: String): Flow<Optional<UserAccountDataEvent>>
/**
* Retrieve the account data with the provided types. The return list can have a different size that
* the size of the types set, because some AccountData may not exist.
* If an empty set is provided, all the AccountData are retrieved
*/
fun getAccountDataEvents(types: Set<String>): List<UserAccountDataEvent>
/**
* Observe the account data with the provided types. If an empty set is provided, all the AccountData are observed
*/
fun getLiveAccountDataEvents(types: Set<String>): Flow<List<UserAccountDataEvent>>
/**
* Update the account data with the provided type and the provided account data content
*/
fun updateAccountData(type: String, content: Content, callback: MatrixCallback<Unit>? = null): Cancelable
}

View File

@@ -24,7 +24,7 @@ import im.vector.matrix.android.api.MatrixCallback
interface CacheService {
/**
* Clear the whole cached data, except credentials. Once done, the session is closed and has to be opened again
* Clear the whole cached data, except credentials. Once done, the sync has to be restarted by the sdk user.
*/
fun clearCache(callback: MatrixCallback<Unit>)
}

View File

@@ -16,6 +16,7 @@
package im.vector.matrix.android.api.session.content
import android.net.Uri
import android.os.Parcelable
import androidx.exifinterface.media.ExifInterface
import kotlinx.android.parcel.Parcelize
@@ -29,8 +30,8 @@ data class ContentAttachmentData(
val width: Long? = 0,
val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED,
val name: String? = null,
val path: String,
val mimeType: String?,
val queryUri: Uri,
private val mimeType: String?,
val type: Type
) : Parcelable {
@@ -40,4 +41,6 @@ data class ContentAttachmentData(
AUDIO,
VIDEO
}
fun getSafeMimeType() = if (mimeType == "image/jpg") "image/jpeg" else mimeType
}

View File

@@ -26,6 +26,11 @@ interface ContentUrlResolver {
SCALE("scale")
}
/**
* URL to use to upload content
*/
val uploadUrl: String
/**
* Get the actual URL for accessing the full-size image of a Matrix media content URI.
*

View File

@@ -17,24 +17,37 @@
package im.vector.matrix.android.api.session.crypto
import android.content.Context
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
interface CryptoService {
fun verificationService(): VerificationService
fun crossSigningService(): CrossSigningService
fun keysBackupService(): KeysBackupService
fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>)
fun deleteDevice(deviceId: String, callback: MatrixCallback<Unit>)
@@ -45,23 +58,19 @@ interface CryptoService {
fun isCryptoEnabled(): Boolean
fun getSasVerificationService(): SasVerificationService
fun getKeysBackupService(): KeysBackupService
fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean
fun setWarnOnUnknownDevices(warn: Boolean)
fun setDeviceVerification(verificationStatus: Int, deviceId: String, userId: String)
fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String)
fun getUserDevices(userId: String): MutableList<MXDeviceInfo>
fun getUserDevices(userId: String): MutableList<CryptoDeviceInfo>
fun setDevicesKnown(devices: List<MXDeviceInfo>, callback: MatrixCallback<Unit>?)
fun deviceWithIdentityKey(senderKey: String, algorithm: String): MXDeviceInfo?
fun deviceWithIdentityKey(senderKey: String, algorithm: String): CryptoDeviceInfo?
fun getMyDevice(): MXDeviceInfo
fun getMyDevice(): CryptoDeviceInfo
fun getGlobalBlacklistUnverifiedDevices(): Boolean
@@ -77,18 +86,22 @@ interface CryptoService {
fun setRoomBlacklistUnverifiedDevices(roomId: String)
fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo?
fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo?
fun requestRoomKeyForEvent(event: Event)
fun reRequestRoomKeyForEvent(event: Event)
fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody)
fun addRoomKeysRequestListener(listener: RoomKeysRequestListener)
fun addRoomKeysRequestListener(listener: GossipingRequestListener)
fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener)
fun removeRoomKeysRequestListener(listener: GossipingRequestListener)
fun getDevicesList(callback: MatrixCallback<DevicesListResponse>)
fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>)
fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int
fun isRoomEncrypted(roomId: String): Boolean
@@ -107,9 +120,21 @@ interface CryptoService {
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
fun downloadKeys(userIds: List<String>, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>)
fun downloadKeys(userIds: List<String>, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<CryptoDeviceInfo>>)
fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo>
fun getLiveCryptoDeviceInfo(): LiveData<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(userId: String): LiveData<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>>
fun addNewSessionListener(newSessionListener: NewSessionListener)
fun removeSessionListener(listener: NewSessionListener)
fun getOutgoingRoomKeyRequest(): List<OutgoingRoomKeyRequest>
fun getIncomingRoomKeyRequest(): List<IncomingRoomKeyRequest>
fun getGossipingEventsTrail(): List<Event>
}

View File

@@ -18,7 +18,7 @@
package im.vector.matrix.android.api.session.crypto
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import org.matrix.olm.OlmException
@@ -36,7 +36,7 @@ sealed class MXCryptoError : Throwable() {
data class OlmError(val olmException: OlmException) : MXCryptoError()
data class UnknownDevice(val deviceList: MXUsersDevicesMap<MXDeviceInfo>) : MXCryptoError()
data class UnknownDevice(val deviceList: MXUsersDevicesMap<CryptoDeviceInfo>) : MXCryptoError()
enum class ErrorType {
ENCRYPTING_NOT_ENABLED,

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.crosssigning
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustResult
import im.vector.matrix.android.internal.crypto.crosssigning.UserTrustResult
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
import im.vector.matrix.android.internal.crypto.store.PrivateKeysInfo
interface CrossSigningService {
fun isCrossSigningVerified(): Boolean
fun isUserTrusted(otherUserId: String): Boolean
/**
* Will not force a download of the key, but will verify signatures trust chain.
* Checks that my trusted user key has signed the other user UserKey
*/
fun checkUserTrust(otherUserId: String): UserTrustResult
/**
* Initialize cross signing for this user.
* Users needs to enter credentials
*/
fun initializeCrossSigning(authParams: UserPasswordAuth?,
callback: MatrixCallback<Unit>? = null)
fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?,
uskKeyPrivateKey: String?,
sskPrivateKey: String?) : UserTrustResult
fun getUserCrossSigningKeys(otherUserId: String): MXCrossSigningInfo?
fun getLiveCrossSigningKeys(userId: String): LiveData<Optional<MXCrossSigningInfo>>
fun getMyCrossSigningKeys(): MXCrossSigningInfo?
fun getCrossSigningPrivateKeys(): PrivateKeysInfo?
fun canCrossSign(): Boolean
fun trustUser(otherUserId: String,
callback: MatrixCallback<Unit>)
fun markMyMasterKeyAsTrusted()
/**
* Sign one of your devices and upload the signature
*/
fun trustDevice(deviceId: String,
callback: MatrixCallback<Unit>)
fun checkDeviceTrust(otherUserId: String,
otherDeviceId: String,
locallyTrusted: Boolean?): DeviceTrustResult
fun onSecretSSKGossip(sskPrivateKey: String)
fun onSecretUSKGossip(uskPrivateKey: String)
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.crosssigning
const val MASTER_KEY_SSSS_NAME = "m.cross_signing.master"
const val USER_SIGNING_KEY_SSSS_NAME = "m.cross_signing.user_signing"
const val SELF_SIGNING_KEY_SSSS_NAME = "m.cross_signing.self_signing"
const val KEYBACKUP_SECRET_SSSS_NAME = "m.megolm_backup.v1"

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.crosssigning
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
import im.vector.matrix.android.internal.crypto.model.KeyUsage
data class MXCrossSigningInfo(
val userId: String,
val crossSigningKeys: List<CryptoCrossSigningKey>
) {
fun isTrusted(): Boolean = masterKey()?.trustLevel?.isVerified() == true
&& selfSigningKey()?.trustLevel?.isVerified() == true
fun masterKey(): CryptoCrossSigningKey? = crossSigningKeys
.firstOrNull { it.usages?.contains(KeyUsage.MASTER.value) == true }
fun userKey(): CryptoCrossSigningKey? = crossSigningKeys
.firstOrNull { it.usages?.contains(KeyUsage.USER_SIGNING.value) == true }
fun selfSigningKey(): CryptoCrossSigningKey? = crossSigningKeys
.firstOrNull { it.usages?.contains(KeyUsage.SELF_SIGNING.value) == true }
}

View File

@@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCre
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo
interface KeysBackupService {
/**
@@ -172,6 +173,8 @@ interface KeysBackupService {
password: String,
callback: MatrixCallback<Unit>)
fun onSecretKeyGossip(secret: String)
/**
* Restore a backup with a recovery key from a given backup version stored on the homeserver.
*
@@ -210,4 +213,10 @@ interface KeysBackupService {
val isEnabled: Boolean
val isStucked: Boolean
val state: KeysBackupState
// For gossiping
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
fun getKeyBackupRecoveryKeyInfo() : SavedKeyBackupKeyInfo?
fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String, callback: MatrixCallback<Boolean>)
}

View File

@@ -17,12 +17,13 @@
package im.vector.matrix.android.api.session.crypto.keyshare
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
/**
* Room keys events listener
*/
interface RoomKeysRequestListener {
interface GossipingRequestListener {
/**
* An room key request has been received.
*
@@ -30,10 +31,16 @@ interface RoomKeysRequestListener {
*/
fun onRoomKeyRequest(request: IncomingRoomKeyRequest)
/**
* Returns the secret value to be shared
* @return true if is handled
*/
fun onSecretShareRequest(request: IncomingSecretShareRequest) : Boolean
/**
* A room key request cancellation has been received.
*
* @param request the cancellation request
*/
fun onRoomKeyRequestCancellation(request: IncomingRoomKeyRequestCancellation)
fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation)
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.sas
interface SasVerificationService {
fun addListener(listener: SasVerificationListener)
fun removeListener(listener: SasVerificationListener)
fun markedLocallyAsManuallyVerified(userId: String, deviceID: String)
fun getExistingTransaction(otherUser: String, tid: String): SasVerificationTransaction?
fun beginKeyVerificationSAS(userId: String, deviceID: String): String?
fun beginKeyVerification(method: String, userId: String, deviceID: String): String?
// fun transactionUpdated(tx: SasVerificationTransaction)
interface SasVerificationListener {
fun transactionCreated(tx: SasVerificationTransaction)
fun transactionUpdated(tx: SasVerificationTransaction)
fun markedAsManuallyVerified(userId: String, deviceId: String)
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.sas
enum class SasVerificationTxState {
None,
// I have started a verification request
SendingStart,
Started,
// Other user/device sent me a request
OnStarted,
// I have accepted a request started by the other user/device
SendingAccept,
Accepted,
// My request has been accepted by the other user/device
OnAccepted,
// I have sent my public key
SendingKey,
KeySent,
// The other user/device has sent me his public key
OnKeyReceived,
// Short code is ready to be displayed
ShortCodeReady,
// I have compared the code and manually said that they match
ShortCodeAccepted,
SendingMac,
MacSent,
Verifying,
Verified,
// Global: The verification has been cancelled (by me or other), see cancelReason for details
Cancelled,
OnCancelled
}

View File

@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.sas
package im.vector.matrix.android.api.session.crypto.verification
enum class CancelCode(val value: String, val humanReadable: String) {
User("m.user", "the user cancelled the verification"),
@@ -25,7 +26,9 @@ enum class CancelCode(val value: String, val humanReadable: String) {
UnexpectedMessage("m.unexpected_message", "the device received an unexpected message"),
InvalidMessage("m.invalid_message", "an invalid message was received"),
MismatchedKeys("m.key_mismatch", "Key mismatch"),
UserMismatchError("m.user_error", "User mismatch")
UserError("m.user_error", "User error"),
MismatchedUser("m.user_mismatch", "User mismatch"),
QrCodeInvalid("m.qr_code.invalid", "Invalid QR code")
}
fun safeValueOf(code: String?): CancelCode {

View File

@@ -14,9 +14,12 @@
* limitations under the License.
*/
package im.vector.matrix.android.api.session.crypto.sas
package im.vector.matrix.android.api.session.crypto.verification
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
data class EmojiRepresentation(val emoji: String,
@StringRes val nameResId: Int)
@StringRes val nameResId: Int,
@DrawableRes val drawableRes: Int? = null
)

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