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

Compare commits

...

298 Commits

Author SHA1 Message Date
Benoit Marty
dffdcfe1e4 Merge branch 'release/1.0.11' 2020-11-27 20:40:03 +01:00
Benoit Marty
7b969ebd74 Ensure the Activity is destroyed, it seems that the intent flags are not enough now. - finish all 2020-11-27 16:00:30 +01:00
Benoit Marty
163f4cfaf2 Ensure the Activity is destroyed, it seems that the intent flags are not enough now. 2020-11-27 15:15:56 +01:00
Benoit Marty
9a8f45fc6f Prepare version 1.0.11 2020-11-27 13:59:23 +01:00
Benoit Marty
e3ca89a81b Fix issue when there is no display name 2020-11-27 13:54:21 +01:00
Benoit Marty
8696650f20 Cleanup 2020-11-27 13:53:19 +01:00
Benoit Marty
942f050579 Merge pull request #2450 from vector-im/feature/bca/home_empty_screens
Home empty screen design update
2020-11-27 13:51:04 +01:00
Benoit Marty
32d42794dd Merge branch 'develop' into feature/bca/home_empty_screens 2020-11-27 12:02:30 +01:00
Benoit Marty
14c71d6c07 Fix issue with too big icons 2020-11-27 12:01:19 +01:00
Benoit Marty
cce4d7d4d9 Use style instead of duplicating the whole layout file 2020-11-27 11:09:13 +01:00
Benoit Marty
708cdad38b Update changelog 2020-11-27 10:24:07 +01:00
Benoit Marty
bc889cbcf4 Merge pull request #2444 from vector-im/feature/bca/deeplink_mxto
Fix issues with matrix.to deep linking
2020-11-27 10:22:51 +01:00
Valere
7c9b943733 Try other asset strategy as lint not happy 2020-11-27 09:58:14 +01:00
Benoit Marty
e3b88d1162 Merge pull request #2461 from RiotTranslateBot/weblate-element-android-element-app
Translations update from Weblate
2020-11-27 09:45:22 +01:00
Weblate
d80927a8f9 Merge branch 'origin/develop' into Weblate. 2020-11-27 07:37:32 +00:00
Valere
835a36986d Refactoring following review 2020-11-26 17:39:00 +01:00
Valere
4c599d3d40 Merge pull request #2451 from vector-im/feature/bca/fix_update_profile_no_rooms
Fix / update profile when no rooms
2020-11-26 15:09:40 +01:00
Valere
67057bfac4 Merge pull request #2417 from vector-im/feature/bca/quick_invite_dm_tab
Feature/bca/quick invite dm tab
2020-11-26 14:58:14 +01:00
Valere
fbc3f47eeb Fix / update profile when no rooms 2020-11-26 14:34:45 +01:00
Valere
79caa4e510 update change log 2020-11-26 13:31:00 +01:00
Valere
fa191136cc Home empty screen design update 2020-11-26 13:27:10 +01:00
Daniel Løvbrøtte Olsen
15d93c8aeb Translated using Weblate (Norwegian Bokmål)
Currently translated at 43.3% (837 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/
2020-11-26 11:50:02 +00:00
Valere
4f5632b916 code review 2020-11-26 09:09:27 +01:00
Valere
8e6e6736a3 Code review 2020-11-26 09:09:27 +01:00
Valere
804afc9a1d Fix issues with matrix.to deep linking 2020-11-26 09:09:27 +01:00
Valere
bcd86977d2 Fix test + lint 2020-11-25 17:17:48 +01:00
Valere
a8b5a5227f Code review update 2020-11-25 15:47:27 +01:00
notramo
d2398a7abb Translated using Weblate (Hungarian)
Currently translated at 83.1% (158 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/hu/
2020-11-25 08:50:03 +00:00
Daniel Løvbrøtte Olsen
0e908ad882 Translated using Weblate (Norwegian Bokmål)
Currently translated at 43.1% (834 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/
2020-11-25 08:50:02 +00:00
Benoit Marty
c0a83d1916 Merge pull request #2429 from vector-im/feature/bca/e2e_logs
Better e2e log reporting
2020-11-24 17:04:11 +01:00
Benoit Marty
920856512e Merge pull request #2433 from EdGeraghty/patch-1
Disable native dialler integration on jitsi widget
2020-11-24 16:45:12 +01:00
Daniel Løvbrøtte Olsen
62b703ca88 Added translation using Weblate (Norwegian Bokmål) 2020-11-24 07:08:01 +00:00
Ed Geraghty
b125b47366 Update CHANGES.md
Signed-off-by: Ed Geraghty <ed@geraghty.london>
2020-11-23 00:01:05 +00:00
Ed Geraghty
bc6debea89 Disable native dialler integration on jitsi widget
Native dialler integration breaks the jitsi widget for those of us with non-vanilla telephony frameworks.

Disabling this integration (as is default on the Jitsi Meet Android app) allows us to also join conference calls, with no adverse effect on those for whom it already works.

Signed-off-by: Ed Geraghty <ed@geraghty.london>
2020-11-22 23:13:01 +00:00
keraint
d5523b18b9 Translated using Weblate (French)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-21 08:49:59 +00:00
Valere
1f69c7e992 Better e2e log reporting 2020-11-20 17:37:20 +01:00
Valere
d9757cc660 Fix lint 2020-11-20 16:23:04 +01:00
Valere
1cb3522e73 Fix string 2020-11-20 15:46:21 +01:00
Valere
7583b0a358 Fix rebase 2020-11-20 15:17:35 +01:00
Valere
77863e2e88 copy tweaks 2020-11-20 14:50:21 +01:00
Valere
564404d4ae Design review 2020-11-20 14:50:21 +01:00
Valere
e2320cd3b2 Upgrade to new design input 2020-11-20 14:50:21 +01:00
Valere
fd92d6559c Refact move utility method open settings 2020-11-20 14:50:21 +01:00
Valere
6146925757 Better error handling Rx call 2020-11-20 14:50:21 +01:00
Valere
baef9f5aa7 Fix permission handling + share my code by text 2020-11-20 14:50:21 +01:00
Benoit Marty
ae6de8fdf1 Small cleanup 2020-11-20 14:50:21 +01:00
Benoit Marty
b888d13e62 Use orEmpty() 2020-11-20 14:50:21 +01:00
Benoit Marty
1070c23608 QR code invite flow support - invite friends
Author: Valere
2020-11-20 14:50:21 +01:00
TR-SLimey
e8d084b855 Add ability to share profile by QR code 2020-11-20 14:49:39 +01:00
Benoit Marty
5b278f704c Merge pull request #2427 from vector-im/feature/bma/dominaezz_cleanup
Feature/bma/dominaezz cleanup
2020-11-20 14:11:53 +01:00
Benoit Marty
a87e44bae4 Merge pull request #2416 from vector-im/feature/bma_create_room_form
Improve create room form
2020-11-20 13:57:46 +01:00
Benoit Marty
85bc5f54aa Merge branch 'develop' into feature/bma_create_room_form 2020-11-20 13:57:35 +01:00
Benoit Marty
41f46d0810 Merge pull request #2367 from vector-im/feature/bma/sanity_test
Feature/bma/sanity test
2020-11-20 13:56:49 +01:00
Benoit Marty
9ce1222fd0 Kotlin optimization form #1435 2020-11-20 09:07:29 +01:00
Benoit Marty
8fb3c68573 Kotlin optimization form #1435 2020-11-20 09:05:53 +01:00
Benoit Marty
eb7ee49096 Kotlin optimization form #1435 2020-11-20 09:04:04 +01:00
Benoit Marty
084b2e8e04 Merge pull request #2373 from vector-im/feature/bma/fix_crash
Feature/bma/fix crash
2020-11-19 18:44:58 +01:00
Benoit Marty
675e4579ac Merge branch 'develop' into feature/bma/fix_crash 2020-11-19 18:44:17 +01:00
Benoit Marty
d2880432da Merge pull request #2366 from vector-im/feature/bma/cleanup
Feature/bma/cleanup
2020-11-19 17:49:17 +01:00
Benoit Marty
6daae83c3a Merge pull request #2383 from vector-im/feature/bma/crop_issue
Try to fix cropped image in timeline (#2126)
2020-11-19 17:29:49 +01:00
Benoit Marty
f9e4b689b7 Merge branch 'develop' into feature/bma/crop_issue 2020-11-19 17:25:36 +01:00
Benoit Marty
2c30050f3d Merge pull request #2384 from vector-im/feature/bma/upgrade
Un configure the template, to be able to upgrade Android Studio
2020-11-19 17:18:08 +01:00
Benoit Marty
13530abdeb Merge pull request #2372 from vector-im/feature/fix_user_vs_room_member
Feature/fix user vs room member
2020-11-19 17:15:42 +01:00
Benoit Marty
5eb50750e2 Merge branch 'develop' into feature/fix_user_vs_room_member 2020-11-19 17:02:35 +01:00
Benoit Marty
9ef873526a Merge pull request #2371 from vector-im/feature/ons/fix_badge_color
Exclude yourself when decorating rooms which are direct or <=2 members.
2020-11-19 17:01:20 +01:00
Benoit Marty
0046fe25c5 Merge branch 'develop' into feature/ons/fix_badge_color 2020-11-19 17:00:49 +01:00
Benoit Marty
fdb13f0b77 Merge pull request #2385 from vector-im/feature/bma/fdroid_60_timeout
F-Droid version: ensure timeout of sync request can be more than 60 s…
2020-11-19 16:59:40 +01:00
Besnik Bleta
029d8574f1 Translated using Weblate (Albanian)
Currently translated at 99.4% (1923 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/sq/
2020-11-19 15:49:59 +00:00
Benoit Marty
a552c57d67 Merge pull request #2409 from vector-im/gradlew-update-6.7.1
Updates Gradle Wrapper from 6.7 to 6.7.1
2020-11-19 15:32:22 +01:00
Benoit Marty
d5f83acaf5 Merge pull request #2414 from Dominaezzz/suspend_functions_2
Convert PushRuleService to suspend functions
2020-11-19 15:32:01 +01:00
Benoit Marty
c50c028c9e Code quality 2020-11-19 15:22:24 +01:00
Benoit Marty
465b33b006 Merge pull request #2407 from vector-im/feature/bma/move_enable_encryption
Move "Enable Encryption" from room setting screen to room profile screen
2020-11-19 15:17:13 +01:00
Benoit Marty
4df68479ac Merge pull request #2369 from vector-im/feature/bca/quick_invite_room_tile
EmptyRoom tile with quick actions
2020-11-19 09:46:25 +01:00
Benoit Marty
3ec25f3634 Merge pull request #2413 from Dominaezzz/suspend_functions
Convert Group to suspend functions
2020-11-19 02:05:06 +01:00
Benoit Marty
c29e4648ea Small cleanup 2020-11-18 18:13:49 +01:00
Benoit Marty
9ed8f26d7c Make the room default avatar clickable to set it (as per the small picto)
And do some cleanup
2020-11-18 18:13:49 +01:00
Benoit Marty
b82b378cfe Cleanup and changelog 2020-11-18 18:13:49 +01:00
Benoit Marty
1eac90e5b1 Use plurals for proper i18n 2020-11-18 18:13:49 +01:00
Valere
206e68b1d2 Unused val 2020-11-18 18:13:49 +01:00
Valere
1de5cd2e61 Code review 2020-11-18 18:13:49 +01:00
Valere
264bc52bcc WIP review 2020-11-18 18:13:49 +01:00
Valere
2626a761ea EmptyRoom tile with quick actions 2020-11-18 18:13:49 +01:00
Dominic Fischer
1359c6be1d Missed a spot
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 15:40:22 +00:00
Benoit Marty
ca0da2c509 Merge pull request #2405 from Dominaezzz/suspend_functions_1
Convert DraftService to suspend functions
2020-11-18 16:00:33 +01:00
Benoit Marty
57d55e05e7 Update comment 2020-11-18 15:36:05 +01:00
Benoit Marty
702d21fbc3 No encryption for public room (#1314) 2020-11-18 15:27:59 +01:00
Dominic Fischer
796ba72bde Reorder
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 14:27:46 +00:00
Dominic Fischer
92a6e9ea5a Remove redundant return
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 14:23:59 +00:00
Dominic Fischer
822ce41b54 Remove redundant return
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 14:22:07 +00:00
Benoit Marty
0c7f4c2af5 Reset error in the form 2020-11-18 15:13:43 +01:00
Benoit Marty
4e1783f856 Merge pull request #2415 from Dominaezzz/suspend_functions_3
Convert SearchService to suspend functions
2020-11-18 15:08:38 +01:00
Benoit Marty
f6aee3d64e Cleanup 2020-11-18 14:54:01 +01:00
Benoit Marty
514263ae12 Room creation Fragment: no more "Retry" action, loading and error displayed in a dialog 2020-11-18 14:51:10 +01:00
Benoit Marty
507d5d3758 Warn the user if room alias is not empty and he wants to leave the form. 2020-11-18 14:21:53 +01:00
Benoit Marty
16b6678aa2 CreateRoomFragment: use argument instead of Activity ViewModel to pass the initial room name 2020-11-18 14:14:43 +01:00
Benoit Marty
af8b400bf4 Room creation form: input an alias for public room (#1314) 2020-11-18 13:44:55 +01:00
Dominic Fischer
a32d7f78bb Convert SearchService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 12:23:40 +00:00
Dominic Fischer
94b135ae95 Convert PushRuleService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 12:19:58 +00:00
Dominic Fischer
e42cad68b4 Convert Group to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-18 12:16:53 +00:00
Rintan
8a44ee9d50 Translated using Weblate (Japanese)
Currently translated at 42.6% (81 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/ja/
2020-11-18 09:50:01 +00:00
Rintan
5bf4fffd2f Translated using Weblate (Japanese)
Currently translated at 50.5% (978 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ja/
2020-11-18 09:50:01 +00:00
Dominic Fischer
82b21e6a09 Ensure draft is saved with NonCancellable
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-17 10:53:57 +00:00
gradle-update-robot
9216eed1b8 Update Gradle Wrapper from 6.7 to 6.7.1.
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2020-11-17 00:40:54 +00:00
Victor Cuadrado Juan
c81c5c4801 Translated using Weblate (Spanish)
Currently translated at 100.0% (4 of 4 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/es/
2020-11-16 23:50:03 +00:00
Victor Cuadrado Juan
14bf0038a9 Translated using Weblate (Spanish)
Currently translated at 100.0% (190 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/es/
2020-11-16 23:50:03 +00:00
AlexanderLevchenkoTechs
a8f2fd3f4b Translated using Weblate (Ukrainian)
Currently translated at 43.6% (844 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/uk/
2020-11-16 23:50:02 +00:00
Rob Johnson
7223959fda Translated using Weblate (Spanish)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/es/
2020-11-16 23:50:01 +00:00
Victor Cuadrado Juan
cf5d112e31 Translated using Weblate (Spanish)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/es/
2020-11-16 23:50:01 +00:00
Pol Gómez Riquelme
b24608891e Translated using Weblate (Catalan)
Currently translated at 60.5% (1171 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/
2020-11-16 23:49:58 +00:00
Benoit Marty
579efb016a Room creation form: add advanced section to disable federation (#1314) 2020-11-16 18:02:18 +01:00
Benoit Marty
2b1b9d35a2 Merge pull request #2406 from Dominaezzz/suspend_functions
Convert RawService to suspend functions
2020-11-16 15:47:50 +01:00
Dominic Fischer
3d970737d1 Remove redundant return
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-16 14:45:42 +00:00
Benoit Marty
75c105a400 Move "Enable Encryption" from room setting screen to room profile screen (#2394) 2020-11-16 15:08:10 +01:00
Dominic Fischer
0a318f618b Convert RawService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-16 13:48:19 +00:00
Dominic Fischer
574d5055bd Convert DraftService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-16 13:46:24 +00:00
Benoit Marty
0022777a4f Merge pull request #2377 from vector-im/feature/bma/consent
Feature/bma/consent
2020-11-16 13:43:30 +01:00
Benoit Marty
4c6996bc09 Merge branch 'develop' into feature/bma/consent 2020-11-16 13:43:02 +01:00
Benoit Marty
6ff12b3a88 Merge pull request #2402 from Dominaezzz/suspend_functions_1
Convert ReportingService to suspend functions
2020-11-16 13:39:47 +01:00
Benoit Marty
babbb82a49 Merge pull request #2401 from Dominaezzz/suspend_functions
Convert TagsService to suspend functions
2020-11-16 13:38:22 +01:00
Benoit Marty
ae5331cf40 Merge pull request #2397 from vector-im/feature/bma/registration_email
Registration: annoying error message scares every new user when they add an email (#2391)
2020-11-16 13:36:45 +01:00
Dominic Fischer
d67029c42c Convert ReportingService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-16 11:47:18 +00:00
Dominic Fischer
4dff9316c2 Convert TagsService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-16 11:44:30 +00:00
Benoit Marty
a056cbd19f Registration: annoying error message scares every new user when they add an email (#2391) 2020-11-16 10:57:29 +01:00
Danial Behzadi
032d46d8e6 Translated using Weblate (Persian)
Currently translated at 100.0% (190 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/fa/
2020-11-14 16:50:02 +00:00
sr093906
b739aa35f2 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.1% (1917 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hans/
2020-11-14 16:50:02 +00:00
LinAGKar
fa3035f9cf Translated using Weblate (Swedish)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/sv/
2020-11-14 16:50:01 +00:00
notramo
daf1362d28 Translated using Weblate (Hungarian)
Currently translated at 94.9% (1835 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/
2020-11-14 16:50:01 +00:00
XoseM
8e7d5ddfd4 Translated using Weblate (Galician)
Currently translated at 27.3% (529 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/gl/
2020-11-14 16:50:01 +00:00
François FERREIRA DE SOUSA
71a70ffafa Translated using Weblate (French)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-14 16:50:00 +00:00
Danial Behzadi
d9ceb32e2f Translated using Weblate (Persian)
Currently translated at 98.4% (1904 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/
2020-11-14 16:50:00 +00:00
Victor Cuadrado Juan
13f716a395 Translated using Weblate (Spanish)
Currently translated at 97.3% (1881 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/es/
2020-11-14 16:50:00 +00:00
Nils Büchner
b9375a1b4e Translated using Weblate (German)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/de/
2020-11-14 16:49:58 +00:00
Auri B. P
38a98a51cb Translated using Weblate (Catalan)
Currently translated at 60.5% (1170 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/
2020-11-14 16:49:57 +00:00
Benoit Marty
64c612dea0 F-Droid version: ensure timeout of sync request can be more than 60 seconds (#2169) 2020-11-13 19:14:50 +01:00
Benoit Marty
f2e8a9e0c7 Un configure the template, to be able to upgrade Android Studio 2020-11-13 18:25:25 +01:00
Benoit Marty
8ae0501c22 Try to fix cropped image in timeline (#2126) 2020-11-13 17:52:02 +01:00
Benoit Marty
8dff0b2c5d Cleanup 2020-11-13 15:33:44 +01:00
Benoit Marty
a713b97e36 Merge pull request #2382 from Dominaezzz/suspend_functions_1
Convert RoomPushRuleService to suspend functions
2020-11-13 15:25:31 +01:00
Benoit Marty
b6acc8da70 Merge pull request #2376 from Dominaezzz/suspend_functions
Convert RoomCryptoService to suspend functions
2020-11-13 15:23:06 +01:00
Benoit Marty
b8c89325bc Improve Javadoc 2020-11-13 11:25:18 +01:00
Benoit Marty
b99cdf7367 Handle events of type "m.room.server_acl" - details only in developer mode (#890) 2020-11-13 11:07:50 +01:00
Dominic Fischer
60ce351a27 Convert RoomPushRuleService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-13 00:10:53 +00:00
Benoit Marty
413a55623e Handle events of type "m.room.server_acl" (#890) 2020-11-13 00:39:16 +01:00
Marcelo Filho
5b2f95d270 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/
2020-11-12 18:50:01 +00:00
Deleted User
44604c2509 Translated using Weblate (Norwegian Bokmål)
Currently translated at 42.2% (816 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/
2020-11-12 18:50:01 +00:00
Kaede
bf2a7c2efd Translated using Weblate (Japanese)
Currently translated at 48.6% (941 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ja/
2020-11-12 18:50:00 +00:00
notramo
ba5c42cc51 Translated using Weblate (Hungarian)
Currently translated at 94.9% (1835 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/
2020-11-12 18:49:59 +00:00
OLIVIER Thomas
cf2ea0f51c Translated using Weblate (French)
Currently translated at 99.9% (1932 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-12 18:49:58 +00:00
Valere
9df002fe4e Translated using Weblate (French)
Currently translated at 99.9% (1932 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-12 18:49:58 +00:00
François FERREIRA DE SOUSA
1a191c7d51 Translated using Weblate (French)
Currently translated at 99.9% (1932 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-12 18:49:58 +00:00
Hivaa
7ca57d918e Translated using Weblate (Persian)
Currently translated at 98.2% (1899 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/
2020-11-12 18:49:58 +00:00
Auri B. P
fe40e74809 Translated using Weblate (Catalan)
Currently translated at 60.1% (1162 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/
2020-11-12 18:49:57 +00:00
Benoit Marty
daac2e2a1c Better rational 2020-11-12 17:21:48 +01:00
Onuray Sahin
b88ec407a3 Merge branch 'develop' into feature/ons/fix_badge_color 2020-11-12 14:57:03 +03:00
Thomas sivertsen
8e9e4215ce Translated using Weblate (Norwegian Bokmål)
Currently translated at 50.0% (2 of 4 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/nb/
2020-11-11 18:19:15 +00:00
Thomas sivertsen
4dd83c29fe Added translation using Weblate (Norwegian Bokmål) 2020-11-11 18:03:06 +00:00
Benoit Marty
6020f423f4 Ask for explicit user consent to send their contact details to the identity server (#2375) 2020-11-11 17:51:39 +01:00
Benoit Marty
99bea8f7c3 small change in signature 2020-11-11 16:40:33 +01:00
Benoit Marty
d1e2d06538 Add userConsent UI to the Discovery screen 2020-11-11 16:15:38 +01:00
Benoit Marty
ccf5d759a4 Add userConsent to the Identity database and migrate the DB 2020-11-11 15:12:49 +01:00
Dominic Fischer
3ce8deec07 Convert RoomCryptoService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-11 13:01:46 +00:00
Benoit Marty
812b1f7baa Merge pull request #2364 from Dominaezzz/fix_draft_sharesheet
Fix draft share sheet
2020-11-11 13:08:45 +01:00
Benoit Marty
d1848fd5f7 Fix compilation issue :) 2020-11-10 16:01:19 +01:00
Benoit Marty
f57fc827fe Last cleanup 2020-11-10 15:37:28 +01:00
Benoit Marty
45e534bbf5 DRY again 2020-11-10 15:33:24 +01:00
Benoit Marty
bfcd4b8250 Extract AttachmentProviderFactory to its own file 2020-11-10 15:26:59 +01:00
Benoit Marty
510f8ae0f5 DRY 2020-11-10 15:26:13 +01:00
Onuray Sahin
a1941bf609 Merge branch 'develop' into feature/ons/fix_badge_color 2020-11-10 17:20:52 +03:00
ganfra
c9defec75d Update CHANGES and clean files 2020-11-10 15:18:41 +01:00
Onuray Sahin
a2a2015af6 Exclude yourself when decorating rooms which are direct or don't have more than 2 users. 2020-11-10 17:17:05 +03:00
Benoit Marty
ca70ddb810 DRY 2020-11-10 15:15:42 +01:00
ganfra
bf9d80c14c Merge branch 'develop' into feature/fix_user_vs_room_member 2020-11-10 15:15:28 +01:00
Benoit Marty
83467b8597 Fix crash on AttachmentViewer (#2365)
Not sure how to reproduce it, but if the value is -1, it will crash for sure
2020-11-10 15:12:21 +01:00
Benoit Marty
816301bf8d More cleanup 2020-11-10 15:09:49 +01:00
Benoit Marty
345e8a0679 i18n 2020-11-10 15:06:51 +01:00
Benoit Marty
bcd384c31c Small cleanup 2020-11-10 14:46:19 +01:00
Michael Telatynski
bbbaa60ddd Merge branch 'develop' into fix_draft_sharesheet 2020-11-10 11:34:29 +00:00
Benoit Marty
dc17e5c3fa Update CHANGES.md after merge of #2354 2020-11-10 10:39:34 +01:00
Benoit Marty
0150d3961b Merge pull request #2354 from Dominaezzz/suspend_functions
Convert `AccountService` to suspend functions
2020-11-10 10:36:44 +01:00
Benoit Marty
ae3e1f3a9f Merge pull request #2368 from vector-im/feature/bma/fix_discard
Feature/bma/fix discard
2020-11-10 09:11:55 +01:00
Benoit Marty
13ddc28d05 Fix issue with callback.onSuccess() called multiple times 2020-11-09 23:07:53 +01:00
Benoit Marty
cedeea13e6 Fix discard change dialog displayed by mistake when avatar has been updated 2020-11-09 23:00:19 +01:00
Benoit Marty
8f78c4a0fb Fix issue of verification banner displayed after logout 2020-11-09 21:08:53 +01:00
Benoit Marty
a37af307f4 Making progress 2020-11-09 20:03:44 +01:00
Dominic Fischer
be3bc175bf Update CHANGES.md
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-09 18:23:45 +00:00
Dominic Fischer
6207aab19d Remove cancellation handling
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-09 17:20:23 +00:00
Benoit Marty
01a5ec4c41 Go deeper in the settings 2020-11-09 16:56:20 +01:00
Benoit Marty
b09d45718a Make id for recyclerView less generic, and remove unused layout 2020-11-09 16:56:20 +01:00
Benoit Marty
07c805a019 Create sanity test with all screens path
Introduce `com.schibsted.spain:barista`
2020-11-09 16:56:20 +01:00
Benoit Marty
ea4e9b8e5e Fix "Riot is now Element" dialog displayed by mistake, after a logout 2020-11-09 16:56:20 +01:00
Benoit Marty
fd4b56572d Use also{} to log info 2020-11-09 16:56:20 +01:00
Benoit Marty
16448c0bc5 Add Github link to the authors 2020-11-09 16:53:17 +01:00
Benoit Marty
c34750bdab Add Onuray in the core team authors 2020-11-09 16:49:31 +01:00
Dominic Fischer
dee6f35888 Fix draft bug
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-08 14:57:15 +00:00
Dominic Fischer
62ca9a2a84 Fix misleading identifier
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-08 14:37:02 +00:00
random
ad64651532 Translated using Weblate (Italian)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/it/
2020-11-08 10:49:57 +00:00
Auri B. P
edc47b56a4 Translated using Weblate (Catalan)
Currently translated at 59.4% (1149 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/
2020-11-08 10:49:56 +00:00
Slavi Pantaleev
f39b3365db Translated using Weblate (Bulgarian)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/bg/
2020-11-08 10:49:55 +00:00
Dominic Fischer
0da4ff7b02 Run ktlint 2020-11-06 19:20:23 +00:00
Dominic Fischer
983e02888c Remove incorrect comment
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-06 19:17:45 +00:00
Dominic Fischer
35768ff7e8 Convert AccountService to suspend functions
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2020-11-06 16:49:51 +00:00
ganfra
6dfdc77ebd Use room member instead of user when it makes sense 2020-11-06 14:41:43 +01:00
Benoit Marty
0753ba3495 Merge pull request #2342 from vector-im/feature/ons/open_existing_dm
Navigate to an existing DM instead of creating a new one.
2020-11-06 11:29:20 +01:00
Jeff Huang
ffd3b9a7a7 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (4 of 4 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/zh_Hant/
2020-11-06 02:50:00 +00:00
Auri B. P
428062e1e4 Translated using Weblate (Catalan)
Currently translated at 100.0% (4 of 4 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/ca/
2020-11-06 02:50:00 +00:00
Auri B. P
cb49c7d060 Translated using Weblate (Catalan)
Currently translated at 100.0% (190 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/ca/
2020-11-06 02:50:00 +00:00
Jeff Huang
2a22d71e7c Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/
2020-11-06 02:49:59 +00:00
Marcelo Filho
eaa7fb7100 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (1929 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/
2020-11-06 02:49:58 +00:00
Priit Jõerüüt
9755dd73eb Translated using Weblate (Estonian)
Currently translated at 100.0% (1933 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/et/
2020-11-06 02:49:58 +00:00
Auri B. P
4c2e62031a Translated using Weblate (Catalan)
Currently translated at 58.9% (1140 of 1933 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/
2020-11-06 02:49:58 +00:00
Benoit Marty
51a95554d7 Remove useless code. We can now inject element in the Fragment constructors 2020-11-05 18:30:00 +01:00
Benoit Marty
12d8bd1743 Cleanup after rebase - avoid computing twice the existing roomId 2020-11-05 17:34:10 +01:00
Onuray Sahin
458b4259fe Change menu action title for existing rooms. 2020-11-05 17:02:13 +01:00
Onuray Sahin
e7714da8e8 Navigate to an existing DM instead of creating a new one. 2020-11-05 17:02:13 +01:00
Benoit Marty
b4f9d40767 Merge pull request #2344 from vector-im/feature/bma/sync_h
Small fixes
2020-11-05 16:58:46 +01:00
Benoit Marty
a0e074043b Merge pull request #2339 from vector-im/feature/realm_10
Realm 10: upgrade lib
2020-11-05 16:57:24 +01:00
Benoit Marty
9068168378 Merge branch 'develop' into feature/realm_10 2020-11-05 16:14:19 +01:00
Benoit Marty
de39a17247 Fix issue on setting avatar on a room.
We deleted the just added avatar because `withState {}` is asynchronous
2020-11-05 16:09:04 +01:00
Benoit Marty
5c7a5fab94 Improve API: rename the method and return empty list instead of null 2020-11-05 15:47:28 +01:00
Benoit Marty
c9e0aff839 DRY 2020-11-05 15:42:44 +01:00
Benoit Marty
61ed436c44 Move some method to the companion 2020-11-05 15:41:52 +01:00
Benoit Marty
b7a1f96294 Append to file but before the extension 2020-11-05 15:40:12 +01:00
Benoit Marty
15ad351579 Some fixes from Valere about verification 2020-11-05 15:33:28 +01:00
Benoit Marty
6cb4645514 Add a key to the category, to be able to hide it 2020-11-05 15:28:13 +01:00
ganfra
eb1fa0919f Room member: add methods to get directly from session 2020-11-04 18:09:51 +01:00
Benoit Marty
45edf6025e SAS Strings for Italian 2020-11-04 16:01:33 +01:00
Benoit Marty
17fed39b27 Version++ 2020-11-04 16:00:16 +01:00
Benoit Marty
bba167d4ea Merge branch 'release/1.0.10' 2020-11-04 15:58:45 +01:00
Benoit Marty
9ebda42d34 Merge branch 'release/1.0.10' into develop 2020-11-04 15:58:44 +01:00
Benoit Marty
619ec4faa4 Prepare release v1.0.10 2020-11-04 15:57:56 +01:00
Benoit Marty
49beae431f Merge pull request #2343 from RiotTranslateBot/weblate-element-android-element-app
Translations update from Weblate
2020-11-04 15:14:28 +01:00
Weblate
f3b8bb066c Merge branch 'origin/develop' into Weblate. 2020-11-04 13:43:47 +00:00
LinAGKar
b879be2b02 Translated using Weblate (Swedish)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/sv/
2020-11-04 13:43:37 +00:00
Hivaa
52e699e125 Translated using Weblate (Persian)
Currently translated at 98.4% (1899 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/
2020-11-04 13:43:36 +00:00
Benoit Marty
8a86b2c940 Merge pull request #2341 from vector-im/feature/bma/multi_home
Two elements in the task switcher (#2299)
2020-11-04 14:34:33 +01:00
Benoit Marty
b15fa7c0d7 Two elements in the task switcher (#2299) 2020-11-04 14:32:54 +01:00
Benoit Marty
6cd50cfaf1 Merge pull request #2336 from vector-im/feature/ons/fix_markdown_formatter
Markdown body should be pure text, see #739, #1506.
2020-11-04 13:50:46 +01:00
Onuray Sahin
9ed529b944 Merge branch 'develop' into feature/ons/fix_markdown_formatter 2020-11-04 13:43:26 +03:00
Onuray Sahin
bbc3dc0504 Set br softbreak to html parser. 2020-11-04 13:42:52 +03:00
Benoit Marty
d1d2c5f117 Merge pull request #2327 from vector-im/feature/bma/keysbackupcrash
Feature/bma/keysbackupcrash
2020-11-04 00:02:48 +01:00
ganfra
9f3f5d8053 Realm 10: upgrade lib and make it works on our current code. 2020-11-03 16:53:30 +01:00
Onuray Sahin
f24b593349 Update MarkdownParserTest. 2020-11-03 15:56:51 +03:00
Benoit Marty
0db1095373 Merge pull request #2334 from vector-im/feature/bca/crypto_db_clean
Feature/bca/crypto db clean
2020-11-03 10:31:53 +01:00
Benoit Marty
997cd68344 Add some padding for easier readability 2020-11-03 09:57:34 +01:00
Onuray Sahin
b40334f7db Markdown body should be pure text, see #739, #1506. 2020-11-03 11:53:50 +03:00
Benoit Marty
a216f82b35 Avoid code duplication and log total count 2020-11-03 09:30:26 +01:00
Benoit Marty
5eb2f14375 Move RealmDebugTools and make it an internal class 2020-11-03 09:20:24 +01:00
Benoit Marty
d4963dfb31 Use the same name for the 2 db log methods 2020-11-03 09:17:07 +01:00
Valere
3c7f61e45c Clean oldest gossiping entries on open
Add a dump of DB size on bug report
2020-11-02 17:45:08 +01:00
Besnik Bleta
10eef60f45 Translated using Weblate (Albanian)
Currently translated at 99.4% (189 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/sq/
2020-11-02 15:49:57 +00:00
zeritti
cb70757790 Translated using Weblate (Czech)
Currently translated at 100.0% (190 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/cs/
2020-11-02 15:49:57 +00:00
Corentin Noël
ac0418c796 Translated using Weblate (French)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-11-02 15:49:57 +00:00
Alexia Ŭerner
86b0094cdb Translated using Weblate (Esperanto)
Currently translated at 99.1% (1913 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/eo/
2020-11-02 15:49:56 +00:00
zeritti
c0f07bc0a5 Translated using Weblate (Czech)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/cs/
2020-11-02 15:49:56 +00:00
Valere
c3b8ed223d Increase log level of file logger 2020-11-02 16:39:06 +01:00
Benoit Marty
3947a78b56 Merge pull request #2058 from vector-im/feature/fix_sync_after_call_invite
Start sync when receive m.call.invite.
2020-11-02 14:45:22 +01:00
Benoit Marty
51ae2ce1e0 Merge branch 'develop' into feature/fix_sync_after_call_invite 2020-11-02 14:45:05 +01:00
Benoit Marty
9ff78051a9 Cleanup 2020-11-02 14:15:27 +01:00
Benoit Marty
a50bd7421c Merge pull request #2174 from lomion0815/fix_2100_2
Fix for #2100 and #2246:: Using Ringtone class to control ringtones for incoming calls.
2020-11-02 14:05:37 +01:00
Benoit Marty
0f21d80154 Merge branch 'develop' into fix_2100_2 2020-11-02 14:03:40 +01:00
Benoit Marty
734602f4f7 Merge pull request #2331 from gjpower/develop
Considerably faster QR-code bitmap generation
2020-11-02 10:03:52 +01:00
Markus
3364dd3380 Merged latest CHANGES.md 2020-11-01 10:13:27 +01:00
Graeme Power
bd36c67bf2 satisfy ktlint demand for spacing around "*"
Signed-off-by: Graeme Power <gjpower@tcd.ie>
2020-10-31 17:43:21 +01:00
Graeme Power
856ae33fd5 Added details to AUTHORS.md
Signed-off-by: Graeme Power <gjpower@tcd.ie>
2020-10-31 17:38:19 +01:00
Graeme Power
fd4bfaea1f Considerably faster QR-code bitmap generation
Directly assign colours to a colour buffer then use that buffer to
generate the bitmap. This is much faster than using Bitmap.setPixel for
every pixel.

Signed-off-by: Graeme Power <gjpower@tcd.ie>
2020-10-31 16:50:58 +01:00
Hakim Oubouali
3dfdb9cba0 Translated using Weblate (Central Atlas Tamazight)
Currently translated at 0.3% (6 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/tzm/
2020-10-31 12:50:08 +00:00
notramo
812181c435 Translated using Weblate (Hungarian)
Currently translated at 100.0% (3 of 3 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/hu/
2020-10-31 12:50:08 +00:00
ynerant
9f3d59711f Translated using Weblate (French)
Currently translated at 100.0% (3 of 3 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/fr/
2020-10-31 12:50:08 +00:00
notramo
438060dfa2 Translated using Weblate (Hungarian)
Currently translated at 64.2% (122 of 190 strings)

Translation: Element Android/Element Android Sdk
Translate-URL: https://translate.element.io/projects/element-android/element-sdk/hu/
2020-10-31 12:50:08 +00:00
Jeff Huang
f527dcf1fc Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/
2020-10-31 12:50:07 +00:00
Besnik Bleta
ae05305e52 Translated using Weblate (Albanian)
Currently translated at 99.4% (1919 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/sq/
2020-10-31 12:50:06 +00:00
Nikita Epifanov
386546dd21 Translated using Weblate (Russian)
Currently translated at 99.8% (1926 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/ru/
2020-10-31 12:50:05 +00:00
Marcelo Filho
88021dbf5e Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/
2020-10-31 12:50:05 +00:00
random
a99de88709 Translated using Weblate (Italian)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/it/
2020-10-31 12:50:03 +00:00
notramo
3fe677986e Translated using Weblate (Hungarian)
Currently translated at 95.1% (1835 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/
2020-10-31 12:50:03 +00:00
ynerant
8990089c65 Translated using Weblate (French)
Currently translated at 99.8% (1926 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/
2020-10-31 12:50:01 +00:00
Hivaa
f70efa2852 Translated using Weblate (Persian)
Currently translated at 75.6% (1460 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/
2020-10-31 12:50:00 +00:00
Priit Jõerüüt
caa29bf7da Translated using Weblate (Estonian)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/et/
2020-10-31 12:49:55 +00:00
Tirifto
d05a394134 Translated using Weblate (Esperanto)
Currently translated at 99.1% (1912 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/eo/
2020-10-31 12:49:54 +00:00
Nikolai Zahariev
18cc689209 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/bg/
2020-10-31 12:49:53 +00:00
Markus
7a11ab5bca Updated CHANGES.md 2020-10-31 13:48:53 +01:00
Markus
aa2a24e68a Changes requested by BillCarsonFs review. Thanks for the comments! 2020-10-31 13:17:25 +01:00
Hakim Oubouali
e3eccf48a3 Added translation using Weblate (Central Atlas Tamazight) 2020-10-31 07:37:35 +00:00
Benoit Marty
1db120a963 cleanup 2020-10-30 18:08:11 +01:00
Benoit Marty
fca0aa2cc4 KeysBackup: Avoid using !!, should fix #2262 2020-10-30 17:17:25 +01:00
Benoit Marty
0bcf42dbb8 KeysBackup: some API parameters are mandatory, so stop considering them as optional and avoid using !!
Also fix an issue with Json name: `hash` -> `etag`
Add some `internal` modifier (not as much as I would like to)
var -> val
Remove unused code
2020-10-30 16:14:33 +01:00
Benoit Marty
14e7e5e9fd Avoid usage of !! 2020-10-30 14:29:44 +01:00
Benoit Marty
1fcbf7ed42 Release backupOlmPkEncryption 2020-10-30 14:16:04 +01:00
Valere
1de1ddd496 Fix / bg sync for received by other session + dismiss full screen intent 2020-10-30 11:53:20 +01:00
Onuray Sahin
33a962b721 Start sync when receive m.call.invite. 2020-10-30 11:53:20 +01:00
Nikolai Zahariev
6e801d5f4d Translated using Weblate (Bulgarian)
Currently translated at 100.0% (3 of 3 strings)

Translation: Element Android/Element Android Store
Translate-URL: https://translate.element.io/projects/element-android/element-store/bg/
2020-10-30 08:22:24 +00:00
aWeinzierl
d46452c580 Translated using Weblate (German)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/de/
2020-10-29 13:28:26 +00:00
@a2sc:matrix.org
18f87924ad Translated using Weblate (German)
Currently translated at 100.0% (1929 of 1929 strings)

Translation: Element Android/Element Android App
Translate-URL: https://translate.element.io/projects/element-android/element-app/de/
2020-10-29 13:28:25 +00:00
Markus
42fc47685c Merge tag 'v1.0.9' into fix_2100_2 2020-10-19 14:07:17 +02:00
Benoit Marty
9a5e71f391 Merge branch 'hotfix/bma/versionCode' 2020-10-19 12:31:35 +02:00
Markus
a9f7fb46b3 Fix for ticket #2246: Ringtone volume cannot bechanged while ringing
This fix delays the creation of the audioManager until the call is connected. This way the call feature does not takes the focus from the core service (where the ringtone is generated) until the call is esablished. This way the volume can be controled correctly while the phone is ringing (incoming and outgoing).
2020-10-12 15:06:49 +02:00
Markus
e6a8fd5b73 Merge tag 'v1.0.8' into fix_2100_2 2020-10-11 09:15:57 +02:00
Markus
67eff0583c Fix for vector-im#2100: Using Ringtone and RingtoneManager classes to control ringtones for incoming calls.
Using systemwide setting for ringtone and volume.
2020-09-27 08:57:32 +02:00
406 changed files with 9471 additions and 5468 deletions

View File

@@ -1,10 +1,10 @@
A full developer contributors list can be found [here](https://github.com/vector-im/element-android/graphs/contributors).
A full developer contributors list can be found [here](https://github.com/vector-im/element-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](https://github.com/bmarty): 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.
@@ -12,7 +12,7 @@ Even if we try to be able to work on all the functionalities, we have more knowl
- Reviewing and polishing developed features, code quality manager, PRs reviewer, GitHub community manager.
- Release manager on the Play Store
## François: Software architect
## [Ganfra](https://github.com/ganfra) (aka François): Software architect
[@ganfra:matrix.org](https://matrix.to/#/@ganfra:matrix.org)
- Software architect, Android developer
@@ -20,12 +20,17 @@ Even if we try to be able to work on all the functionalities, we have more knowl
- Work mainly on the global architecture of the project.
- Specialist of the timeline, and lots of other features.
## Valere: Product manager, Android developer
## [Valere](https://github.com/BillCarsonFr): Product manager, Android developer
[@valere35:matrix.org](https://matrix.to/#/@valere35:matrix.org)
- Product manager, Android developer
- Specialist on the crypto implementation.
## [Onuray](https://github.com/onurays): Android developer
[@onurays:matrix.org](https://matrix.to/#/@onurays:matrix.org)
- Android developer
# Other contributors
First of all, we thank all contributors who use Element and report problems on this GitHub project or via the integrated rageshake function.
@@ -33,3 +38,8 @@ First of all, we thank all contributors who use Element and report problems on t
We do not forget all translators, for their work of translating Element into many languages. They are also the authors of Element.
Feel free to add your name below, when you contribute to the project!
Name | Matrix ID | GitHub
----------|-----------------------------|--------------------------------------
gjpower | @gjpower:matrix.org | [gjpower](https://github.com/gjpower)
TR_SLimey | @tr_slimey:an-atom-in.space | [TR-SLimey](https://github.com/TR-SLimey)

View File

@@ -1,8 +1,47 @@
Changes in Element 1.0.10 (2020-XX-XX)
Changes in Element 1.0.11 (2020-11-27)
===================================================
Features ✨:
-
- Create DMs with users by scanning their QR code (#2025)
- Add Invite friends quick invite actions (#2348)
- Add friend by scanning QR code, show your code to friends (#2025)
Improvements 🙌:
- New room creation tile with quick action (#2346)
- Open an existing DM instead of creating a new one (#2319)
- Use RoomMember instead of User in the context of a Room.
- Ask for explicit user consent to send their contact details to the identity server (#2375)
- Handle events of type "m.room.server_acl" (#890)
- Room creation form: add advanced section to disable federation (#1314)
- Move "Enable Encryption" from room setting screen to room profile screen (#2394)
- Home empty screens quick design update (#2347)
- Improve Invite user screen (seamless search for matrix ID)
Bugfix 🐛:
- Fix crash on AttachmentViewer (#2365)
- Exclude yourself when decorating rooms which are direct or don't have more than 2 users (#2370)
- F-Droid version: ensure timeout of sync request can be more than 60 seconds (#2169)
- Fix issue when restoring draft after sharing (#2287)
- Fix issue when updating the avatar of a room (new avatar vanishing)
- Discard change dialog displayed by mistake when avatar has been updated
- Try to fix cropped image in timeline (#2126)
- Registration: annoying error message scares every new user when they add an email (#2391)
- Fix jitsi integration for those with non-vanilla dialler frameworks
- Update profile has no effect if user is in zero rooms
- Fix issues with matrix.to deep linking (#2349)
SDK API changes ⚠️:
- AccountService now exposes suspendable function instead of using MatrixCallback (#2354).
Note: We will incrementally migrate all the SDK API in a near future (#2449)
Test:
- Add `allScreensTest` to cover all screens of the app
Other changes:
- Upgrade Realm dependency to 10.0.0
Changes in Element 1.0.10 (2020-11-04)
===================================================
Improvements 🙌:
- Rework sending Event management (#154)
@@ -17,22 +56,16 @@ Improvements 🙌:
- Prepare changelog for F-Droid (#2296)
- Add graphic resources for F-Droid (#812, #2220)
- Highlight text in the body of the displayed result (#2200)
- Considerably faster QR-code bitmap generation (#2331)
Bugfix 🐛:
- Fixed ringtone handling (#2100 & #2246)
- Messages encrypted with no way to decrypt after SDK update from 0.18 to 1.0.0 (#2252)
- Incoming call continues to ring if call is answered on another device (#1921)
- Search Result | scroll jumps after pagination (#2238)
Translations 🗣:
-
SDK API changes ⚠️:
-
Build 🧱:
-
Other changes:
-
- Badly formatted mentions in body (#1506)
- KeysBackup: Avoid using `!!` (#2262)
- Two elements in the task switcher (#2299)
Changes in Element 1.0.9 (2020-10-16)
===================================================
@@ -1017,5 +1050,8 @@ SDK API changes ⚠️:
Build 🧱:
-
Test:
-
Other changes:
-

View File

@@ -0,0 +1,30 @@
Element е приложение от нов тип за съобщения и сътрудничество:
1. Дава Ви контрол, за да запазите поверителността си
2. Позволява ви да комуникирате с всеки в мрежата на Matrix и дори извън него, като се интегрира с приложения като Slack
3. Предпазва ви от реклами, изтичане на данни и търговско следене
4. Защитава ви чрез шифроване от край до край, с кръстосано подписване, за да проверите другите
Element е напълно различен от другите приложения за съобщения и сътрудничество, понеже е децентрализиран и с отворен код.
Element ви позволява да го хоствате самостоятелно - или да изберете хост - така че да имате поверителност, собственост и контрол върху Вашите данни и разговори. Дава ви достъп до отворена мрежа, така че комуникацията Ви не е ограничена до потребителите на Element. И е много сигурно.
Element е в състояние да направи всичко това, защото работи върху Matrix - стандартът за отворена, децентрализирана комуникация.
Element ви дава контрол, като ви позволява да изберете кой да хоства Вашите разговори. От приложението Element можете да изберете хостване по различни начини:
1. Вземете безплатен профил на публичния сървър на matrix.org, хостван от разработчиците на Matrix, или изберете от хиляди публични сървъри, хоствани от доброволци
2. Самостоятелно хоствайте профила си, като пуснете сървър на собствен хардуер
3. Регистрирайте се за профил на персонализиран сървър, като се абонирате за хостинг платформата Element Matrix Services
<b>Защо да изберете Element?</b>
<b>ПРИТЕЖАВАЙТЕ ДАННИТЕ СИ</b>: Вие решавате къде да съхранявате вашите данни и съобщения. Вие ги притежавате и контролирате, а не някаква МЕГАКОРПОРАЦИЯ, която складира вашите данни или дава достъп на трети страни.
<b>ОТВОРЕНИ СЪОБЩЕНИЯ И СЪТРУДНИЧЕСТВО</b>: Можете да разговаряте с всеки друг в мрежата на Matrix, независимо дали използва Element или друго приложение на Matrix и дори ако използва различна система за съобщения като Slack, IRC or XMPP.
<b>СВРЪХ СИГУРНО</b>: Реално шифроване от край до край (само тези в разговора могат да дешифрират съобщения) и кръстосано подписване за проверка на устройствата на участниците в разговора.
<b>ПЪЛНА КОМУНИКАЦИЯ</b>: Съобщения, гласови и видео разговори, споделяне на файлове, споделяне на екран и цял куп интеграции, ботове и джаджи. Изграждайте стаи, общности, поддържайте връзка и направете нещата завършени.
<b>НАВСЯКЪДЕ КЪДЕТО СТЕ</b>: Поддържайте връзка, където и да сте, с напълно синхронизирана история на съобщенията на всичките ви устройства и чрез web на https://app.element.io.

View File

@@ -0,0 +1 @@
Сигурен децентрализиран чат и VoIP. Пазете данните си от външни лица.

View File

@@ -0,0 +1 @@
Element (предишен Riot.im)

View File

@@ -0,0 +1 @@
// TODO

View File

@@ -0,0 +1,30 @@
Element és un nou tipus d'aplicació de missatgeria i col·laboració que:
1. Et dóna a tu el control per preservar la teva privadesa
2. Et permet comunicar-te amb qualsevol persona de la xarxa Matrix i, fins i tot més enllà gràcies a integracions amb altres aplicacions com Slack
3. Et protegeix de la publicitat, l'obtenció no desitjada de dades i dels navegadors amb accés controlat
4. T'assegura a tu mitjançant l'encriptació d'extrem a extrem i amb signatures creuades per verificar els altres
Element és completament diferent a les altres aplicacions de missatgeria i col·laboració ja que és descentralitzat i de codi obert.
Element et deixa triar l'allotjament perquè disposis de privadesa, propietat i control de les teves dades i converses. Et dóna accés a una xarxa oberta perquè no et quedis únicament parlant amb els usuaris d'Element.
Element pot fer tot això ja que opera sobre Matrix - l'estàndard per a les comunicacions obertes i descentralitzades.
Element et dóna el control perquè et deixa escollir qui vols que allotgi les teves converses. Des de l'aplicació d'Element, pots triar l'allotjament de diferents maneres:
1. Crea un compte gratuït al servidor públic de matrix.org allotjat pels desenvolupadors de Matrix o tria'n un entre els milers de servidors públics creats per voluntaris
2. Allotja tu mateix el teu compte en el teu propi servidor
3. Registra el compte en un servidor personalitzat subscrivint-te a la plataforma d'Element Matrix Services (EMS)
<b>Per què escollir Element?</b>
<b>PROPIETAT DE LES TEVES DADES</b>: Tu decideixes a on desar les teves dades i missatges. Tu les controles i n'ets el propietari, no una mega-corporació que s'aprofita de les teves dades o les cedeix a tercers.
<b>MISSATGERIA I COL·LABORACIÓ OBERTA</b>: Pots parlar amb qualsevol que estigui a la xarxa Matrix, ja sigui amb Element o amb qualsevol altre aplicació Matrix, fins i tot encara que utilitzin sistemes de missatgeria diferents com Slack, IRC o XMPP.
<b>SUPER-SEGUR</b>: Encriptació d'extrem a extrem real (només qui està conversant pot desxifrar els missatges), i amb signatures creuades per a verificar els dispositius dels participants en les converses.
<b>COMUNICACIÓ COMPLETA</b>: Missatgeria, veu i video-trucades, compartició de fitxers, compartició de pantalla i un munt d'integracions, bots i ginys. Crea sales, comunitats, mantén-te en contacte i enllesteix el que et proposes.
<b>A TOT ARREU</b>: Mantingues el contacte des de qualsevol lloc on siguis, amb un historial de missatges totalment sincronitzat entre tots els teus dispositius i també a la web: https://app.element.io.

View File

@@ -0,0 +1 @@
Xat i VoIP segurs i descentralitzats. Protegeix les teves dades de tercers.

View File

@@ -0,0 +1 @@
Element (anteriorment Riot.im)

View File

@@ -0,0 +1 @@
// TODO

View File

@@ -1 +1,2 @@
// TODO
This new version mainly contains bug fixes and improvements. Sending a message is now much faster.
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.10

View File

@@ -0,0 +1,2 @@
This new version mainly contains user interface and user experience improvements. Now you can invite friends, and create DM very fast by scanning QR codes.
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.11

View File

@@ -0,0 +1 @@
// TODO

View File

@@ -1,30 +1,30 @@
Element es un nuevo tipo de aplicación de mensajería y colaboración que:
1. Le da el control para preservar su privacidad
2. Le permite comunicarse con cualquier persona en la red Matrix e incluso más allá al integrarse con aplicaciones como Slack.
3. Te protege de la publicidad, la minería de datos y los jardines vallados.
4. Lo protege a través del cifrado de un extremo a otro, con firma cruzada para verificar a otros
1. Te da el control para preservar su privacidad
2. Te permite comunicarse con cualquier persona en la red Matrix e incluso más allá al integrarse con aplicaciones como Slack
3. Te protege de la publicidad, la minería de datos y los jardines vallados
4. Te protege a través de encriptación de Extremo-a-Extremo, con firma cruzada para verificar a otros
Element es completamente diferente de otras aplicaciones de mensajería y colaboración porque es descentralizado y de código abierto.
Element le permite autohospedarse, o elegir un host, para que tenga privacidad, propiedad y control de sus datos y conversaciones. Te da acceso a una red abierta; para que no se quede atascado hablando solo con otros usuarios de Element. Y es muy seguro.
Element te permite tener su propio servidor privado, o elegir uno público, para que tenga privacidad, posesión, y control de sus datos y conversaciones. Te da acceso a una red abierta; para que no se quede atrapado hablando solo con otros usuarios de Element. Y es muy seguro.
Element puede hacer todo esto porque opera en Matrix, el estándar para la comunicación abierta y descentralizada.
Element te da el control permitiéndote elegir quién aloja tus conversaciones. Desde la aplicación Element, puede elegir hospedar de diferentes maneras:
Element te da el control permitiéndote elegir quién aloja tus conversaciones. Desde la aplicación Element, puedes elegir hospedar de diferentes maneras:
1. Obtenga una cuenta gratuita en el servidor público de matrix.org alojado por los desarrolladores de Matrix, o elija entre miles de servidores públicos alojados por voluntarios
2. Autohospede su cuenta ejecutando un servidor en su propio hardware
3. Regístrese para obtener una cuenta en un servidor personalizado simplemente suscribiéndose a la plataforma de alojamiento de Element Matrix Services
1. Obtén una cuenta gratuita en el servidor público de matrix.org alojado por los desarrolladores de Matrix, o elije entre miles de servidores públicos alojados por voluntarios
2. Autohospeda tu cuenta con un servidor en tu propio hardware
3. Regístrate para obtener una cuenta en un servidor personalizado simplemente suscribiéndote a la plataforma de alojamiento de Element Matrix Services
<b>¿Por qué elegir Element?</b>
<b>POSEE SUS DATOS</b>: Tú decides dónde guardar tus datos y mensajes. Usted es el propietario y lo controla, no algún MEGACORP que extraiga sus datos o dé acceso a terceros.
<b>TOMA POSESIÓN DE TUS DATOS</b>: Tú decides dónde guardar tus datos y mensajes. Tú eres el propietario y quien lo controla, no alguna MEGACORP que extrae tu datos o da acceso a terceros.
<b>MENSAJERÍA ABIERTA Y COLABORACIÓN</b>: Puede chatear con cualquier otra persona en la red de Matrix, ya sea que estén usando Element u otra aplicación de Matrix, e incluso si están usando un sistema de mensajería diferente como Slack, IRC o XMPP.
<b>MENSAJERÍA ABIERTA Y COLABORACIÓN</b>: Puede chatear con cualquier otra persona en la red de Matrix, tanto si usan Element u otra aplicación de Matrix, e incluso si están usando un sistema de mensajería diferente como Slack, IRC o XMPP.
<b>SUPER SEGURO</b>: Cifrado real de extremo a extremo (solo aquellos en la conversación pueden descifrar mensajes) y firma cruzada para verificar los dispositivos de los participantes de la conversación.
<b>SUPER SEGURO</b>: Encriptación de Extremo-a-Extremo real (solo aquellos en la conversación pueden descifrar mensajes) y firma cruzada para verificar los dispositivos de los participantes de la conversación.
<b>COMUNICACIÓN COMPLETA</b>: Mensajería, llamadas de voz y video, uso compartido de archivos, uso compartido de pantalla y un montón de integraciones, bots y widgets. Construya salas, comunidades, manténgase en contacto y haga las cosas.
<b>COMUNICACIÓN COMPLETA</b>: Mensajería, llamadas de voz y video, uso compartido de archivos, uso compartido de pantalla y un montón de integraciones, bots y widgets. Crea salas, comunidades, mantente en contacto y organízate con eficacia.
<b>EN TODAS PARTES</b>: Manténgase en contacto donde quiera que esté con un historial de mensajes totalmente sincronizado en todos sus dispositivos y en la web en https://app.element.io.
<b>EN TODAS PARTES</b>: Mantente en contacto donde quiera que estés con un historial de mensajes totalmente sincronizado en todos sus dispositivos y en la web en https://app.element.io.

View File

@@ -1 +1 @@
Chat y VoIP descentralizados seguros. Mantenga sus datos a salvo de terceros.
Chat y VoIP descentralizados y seguros. Mantén tus datos a salvo de terceros.

View File

@@ -1 +1 @@
Element (anteriorment Riot.im)
Element (previamente Riot.im)

View File

@@ -0,0 +1 @@
// برای انجام

View File

@@ -0,0 +1,30 @@
Element est une nouvelle application de messagerie et de collaboration qui :
1) Vous place aux commandes de votre vie privée
2) Vous permet de communiquer avec n'importe qui du réseau Matrix, et plus encore par des intégrations d'autres applications comme Slack ou Discord
3) Vous protège de la publicité et de la collecte de données
4) Vous sécurise grâce à du chiffrement bout-à-bout, avec de la signature croisée pour authentifier les autres utilisateurs
Element est complètement différent des autres applications de messagerie et de collaboration puisque l'application est décentralisée et open-source.
Element vous permet d'héberger vous-même -ou de choisir un hôte- vous permettant d'assurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous offre l'accès à un réseau ouvert, vous n'êtes donc pas condamné à parler à d'autres utilisateurs d'Element seulement. Et c'est très sécurisé.
Element peut faire tout ça car il est basé sur Matrix, le protocole standard pour la communication ouverte et décentralisée.
Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières :
1) Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parler les milliers de serveurs public hébergés par des bénévoles
2) Héberger vous-même votre compte en installant un serveur sur votre propre machine
3) Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS)
<b>Pourquoi choisir Element ?</b>
<b>POSSÉDEZ VOS DONNÉES</b> : Vous décidez où conserver vos données et vos messages. Vous les possédez et vous les contrôlez, et non une MEGACORP qui mine vos données ou les donnent à des tiers
<b>UNE MESSAGERIE OUVERTE ET COLLABORATIVE</b> : Vous pouvez discuter avec n'importe qui sur le réseau Matrix, qu'ils utilisent Element ou une autre application basée sur Matrix, et même s'ils utilisent un système de messagerie différent comment Slack, Discord, IRC ou XMPP.
<b>SUPER SÉCURISÉ</b> : Un réel chiffrement bout-à-bout (seulement ceux deux la conversation peuvent déchiffrer les messages), et une signature croisée pour vérifier les appareils des participants de la conversation.
<b>COMMUNICATION COMPLÈTE</b> : Messagerie, appels vocaux et vidéo, transfert de fichiers, partage d'écran et un tas d'intégrations, robots et widgets. Construisez des salons, des communautés, restez en contact et accomplissez de grandes choses.
<b>PARTOUT OÙ VOUS ÊTES</b> : Restez connectés peu import où vous êtes avec la synchronisation complète de l'historique des messages sur tous vos appareils et sur le web sur https://app.element.io.

View File

@@ -1 +1 @@
Element (előzőleg Riot.im)
Element (régebben Riot.im)

View File

@@ -0,0 +1 @@
// DA FARE

View File

@@ -0,0 +1 @@
Sikker desentralisert chat & VoIP. Beskytt dataene dine fra tredjeparter.

View File

@@ -0,0 +1 @@
Element (tidligere Riot.im)

View File

@@ -0,0 +1 @@
// A FAZER

View File

@@ -0,0 +1 @@
// ATT GÖRA

View File

@@ -0,0 +1 @@
// 待辦事項

View File

@@ -0,0 +1,30 @@
Element 是一種新型態的即時通訊軟體與協作應用程式:
1. 自己的隱私自己掌控
2. 讓您與任何在 Matrix 網路中的人通訊,甚至可與如 Slack 等的應用程式整合
3. 保護您免受廣告、資料採礦與圍牆花園的侵害
4. 透過端到端加密保護您,並使用交叉簽章來驗證其他人
Element 是去中心化且開放原始碼的應用程式,因此與其他即時通訊與協作軟體完全不同。
Element 讓您可以自架(或是自行選擇服務提供者)所以您擁有您資料與對話的隱私、所有權與控制權。它讓您可以存取開放的網路;因此,您不僅可以與其他 Matrix 使用者聊天。而且非常安全。
Element 能作到這些事情是因為它在 Matrix 上執行,這是一個開放的去中心化通訊的標準。
Element 讓您選擇您要在哪裡託管您的對話來將控制權還給您。在 Element 應用程式中,您可以選擇其他方式來託管:
1. 在由 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費的帳號,或是從數千個由志願者所架設的公開伺服器中選擇
2. 在您自己的硬體上自行架設伺服器並建立帳號
3. 訂閱 Element Matrix 服務託管平台並在自訂伺服氣上註冊帳號
<b>為何選擇 Element</b>
<b>擁有您的資料</b>:您決定您的資料與訊息要放在哪裡。您擁有並控制它,而非某些科技巨頭會挖掘您的資料並將其售予第三方。
<b>開放的即時通訊與協作</b>:您可以與 Matrix 網路中的任何人聊天,不管他們是使用 Element 或其他 Matrix 應用程式都可以,或甚至是其他的訊息系統,如 Slack、IRC 或 XMPP 也都可以。
<b>超級安全</b>:即時的端到端加密(僅有參與對話的人可以解密訊息),以及交叉簽章以驗證對話參與者的裝置。
<b>完整通訊</b>:即時通訊、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建立聊天室、保持聯繫並完成工作。
<b>無論您身在何處</b>:無論您身在何處,都可以透過 https://app.element.io 來在所有裝置與網路上保持訊息歷史同步。

View File

@@ -0,0 +1 @@
安全的去中心化聊天與 VoIP。確保您的資料不受第三方的影響。

View File

@@ -0,0 +1 @@
Element曾名為 Riot.im

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=0080de8491f0918e4f529a6db6820fa0b9e818ee2386117f4394f95feb1d5583
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionSha256Sum=22449f5231796abd892c98b2a07c9ceebe4688d192cd2d6763f8e3bf8acbedeb
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.pushers.Pusher
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.sync.SyncState
@@ -92,6 +93,13 @@ class RxSession(private val session: Session) {
}
}
fun liveRoomMember(userId: String, roomId: String): Observable<Optional<RoomMemberSummary>> {
return session.getRoomMemberLive(userId, roomId).asObservable()
.startWithCallable {
session.getRoomMember(userId, roomId).toOptional()
}
}
fun liveUsers(): Observable<List<User>> {
return session.getUsersLive().asObservable()
}

View File

@@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:6.1.0"
classpath "io.realm:realm-gradle-plugin:10.0.0"
}
}
@@ -149,7 +149,7 @@ dependencies {
implementation 'androidx.exifinterface:exifinterface:1.3.0'
// Database
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
// Work

View File

@@ -43,8 +43,8 @@ class ChangePasswordTest : InstrumentedTest {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
// Change password
commonTestHelper.doSync<Unit> {
session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD, it)
commonTestHelper.runBlockingTest {
session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD)
}
// Try to login with the previous password, it will fail

View File

@@ -43,8 +43,8 @@ class DeactivateAccountTest : InstrumentedTest {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
// Deactivate the account
commonTestHelper.doSync<Unit> {
session.deactivateAccount(TestConstants.PASSWORD, false, it)
commonTestHelper.runBlockingTest {
session.deactivateAccount(TestConstants.PASSWORD, false)
}
// Try to login on the previous account, it will fail (M_USER_DEACTIVATED)

View File

@@ -40,6 +40,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
@@ -343,6 +344,14 @@ class CommonTestHelper(context: Context) {
await(latch, timeout)
}
fun <T> runBlockingTest(timeout: Long = TestConstants.timeOutMillis, block: suspend () -> T): T {
return runBlocking {
withTimeout(timeout) {
block()
}
}
}
// Transform a method with a MatrixCallback to a synchronous method
inline fun <reified T> doSync(timeout: Long? = TestConstants.timeOutMillis, block: (MatrixCallback<T>) -> Unit): T {
val lock = CountDownLatch(1)

View File

@@ -68,8 +68,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
if (encryptedRoom) {
val room = aliceSession.getRoom(roomId)!!
mTestHelper.doSync<Unit> {
room.enableEncryption(callback = it)
mTestHelper.runBlockingTest {
room.enableEncryption()
}
}
@@ -245,7 +245,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
return MegolmBackupCreationInfo(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
authData = createFakeMegolmBackupAuthData()
authData = createFakeMegolmBackupAuthData(),
recoveryKey = "fake"
)
}

View File

@@ -115,9 +115,8 @@ class KeysBackupTest : InstrumentedTest {
}
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm)
assertNotNull(megolmBackupCreationInfo.authData)
assertNotNull(megolmBackupCreationInfo.authData!!.publicKey)
assertNotNull(megolmBackupCreationInfo.authData!!.signatures)
assertNotNull(megolmBackupCreationInfo.authData.publicKey)
assertNotNull(megolmBackupCreationInfo.authData.signatures)
assertNotNull(megolmBackupCreationInfo.recoveryKey)
stateObserver.stopAndCheckStates(null)
@@ -258,14 +257,14 @@ class KeysBackupTest : InstrumentedTest {
// - Check encryptGroupSession() returns stg
val keyBackupData = keysBackup.encryptGroupSession(session)
assertNotNull(keyBackupData)
assertNotNull(keyBackupData.sessionData)
assertNotNull(keyBackupData!!.sessionData)
// - Check pkDecryptionFromRecoveryKey() is able to create a OlmPkDecryption
val decryption = keysBackup.pkDecryptionFromRecoveryKey(keyBackupCreationInfo.recoveryKey)
assertNotNull(decryption)
// - Check decryptKeyBackupData() returns stg
val sessionData = keysBackup
.decryptKeyBackupData(keyBackupData,
.decryptKeyBackupData(keyBackupData!!,
session.olmInboundGroupSession!!.sessionIdentifier(),
cryptoTestData.roomId,
decryption!!)

View File

@@ -555,7 +555,7 @@ class SASTest : InstrumentedTest {
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
requestID = prAlicePOV?.transactionId
Log.v("TEST", "== alicePOV is $prAlicePOV")
prAlicePOV?.transactionId != null && prAlicePOV.localId == req.localId
@@ -566,7 +566,7 @@ class SASTest : InstrumentedTest {
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prBobPOV = bobVerificationService.getExistingVerificationRequest(aliceSession.myUserId)?.firstOrNull()
val prBobPOV = bobVerificationService.getExistingVerificationRequests(aliceSession.myUserId).firstOrNull()
Log.v("TEST", "== prBobPOV is $prBobPOV")
prBobPOV?.transactionId == requestID
}
@@ -581,7 +581,7 @@ class SASTest : InstrumentedTest {
// wait for alice to get the ready
mTestHelper.waitWithLatch {
mTestHelper.retryPeriodicallyWithLatch(it) {
val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
Log.v("TEST", "== prAlicePOV is $prAlicePOV")
prAlicePOV?.transactionId == requestID && prAlicePOV?.isReady != null
}

View File

@@ -25,6 +25,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.internal.session.room.send.pills.MentionLinkSpecComparator
import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
/**
* It will not be possible to test all combinations. For the moment I add a few tests, then, depending on the problem discovered in the wild,
@@ -45,7 +47,8 @@ class MarkdownParserTest : InstrumentedTest {
*/
private val markdownParser = MarkdownParser(
Parser.builder().build(),
HtmlRenderer.builder().build()
HtmlRenderer.builder().softbreak("<br />").build(),
TextPillsUtils(MentionLinkSpecComparator())
)
@Test
@@ -144,12 +147,14 @@ class MarkdownParserTest : InstrumentedTest {
)
}
// TODO. Improve testTypeNewLines function to cover <pre><code class="language-code">test</code></pre>
@Test
fun parseCodeNewLines() {
fun parseCodeNewLines_not_passing() {
testTypeNewLines(
name = "code",
markdownPattern = "`",
htmlExpectedTag = "code"
markdownPattern = "```",
htmlExpectedTag = "code",
softBreak = "\n"
)
}
@@ -163,7 +168,7 @@ class MarkdownParserTest : InstrumentedTest {
}
@Test
fun parseCode2NewLines() {
fun parseCode2NewLines_not_passing() {
testTypeNewLines(
name = "code",
markdownPattern = "``",
@@ -181,7 +186,7 @@ class MarkdownParserTest : InstrumentedTest {
}
@Test
fun parseCode3NewLines() {
fun parseCode3NewLines_not_passing() {
testTypeNewLines(
name = "code",
markdownPattern = "```",
@@ -243,7 +248,7 @@ class MarkdownParserTest : InstrumentedTest {
}
@Test
fun parseBoldNewLines_not_passing() {
fun parseBoldNewLines2() {
"**bold**\nline2".let { markdownParser.parse(it).expect(it, "<strong>bold</strong><br />line2") }
}
@@ -334,13 +339,14 @@ class MarkdownParserTest : InstrumentedTest {
private fun testTypeNewLines(name: String,
markdownPattern: String,
htmlExpectedTag: String) {
htmlExpectedTag: String,
softBreak: String = "<br />") {
// With new line inside the block
"$markdownPattern$name\n$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name<br />$name</$htmlExpectedTag>")
expectedFormattedText = "<$htmlExpectedTag>$name$softBreak$name</$htmlExpectedTag>")
}
// With new line between two blocks
@@ -348,7 +354,7 @@ class MarkdownParserTest : InstrumentedTest {
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><$htmlExpectedTag>$name</$htmlExpectedTag>")
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><br /><$htmlExpectedTag>$name</$htmlExpectedTag>")
}
}

View File

@@ -71,38 +71,27 @@ class SearchMessagesTest : InstrumentedTest {
commonTestHelper.await(lock)
lock = CountDownLatch(1)
aliceSession
.searchService()
.search(
searchTerm = "lore",
limit = 10,
includeProfile = true,
afterLimit = 0,
beforeLimit = 10,
orderByRecent = true,
nextBatch = null,
roomId = aliceRoomId,
callback = object : MatrixCallback<SearchResult> {
override fun onSuccess(data: SearchResult) {
super.onSuccess(data)
assertTrue(data.results?.size == 2)
assertTrue(
data.results
?.all {
(it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse()
}.orFalse()
)
lock.countDown()
}
override fun onFailure(failure: Throwable) {
super.onFailure(failure)
fail(failure.localizedMessage)
lock.countDown()
}
}
)
lock.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)
val data = commonTestHelper.runBlockingTest {
aliceSession
.searchService()
.search(
searchTerm = "lore",
limit = 10,
includeProfile = true,
afterLimit = 0,
beforeLimit = 10,
orderByRecent = true,
nextBatch = null,
roomId = aliceRoomId
)
}
assertTrue(data.results?.size == 2)
assertTrue(
data.results
?.all {
(it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse()
}.orFalse()
)
aliceTimeline.removeAllListeners()
cryptoTestData.cleanUp(commonTestHelper)

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.database
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.where
import timber.log.Timber
object RealmDebugTools {
/**
* Log info about the crypto DB
*/
fun dumpCryptoDb(realmConfiguration: RealmConfiguration) {
Realm.getInstance(realmConfiguration).use {
Timber.d("Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}")
val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) }
Timber.d("Realm encryption key : $key")
// Check if we have data
Timber.e("Realm is empty: ${it.isEmpty}")
Timber.d("Realm has CryptoMetadataEntity: ${it.where<CryptoMetadataEntity>().count()}")
Timber.d("Realm has CryptoRoomEntity: ${it.where<CryptoRoomEntity>().count()}")
Timber.d("Realm has DeviceInfoEntity: ${it.where<DeviceInfoEntity>().count()}")
Timber.d("Realm has KeysBackupDataEntity: ${it.where<KeysBackupDataEntity>().count()}")
Timber.d("Realm has OlmInboundGroupSessionEntity: ${it.where<OlmInboundGroupSessionEntity>().count()}")
Timber.d("Realm has OlmSessionEntity: ${it.where<OlmSessionEntity>().count()}")
Timber.d("Realm has UserEntity: ${it.where<UserEntity>().count()}")
Timber.d("Realm has KeyInfoEntity: ${it.where<KeyInfoEntity>().count()}")
Timber.d("Realm has CrossSigningInfoEntity: ${it.where<CrossSigningInfoEntity>().count()}")
Timber.d("Realm has TrustLevelEntity: ${it.where<TrustLevelEntity>().count()}")
Timber.d("Realm has GossipingEventEntity: ${it.where<GossipingEventEntity>().count()}")
Timber.d("Realm has IncomingGossipingRequestEntity: ${it.where<IncomingGossipingRequestEntity>().count()}")
Timber.d("Realm has OutgoingGossipingRequestEntity: ${it.where<OutgoingGossipingRequestEntity>().count()}")
Timber.d("Realm has MyDeviceLastSeenInfoEntity: ${it.where<MyDeviceLastSeenInfoEntity>().count()}")
}
}
}

View File

@@ -66,9 +66,9 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
}
private fun logJson(formattedJson: String) {
val arr = formattedJson.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (s in arr) {
Timber.v(s)
}
formattedJson
.lines()
.dropLastWhile { it.isEmpty() }
.forEach { Timber.v(it) }
}
}

View File

@@ -27,7 +27,7 @@ interface LoginWizard {
* @param password the password field
* @param deviceName the initial device name
* @param callback the matrix callback on which you'll receive the result of authentication.
* @return return a [Cancelable]
* @return a [Cancelable]
*/
fun login(login: String,
password: String,

View File

@@ -22,3 +22,8 @@ fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
else -> "$prefix$this"
}
}
/**
* Append a new line and then the provided string
*/
fun StringBuilder.appendNl(str: String) = append("\n").append(str)

View File

@@ -15,11 +15,9 @@
*/
package org.matrix.android.sdk.api.pushrules
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.pushrules.rest.PushRule
import org.matrix.android.sdk.api.pushrules.rest.RuleSet
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.Cancelable
interface PushRuleService {
/**
@@ -29,13 +27,13 @@ interface PushRuleService {
fun getPushRules(scope: String = RuleScope.GLOBAL): RuleSet
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
suspend fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean)
fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
suspend fun addPushRule(kind: RuleKind, pushRule: PushRule)
fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
suspend fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule)
fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
suspend fun removePushRule(kind: RuleKind, pushRule: PushRule)
fun addPushRuleListener(listener: PushRuleListener)

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.raw
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* Useful methods to fetch raw data from the server. The access token will not be used to fetched the data
*/
@@ -26,17 +23,15 @@ interface RawService {
/**
* Get a URL, either from cache or from the remote server, depending on the cache strategy
*/
fun getUrl(url: String,
rawCacheStrategy: RawCacheStrategy,
matrixCallback: MatrixCallback<String>): Cancelable
suspend fun getUrl(url: String, rawCacheStrategy: RawCacheStrategy): String
/**
* Specific case for the well-known file. Cache validity is 8 hours
*/
fun getWellknown(userId: String, matrixCallback: MatrixCallback<String>): Cancelable
suspend fun getWellknown(userId: String): String
/**
* Clear all the cache data
*/
fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable
suspend fun clearCache()
}

View File

@@ -238,4 +238,9 @@ interface Session :
}
val sharedSecretStorageService: SharedSecretStorageService
/**
* Maintenance API, allows to print outs info on DB size to logcat
*/
fun logDbUsageInfo()
}

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.session.account
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to manage the account. It's implemented at the session level.
*/
@@ -28,7 +25,7 @@ interface AccountService {
* @param password Current password.
* @param newPassword New password
*/
fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable
suspend fun changePassword(password: String, newPassword: String)
/**
* Deactivate the account.
@@ -46,5 +43,5 @@ interface AccountService {
* @param eraseAllData set to true to forget all messages that have been sent. Warning: this will cause future users to see
* an incomplete view of conversations
*/
fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback<Unit>): Cancelable
suspend fun deactivateAccount(password: String, eraseAllData: Boolean)
}

View File

@@ -155,4 +155,6 @@ interface CryptoService {
// For testing shared session
fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int>
fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
fun logDbUsageInfo()
}

View File

@@ -41,7 +41,7 @@ interface VerificationService {
fun getExistingTransaction(otherUserId: String, tid: String): VerificationTransaction?
fun getExistingVerificationRequest(otherUserId: String): List<PendingVerificationRequest>?
fun getExistingVerificationRequests(otherUserId: String): List<PendingVerificationRequest>
fun getExistingVerificationRequest(otherUserId: String, tid: String?): PendingVerificationRequest?

View File

@@ -56,6 +56,7 @@ object EventType {
const val STATE_ROOM_RELATED_GROUPS = "m.room.related_groups"
const val STATE_ROOM_PINNED_EVENT = "m.room.pinned_events"
const val STATE_ROOM_ENCRYPTION = "m.room.encryption"
const val STATE_ROOM_SERVER_ACL = "m.room.server_acl"
// Call Events
const val CALL_INVITE = "m.call.invite"

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.session.group
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to interact within a group.
*/
@@ -28,8 +25,7 @@ interface Group {
/**
* This methods allows you to refresh data about this group. It will be reflected on the GroupSummary.
* The SDK also takes care of refreshing group data every hour.
* @param callback : the matrix callback to be notified of success or failure
* @return a Cancelable to be able to cancel requests.
*/
fun fetchGroupData(callback: MatrixCallback<Unit>): Cancelable
suspend fun fetchGroupData()
}

View File

@@ -92,9 +92,29 @@ interface IdentityService {
/**
* Search MatrixId of users providing email and phone numbers
* Note the the user consent has to be set to true, or it will throw a UserConsentNotProvided failure
* Application has to explicitly ask for the user consent, and the answer can be stored using [setUserConsent]
* Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
*/
fun lookUp(threePids: List<ThreePid>, callback: MatrixCallback<List<FoundThreePid>>): Cancelable
/**
* Return the current user consent for the current identity server, which has been stored using [setUserConsent].
* If [setUserConsent] has not been called, the returned value will be false.
* Note that if the identity server is changed, the user consent is reset to false.
* @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
* has been changed
*/
fun getUserConsent(): Boolean
/**
* Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data
* (email and phone numbers) to the identity server.
* Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
* @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent.
*/
fun setUserConsent(newValue: Boolean)
/**
* Get the status of the current user's threePid
* A lookup will be performed, but also pending binding state will be restored

View File

@@ -24,6 +24,7 @@ sealed class IdentityServiceError : Failure.FeatureFailure() {
object NoIdentityServerConfigured : IdentityServiceError()
object TermsNotSignedException : IdentityServiceError()
object BulkLookupSha256NotSupported : IdentityServiceError()
object UserConsentNotProvided : IdentityServiceError()
object BindingError : IdentityServiceError()
object NoCurrentBindingError : IdentityServiceError()
}

View File

@@ -17,6 +17,7 @@
package org.matrix.android.sdk.api.session.permalinks
import android.text.Spannable
import org.matrix.android.sdk.api.MatrixPatterns
/**
* MatrixLinkify take a piece of text and turns all of the
@@ -35,7 +36,7 @@ object MatrixLinkify {
* 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
@@ -48,14 +49,21 @@ object MatrixLinkify {
val startPos = match.range.first
if (startPos == 0 || text[startPos - 1] != '/') {
val endPos = match.range.last + 1
val url = text.substring(match.range)
var url = text.substring(match.range)
if (MatrixPatterns.isUserId(url)
|| MatrixPatterns.isRoomAlias(url)
|| MatrixPatterns.isRoomId(url)
|| MatrixPatterns.isGroupId(url)
|| MatrixPatterns.isEventId(url)) {
url = PermalinkService.MATRIX_TO_URL_BASE + url
}
val span = MatrixPermalinkSpan(url, callback)
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
return hasMatch
*/
return false
// return false
}
}

View File

@@ -44,13 +44,12 @@ object PermalinkParser {
if (fragment.isNullOrEmpty()) {
return PermalinkData.FallbackLink(uri)
}
val indexOfQuery = fragment.indexOf("?")
val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment
val safeFragment = fragment.substringBefore('?')
val viaQueryParameters = fragment.getViaParameters()
// we are limiting to 2 params
val params = safeFragment
.split(MatrixPatterns.SEP_REGEX.toRegex())
.split(MatrixPatterns.SEP_REGEX)
.filter { it.isNotEmpty() }
.take(2)

View File

@@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.session.room
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.Cancelable
@@ -141,4 +142,20 @@ interface RoomService {
* - the power level of the users are not taken into account. Normally in a DM, the 2 members are admins of the room
*/
fun getExistingDirectRoomWithUser(otherUserId: String): String?
/**
* Get a room member for the tuple {userId,roomId}
* @param userId the userId to look for.
* @param roomId the roomId to look for.
* @return the room member or null
*/
fun getRoomMember(userId: String, roomId: String): RoomMemberSummary?
/**
* Observe a live room member for the tuple {userId,roomId}
* @param userId the userId to look for.
* @param roomId the roomId to look for.
* @return a LiveData of the optional found room member
*/
fun getRoomMemberLive(userId: String, roomId: String): LiveData<Optional<RoomMemberSummary>>
}

View File

@@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.room.crypto
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
interface RoomCryptoService {
@@ -30,6 +29,5 @@ interface RoomCryptoService {
/**
* Enable encryption of the room
*/
fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM,
callback: MatrixCallback<Unit>)
suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM)
}

View File

@@ -22,4 +22,9 @@ import org.matrix.android.sdk.api.failure.MatrixError
sealed class CreateRoomFailure : Failure.FeatureFailure() {
object CreatedWithTimeout : CreateRoomFailure()
data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
sealed class RoomAliasError : CreateRoomFailure() {
object AliasEmpty : RoomAliasError()
object AliasNotAvailable : RoomAliasError()
object AliasInvalid : RoomAliasError()
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.api.session.room.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing the EventType.STATE_ROOM_SERVER_ACL state event content
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#m-room-server-acl
*/
@JsonClass(generateAdapter = true)
data class RoomServerAclContent(
/**
* True to allow server names that are IP address literals. False to deny.
* Defaults to true if missing or otherwise not a boolean.
* This is strongly recommended to be set to false as servers running with IP literal names are strongly
* discouraged in order to require legitimate homeservers to be backed by a valid registered domain name.
*/
@Json(name = "allow_ip_literals")
val allowIpLiterals: Boolean = true,
/**
* The server names to allow in the room, excluding any port information. Wildcards may be used to cover
* a wider range of hosts, where * matches zero or more characters and ? matches exactly one character.
*
* This defaults to an empty list when not provided, effectively disallowing every server.
*/
@Json(name = "allow")
val allowList: List<String> = emptyList(),
/**
* The server names to disallow in the room, excluding any port information. Wildcards may be used to cover
* a wider range of hosts, where * matches zero or more characters and ? matches exactly one character.
*
* This defaults to an empty list when not provided.
*/
@Json(name = "deny")
val denyList: List<String> = emptyList()
) {
companion object {
const val ALL = "*"
}
}

View File

@@ -94,7 +94,22 @@ class CreateRoomParams {
* The server will clobber the following keys: creator.
* Future versions of the specification may allow the server to clobber other keys.
*/
var creationContent: Any? = null
val creationContent = mutableMapOf<String, Any>()
/**
* Set to true to disable federation of this room.
* Default: false
*/
var disableFederation = false
set(value) {
field = value
if (value) {
creationContent[CREATION_CONTENT_KEY_M_FEDERATE] = false
} else {
// This is the default value, we remove the field
creationContent.remove(CREATION_CONTENT_KEY_M_FEDERATE)
}
}
/**
* The power level content to override in the default power level event
@@ -120,4 +135,8 @@ class CreateRoomParams {
fun enableEncryption() {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}
companion object {
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
}
}

View File

@@ -17,12 +17,10 @@
package org.matrix.android.sdk.api.session.room.notification
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
interface RoomPushRuleService {
fun getLiveRoomNotificationState(): LiveData<RoomNotificationState>
fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback<Unit>): Cancelable
suspend fun setRoomNotificationState(roomNotificationState: RoomNotificationState)
}

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.session.room.reporting
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to report content of an event.
*/
@@ -28,5 +25,5 @@ interface ReportingService {
* Report content
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-rooms-roomid-report-eventid
*/
fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback<Unit>): Cancelable
suspend fun reportContent(eventId: String, score: Int, reason: String)
}

View File

@@ -17,8 +17,6 @@
package org.matrix.android.sdk.api.session.room.send
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.api.util.Optional
interface DraftService {
@@ -26,12 +24,12 @@ interface DraftService {
/**
* Save or update a draft to the room
*/
fun saveDraft(draft: UserDraft, callback: MatrixCallback<Unit>): Cancelable
suspend fun saveDraft(draft: UserDraft)
/**
* Delete the last draft, basically just after sending the message
*/
fun deleteDraft(callback: MatrixCallback<Unit>): Cancelable
suspend fun deleteDraft()
/**
* Return the current draft or null

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.session.room.tags
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to handle tags of a room. It's implemented at the room level.
*/
@@ -26,10 +23,10 @@ interface TagsService {
/**
* Add a tag to a room
*/
fun addTag(tag: String, order: Double?, callback: MatrixCallback<Unit>): Cancelable
suspend fun addTag(tag: String, order: Double?)
/**
* Remove tag from a room
*/
fun deleteTag(tag: String, callback: MatrixCallback<Unit>): Cancelable
suspend fun deleteTag(tag: String)
}

View File

@@ -16,9 +16,6 @@
package org.matrix.android.sdk.api.session.search
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines methods to search messages in rooms.
*/
@@ -35,15 +32,13 @@ interface SearchService {
* @param beforeLimit how many events before the result are returned.
* @param afterLimit how many events after the result are returned.
* @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned.
* @param callback Callback to get the search result
*/
fun search(searchTerm: String,
roomId: String,
nextBatch: String?,
orderByRecent: Boolean,
limit: Int,
beforeLimit: Int,
afterLimit: Int,
includeProfile: Boolean,
callback: MatrixCallback<SearchResult>): Cancelable
suspend fun search(searchTerm: String,
roomId: String,
nextBatch: String?,
orderByRecent: Boolean,
limit: Int,
beforeLimit: Int,
afterLimit: Int,
includeProfile: Boolean): SearchResult
}

View File

@@ -35,6 +35,11 @@ interface UserService {
*/
fun getUser(userId: String): User?
/**
* Try to resolve user from known users, or using profile api
*/
fun resolveUser(userId: String, callback: MatrixCallback<User>)
/**
* Search list of users on server directory.
* @param search the searched term

View File

@@ -123,6 +123,7 @@ internal abstract class CryptoModule {
}
.name("crypto_store.realm")
.modules(RealmCryptoStoreModule())
.allowWritesOnUiThread(true)
.schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION)
.migration(realmCryptoStoreMigration)
.build()

View File

@@ -314,6 +314,10 @@ internal class DefaultCryptoService @Inject constructor(
}
// Just update
fetchDevicesList(NoOpMatrixCallback())
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
cryptoStore.tidyUpDataBase()
}
}
fun ensureDevice() {
@@ -763,9 +767,9 @@ internal class DefaultCryptoService @Inject constructor(
*/
private fun onRoomKeyEvent(event: Event) {
val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
Timber.v("## CRYPTO | GOSSIP onRoomKeyEvent() : type<${event.getClearType()}> , sessionId<${roomKeyContent.sessionId}>")
Timber.i("## CRYPTO | onRoomKeyEvent() from: ${event.senderId} type<${event.getClearType()}> , sessionId<${roomKeyContent.sessionId}>")
if (roomKeyContent.roomId.isNullOrEmpty() || roomKeyContent.algorithm.isNullOrEmpty()) {
Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : missing fields")
Timber.e("## CRYPTO | onRoomKeyEvent() : missing fields")
return
}
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
@@ -778,20 +782,20 @@ internal class DefaultCryptoService @Inject constructor(
private fun onKeyWithHeldReceived(event: Event) {
val withHeldContent = event.getClearContent().toModel<RoomKeyWithHeldContent>() ?: return Unit.also {
Timber.e("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
}
Timber.d("## CRYPTO | onKeyWithHeldReceived() received : content <$withHeldContent>")
Timber.i("## CRYPTO | onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
if (alg is IMXWithHeldExtension) {
alg.onRoomKeyWithHeldEvent(withHeldContent)
} else {
Timber.e("## CRYPTO | onKeyWithHeldReceived() : Unable to handle WithHeldContent for ${withHeldContent.algorithm}")
Timber.e("## CRYPTO | onKeyWithHeldReceived() from:${event.senderId}: Unable to handle WithHeldContent for ${withHeldContent.algorithm}")
return
}
}
private fun onSecretSendReceived(event: Event) {
Timber.i("## CRYPTO | GOSSIP onSecretSend() : onSecretSendReceived ${event.content?.get("sender_key")}")
Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
if (!event.isEncrypted()) {
// secret send messages must be encrypted
Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
@@ -1291,6 +1295,11 @@ internal class DefaultCryptoService @Inject constructor(
override fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? {
return cryptoStore.getWithHeldMegolmSession(roomId, sessionId)
}
override fun logDbUsageInfo() {
cryptoStore.logDbUsageInfo()
}
/* ==========================================================================================
* For test only
* ========================================================================================== */

View File

@@ -119,7 +119,7 @@ internal class EventDecryptor @Inject constructor(
markOlmSessionForUnwedging(event.senderId ?: "", it)
}
?: run {
Timber.v("## CRYPTO | markOlmSessionForUnwedging() : Failed to find sender crypto device")
Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
}
}
}
@@ -137,16 +137,18 @@ internal class EventDecryptor @Inject constructor(
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
val now = System.currentTimeMillis()
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
return
}
Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
// offload this from crypto thread (?)
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
// Now send a blank message on that session so the other side knows about it.
// (The keyshare request is sent in the clear so that won't do)
@@ -159,10 +161,14 @@ internal class EventDecryptor @Inject constructor(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
withContext(coroutineDispatchers.io) {
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
sendToDeviceTask.execute(sendToDeviceParams)
try {
sendToDeviceTask.execute(sendToDeviceParams)
} catch (failure: Throwable) {
Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
}
}
}
}

View File

@@ -54,6 +54,7 @@ internal class IncomingGossipingRequestManager @Inject constructor(
private val cryptoCoroutineScope: CoroutineScope) {
private val executor = Executors.newSingleThreadExecutor()
// list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations
// we received in the current sync.
private val receivedGossipingRequests = ArrayList<IncomingShareRequestCommon>()
@@ -103,11 +104,11 @@ internal class IncomingGossipingRequestManager @Inject constructor(
* @param event the announcement event.
*/
fun onGossipingRequestEvent(event: Event) {
Timber.v("## CRYPTO | GOSSIP onGossipingRequestEvent type ${event.type} from user ${event.senderId}")
val roomKeyShare = event.getClearContent().toModel<GossipingDefaultContent>()
Timber.i("## CRYPTO | GOSSIP onGossipingRequestEvent received type ${event.type} from user:${event.senderId}, content:$roomKeyShare")
// val ageLocalTs = event.unsignedData?.age?.let { System.currentTimeMillis() - it }
when (roomKeyShare?.action) {
GossipingToDeviceObject.ACTION_SHARE_REQUEST -> {
GossipingToDeviceObject.ACTION_SHARE_REQUEST -> {
if (event.getClearType() == EventType.REQUEST_SECRET) {
IncomingSecretShareRequest.fromEvent(event)?.let {
if (event.senderId == credentials.userId && it.deviceId == credentials.deviceId) {
@@ -324,7 +325,7 @@ internal class IncomingGossipingRequestManager @Inject constructor(
val isDeviceLocallyVerified = cryptoStore.getUserDevice(userId, deviceId)?.trustLevel?.isLocallyVerified()
when (secretName) {
MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master
MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master
SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned
USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user
KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey

View File

@@ -760,7 +760,7 @@ internal class MXOlmDevice @Inject constructor(
return session
}
} else {
Timber.v("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
Timber.w("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID, MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON)
}
}

View File

@@ -100,7 +100,7 @@ internal class SendGossipWorker(context: Context,
requestId = params.requestId,
state = GossipingRequestState.FAILED_TO_ACCEPTED
)
Timber.e("no session with this device, probably because there were no one-time keys.")
Timber.e("no session with this device $requestingDeviceId, probably because there were no one-time keys.")
}
}

View File

@@ -69,7 +69,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
//
// That should eventually resolve itself, but it's poor form.
Timber.v("## CRYPTO | claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
Timber.i("## CRYPTO | claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim)
val oneTimeKeys = oneTimeKeysForUsersDeviceTask.execute(claimParams)
@@ -90,7 +90,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
oneTimeKey = key
}
if (oneTimeKey == null) {
Timber.v("## CRYPTO | ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
Timber.w("## CRYPTO | ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
+ " for device " + userId + " : " + deviceId)
continue
}

View File

@@ -243,8 +243,7 @@ internal class MXMegolmDecryption(private val userId: String,
return
}
if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
Timber.v("## CRYPTO | onRoomKeyEvent(), forward adding key : roomId ${roomKeyContent.roomId}" +
" sessionId ${roomKeyContent.sessionId} sessionKey ${roomKeyContent.sessionKey}")
Timber.i("## CRYPTO | onRoomKeyEvent(), forward adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()
?: return
@@ -273,9 +272,7 @@ internal class MXMegolmDecryption(private val userId: String,
keysClaimed["ed25519"] = forwardedRoomKeyContent.senderClaimedEd25519Key
} else {
Timber.v("## CRYPTO | onRoomKeyEvent(), Adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId
+ " sessionKey " + roomKeyContent.sessionKey) // from " + event);
Timber.i("## CRYPTO | onRoomKeyEvent(), Adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
if (null == senderKey) {
Timber.e("## onRoomKeyEvent() : key event has no sender key (not encrypted?)")
return
@@ -285,7 +282,7 @@ internal class MXMegolmDecryption(private val userId: String,
keysClaimed = event.getKeysClaimed().toMutableMap()
}
Timber.e("## CRYPTO | onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
Timber.i("## CRYPTO | onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId,
roomKeyContent.sessionKey,
roomKeyContent.roomId,
@@ -349,10 +346,10 @@ internal class MXMegolmDecryption(private val userId: String,
if (olmSessionResult?.sessionId == null) {
// no session with this device, probably because there
// were no one-time keys.
Timber.e("no session with this device $deviceId, probably because there were no one-time keys.")
return@mapCatching
}
Timber.v("## CRYPTO | shareKeysWithDevice() : sharing keys for session" +
" ${body.senderKey}|${body.sessionId} with device $userId:$deviceId")
Timber.i("## CRYPTO | shareKeysWithDevice() : sharing session ${body.sessionId} with device $userId:$deviceId")
val payloadJson = mutableMapOf<String, Any>("type" to EventType.FORWARDED_ROOM_KEY)
runCatching { olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId) }
@@ -363,6 +360,7 @@ internal class MXMegolmDecryption(private val userId: String,
},
{
// TODO
Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
}
)
@@ -370,9 +368,13 @@ internal class MXMegolmDecryption(private val userId: String,
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
Timber.v("## CRYPTO | shareKeysWithDevice() : sending to $userId:$deviceId")
Timber.i("## CRYPTO | shareKeysWithDevice() : sending ${body.sessionId} to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
sendToDeviceTask.execute(sendToDeviceParams)
try {
sendToDeviceTask.execute(sendToDeviceParams)
} catch (failure: Throwable) {
Timber.e(failure, "## CRYPTO | shareKeysWithDevice() : Failed to send ${body.sessionId} to $userId:$deviceId")
}
}
}
}

View File

@@ -217,8 +217,10 @@ internal class MXMegolmEncryption(
Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
Timber.v("## CRYPTO | shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
+ (System.currentTimeMillis() - t0) + " ms")
Timber.v(
"""## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
.trimMargin()
)
val contentMap = MXUsersDevicesMap<Any>()
var haveTargets = false
val userIds = results.userIds
@@ -242,7 +244,7 @@ internal class MXMegolmEncryption(
continue
}
Timber.v("## CRYPTO | shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
Timber.i("## CRYPTO | shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
haveTargets = true
}
@@ -270,21 +272,22 @@ internal class MXMegolmEncryption(
if (haveTargets) {
t0 = System.currentTimeMillis()
Timber.v("## CRYPTO | shareUserDevicesKey() : has target")
Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
try {
sendToDeviceTask.execute(sendToDeviceParams)
Timber.v("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
} catch (failure: Throwable) {
// What to do here...
Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
}
} else {
Timber.v("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
}
}
private fun notifyKeyWithHeld(targets: List<UserDevice>, sessionId: String, senderKey: String?, code: WithHeldCode) {
Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId ")
val withHeldContent = RoomKeyWithHeldContent(
roomId = roomId,
senderKey = senderKey,
@@ -393,16 +396,16 @@ internal class MXMegolmEncryption(
userId: String,
deviceId: String,
senderKey: String): Boolean {
Timber.d("[MXMegolmEncryption] reshareKey: $sessionId to $userId:$deviceId")
Timber.i("## Crypto process reshareKey for $sessionId to $userId:$deviceId")
val deviceInfo = cryptoStore.getUserDevice(userId, deviceId) ?: return false
.also { Timber.w("Device not found") }
.also { Timber.w("## Crypto reshareKey: Device not found") }
// Get the chain index of the key we previously sent this device
val chainIndex = outboundSession?.sharedWithHelper?.wasSharedWith(userId, deviceId) ?: return false
.also {
// Send a room key with held
notifyKeyWithHeld(listOf(UserDevice(userId, deviceId)), sessionId, senderKey, WithHeldCode.UNAUTHORISED)
Timber.w("[MXMegolmEncryption] reshareKey : ERROR : Never share megolm with this device")
Timber.w("## Crypto reshareKey: ERROR : Never share megolm with this device")
}
val devicesByUser = mapOf(userId to listOf(deviceInfo))
@@ -411,9 +414,11 @@ internal class MXMegolmEncryption(
olmSessionResult?.sessionId
?: // no session with this device, probably because there were no one-time keys.
// ensureOlmSessionsForDevicesAction has already done the logging, so just skip it.
return false
return false.also {
Timber.w("## Crypto reshareKey: no session with this device, probably because there were no one-time keys")
}
Timber.d("[MXMegolmEncryption] reshareKey: sharing keys for session $senderKey|$sessionId:$chainIndex with device $userId:$deviceId")
Timber.i("[MXMegolmEncryption] reshareKey: sharing keys for session $senderKey|$sessionId:$chainIndex with device $userId:$deviceId")
val payloadJson = mutableMapOf<String, Any>("type" to EventType.FORWARDED_ROOM_KEY)
@@ -425,6 +430,7 @@ internal class MXMegolmEncryption(
},
{
// TODO
Timber.e(it, "[MXMegolmEncryption] reshareKey: failed to get session $sessionId|$senderKey|$roomId")
}
)
@@ -432,13 +438,14 @@ internal class MXMegolmEncryption(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
Timber.v("## CRYPTO | CRYPTO | reshareKey() : sending to $userId:$deviceId")
Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
return try {
sendToDeviceTask.execute(sendToDeviceParams)
Timber.i("## CRYPTO reshareKey() : successfully send <$sessionId> to $userId:$deviceId")
true
} catch (failure: Throwable) {
Timber.e(failure, "## CRYPTO | CRYPTO | reshareKey() : fail to send <$sessionId> to $userId:$deviceId")
Timber.e(failure, "## CRYPTO reshareKey() : fail to send <$sessionId> to $userId:$deviceId")
false
}
}

View File

@@ -38,7 +38,6 @@ import org.matrix.android.sdk.internal.task.TaskThread
import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.util.withoutPrefix
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
@@ -444,7 +443,7 @@ internal class DefaultCrossSigningService @Inject constructor(
} else {
// Maybe it's signed by a locally trusted device?
myMasterKey.signatures?.get(userId)?.forEach { (key, value) ->
val potentialDeviceId = key.withoutPrefix("ed25519:")
val potentialDeviceId = key.removePrefix("ed25519:")
val potentialDevice = myDevices?.firstOrNull { it.deviceId == potentialDeviceId } // cryptoStore.getUserDevice(userId, potentialDeviceId)
if (potentialDevice != null && potentialDevice.isVerified) {
// Check signature validity?

View File

@@ -241,9 +241,9 @@ internal class UpdateTrustWorker(context: Context,
private fun computeRoomShield(activeMemberUserIds: List<String>, roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> $activeMemberUserIds")
// The set of “all users” depends on the type of room:
// For regular / topic rooms, all users including yourself, are considered when decorating a room
// For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
// For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
val listToCheck = if (roomSummaryEntity.isDirect) {
val listToCheck = if (roomSummaryEntity.isDirect || activeMemberUserIds.size <= 2) {
activeMemberUserIds.filter { it != myUserId }
} else {
activeMemberUserIds

View File

@@ -30,7 +30,6 @@ import org.matrix.android.sdk.api.listeners.StepProgressListener
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
@@ -85,6 +84,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
import org.matrix.olm.OlmException
import org.matrix.olm.OlmPkDecryption
import org.matrix.olm.OlmPkEncryption
@@ -170,7 +170,7 @@ internal class DefaultKeysBackupService @Inject constructor(
runCatching {
withContext(coroutineDispatchers.crypto) {
val olmPkDecryption = OlmPkDecryption()
val megolmBackupAuthData = if (password != null) {
val signalableMegolmBackupAuthData = if (password != null) {
// Generate a private key from the password
val backgroundProgressListener = if (progressListener == null) {
null
@@ -189,7 +189,7 @@ internal class DefaultKeysBackupService @Inject constructor(
}
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
MegolmBackupAuthData(
SignalableMegolmBackupAuthData(
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
privateKeySalt = generatePrivateKeyResult.salt,
privateKeyIterations = generatePrivateKeyResult.iterations
@@ -197,14 +197,17 @@ internal class DefaultKeysBackupService @Inject constructor(
} else {
val publicKey = olmPkDecryption.generateKey()
MegolmBackupAuthData(
SignalableMegolmBackupAuthData(
publicKey = publicKey
)
}
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
val signedMegolmBackupAuthData = megolmBackupAuthData.copy(
val signedMegolmBackupAuthData = MegolmBackupAuthData(
publicKey = signalableMegolmBackupAuthData.publicKey,
privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
signatures = objectSigner.signObject(canonicalJson)
)
@@ -223,8 +226,7 @@ internal class DefaultKeysBackupService @Inject constructor(
@Suppress("UNCHECKED_CAST")
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
algorithm = keysBackupCreationInfo.algorithm,
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
authData = keysBackupCreationInfo.authData.toJsonDict()
)
keysBackupStateManager.state = KeysBackupState.Enabling
@@ -245,7 +247,7 @@ internal class DefaultKeysBackupService @Inject constructor(
version = data.version,
// We can consider that the server does not have keys yet
count = 0,
hash = null
hash = ""
)
enableKeysBackup(keyBackupVersion)
@@ -267,7 +269,7 @@ internal class DefaultKeysBackupService @Inject constructor(
withContext(coroutineDispatchers.crypto) {
// If we're currently backing up to this backup... stop.
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
if (keysBackupVersion != null && version == keysBackupVersion!!.version) {
if (keysBackupVersion != null && version == keysBackupVersion?.version) {
resetKeysBackupData()
keysBackupVersion = null
keysBackupStateManager.state = KeysBackupState.Unknown
@@ -408,10 +410,7 @@ internal class DefaultKeysBackupService @Inject constructor(
val keysBackupVersionTrust = KeysBackupVersionTrust()
val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData()
if (keysBackupVersion.algorithm == null
|| authData == null
|| authData.publicKey.isEmpty()
|| authData.signatures.isNullOrEmpty()) {
if (authData == null || authData.publicKey.isEmpty() || authData.signatures.isEmpty()) {
Timber.v("getKeysBackupTrust: Key backup is absent or missing required data")
return keysBackupVersionTrust
}
@@ -479,7 +478,7 @@ internal class DefaultKeysBackupService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
// Get current signatures, or create an empty set
val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap() ?: HashMap()
val myUserSignatures = authData.signatures[userId].orEmpty().toMutableMap()
if (trust) {
// Add current device signature
@@ -498,26 +497,23 @@ internal class DefaultKeysBackupService @Inject constructor(
// Create an updated version of KeysVersionResult
val newMegolmBackupAuthData = authData.copy()
val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap()
val newSignatures = newMegolmBackupAuthData.signatures.toMutableMap()
newSignatures[userId] = myUserSignatures
val newMegolmBackupAuthDataWithNewSignature = newMegolmBackupAuthData.copy(
signatures = newSignatures
)
val moshi = MoshiProvider.providesMoshi()
val adapter = moshi.adapter(Map::class.java)
@Suppress("UNCHECKED_CAST")
UpdateKeysBackupVersionBody(
algorithm = keysBackupVersion.algorithm,
authData = adapter.fromJson(newMegolmBackupAuthDataWithNewSignature.toJsonString()) as Map<String, Any>?,
version = keysBackupVersion.version!!)
authData = newMegolmBackupAuthDataWithNewSignature.toJsonDict(),
version = keysBackupVersion.version)
}
// And send it to the homeserver
updateKeysBackupVersionTask
.configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version!!, updateKeysBackupVersionBody)) {
.configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, updateKeysBackupVersionBody)) {
this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
// Relaunch the state machine on this updated backup version
@@ -688,7 +684,7 @@ internal class DefaultKeysBackupService @Inject constructor(
stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey)
// Get backed up keys from the homeserver
val data = getKeys(sessionId, roomId, keysVersionResult.version!!)
val data = getKeys(sessionId, roomId, keysVersionResult.version)
withContext(coroutineDispatchers.computation) {
val sessionsData = ArrayList<MegolmSessionData>()
@@ -1023,19 +1019,10 @@ internal class DefaultKeysBackupService @Inject constructor(
* @return the authentication if found and valid, null in other case
*/
private fun getMegolmBackupAuthData(keysBackupData: KeysVersionResult): MegolmBackupAuthData? {
if (keysBackupData.version.isNullOrBlank()
|| keysBackupData.algorithm != MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|| keysBackupData.authData == null) {
return null
}
val authData = keysBackupData.getAuthDataAsMegolmBackupAuthData()
if (authData?.signatures == null || authData.publicKey.isBlank()) {
return null
}
return authData
return keysBackupData
.takeIf { it.version.isNotEmpty() && it.algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP }
?.getAuthDataAsMegolmBackupAuthData()
?.takeIf { it.publicKey.isNotEmpty() }
}
/**
@@ -1123,34 +1110,29 @@ internal class DefaultKeysBackupService @Inject constructor(
* @param keysVersionResult backup information object as returned by [getCurrentVersion].
*/
private fun enableKeysBackup(keysVersionResult: KeysVersionResult) {
if (keysVersionResult.authData != null) {
val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData()
val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData()
if (retrievedMegolmBackupAuthData != null) {
keysBackupVersion = keysVersionResult
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
cryptoStore.setKeyBackupVersion(keysVersionResult.version)
}
onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash)
try {
backupOlmPkEncryption = OlmPkEncryption().apply {
setRecipientKey(retrievedMegolmBackupAuthData.publicKey)
}
} catch (e: OlmException) {
Timber.e(e, "OlmException")
keysBackupStateManager.state = KeysBackupState.Disabled
return
}
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
maybeBackupKeys()
} else {
Timber.e("Invalid authentication data")
keysBackupStateManager.state = KeysBackupState.Disabled
if (retrievedMegolmBackupAuthData != null) {
keysBackupVersion = keysVersionResult
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
cryptoStore.setKeyBackupVersion(keysVersionResult.version)
}
onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash)
try {
backupOlmPkEncryption = OlmPkEncryption().apply {
setRecipientKey(retrievedMegolmBackupAuthData.publicKey)
}
} catch (e: OlmException) {
Timber.e(e, "OlmException")
keysBackupStateManager.state = KeysBackupState.Disabled
return
}
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
maybeBackupKeys()
} else {
Timber.e("Invalid authentication data")
keysBackupStateManager.state = KeysBackupState.Disabled
@@ -1160,11 +1142,11 @@ internal class DefaultKeysBackupService @Inject constructor(
/**
* Update the DB with data fetch from the server
*/
private fun onServerDataRetrieved(count: Int?, hash: String?) {
private fun onServerDataRetrieved(count: Int?, etag: String?) {
cryptoStore.setKeysBackupData(KeysBackupDataEntity()
.apply {
backupLastServerNumberOfKeys = count
backupLastServerHash = hash
backupLastServerHash = etag
}
)
}
@@ -1179,6 +1161,7 @@ internal class DefaultKeysBackupService @Inject constructor(
cryptoStore.setKeyBackupVersion(null)
cryptoStore.setKeysBackupData(null)
backupOlmPkEncryption?.releaseEncryption()
backupOlmPkEncryption = null
// Reset backup markers
@@ -1229,22 +1212,19 @@ internal class DefaultKeysBackupService @Inject constructor(
// Gather data to send to the homeserver
// roomId -> sessionId -> MXKeyBackupData
val keysBackupData = KeysBackupData(
roomIdToRoomKeysBackupData = HashMap()
)
val keysBackupData = KeysBackupData()
for (olmInboundGroupSessionWrapper in olmInboundGroupSessionWrappers) {
val keyBackupData = encryptGroupSession(olmInboundGroupSessionWrapper)
if (keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId] == null) {
val roomKeysBackupData = RoomKeysBackupData(
sessionIdToKeyBackupData = HashMap()
)
keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId!!] = roomKeysBackupData
}
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
val roomId = olmInboundGroupSessionWrapper.roomId ?: return@forEach
val olmInboundGroupSession = olmInboundGroupSessionWrapper.olmInboundGroupSession ?: return@forEach
try {
keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId]!!
.sessionIdToKeyBackupData[olmInboundGroupSessionWrapper.olmInboundGroupSession!!.sessionIdentifier()] = keyBackupData
encryptGroupSession(olmInboundGroupSessionWrapper)
?.let {
keysBackupData.roomIdToRoomKeysBackupData
.getOrPut(roomId) { RoomKeysBackupData() }
.sessionIdToKeyBackupData[olmInboundGroupSession.sessionIdentifier()] = it
}
} catch (e: OlmException) {
Timber.e(e, "OlmException")
}
@@ -1252,71 +1232,71 @@ internal class DefaultKeysBackupService @Inject constructor(
Timber.v("backupKeys: 4 - Sending request")
val sendingRequestCallback = object : MatrixCallback<BackupKeysResult> {
override fun onSuccess(data: BackupKeysResult) {
uiHandler.post {
Timber.v("backupKeys: 5a - Request complete")
// Make the request
val version = keysBackupVersion?.version ?: return@withContext
// Mark keys as backed up
cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
storeSessionDataTask
.configureWith(StoreSessionsDataTask.Params(version, keysBackupData)) {
this.callback = object : MatrixCallback<BackupKeysResult> {
override fun onSuccess(data: BackupKeysResult) {
uiHandler.post {
Timber.v("backupKeys: 5a - Request complete")
if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
Timber.v("backupKeys: All keys have been backed up")
onServerDataRetrieved(data.count, data.hash)
// Mark keys as backed up
cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
// Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess()
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
} else {
Timber.v("backupKeys: Continue to back up keys")
keysBackupStateManager.state = KeysBackupState.WillBackUp
if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
Timber.v("backupKeys: All keys have been backed up")
onServerDataRetrieved(data.count, data.hash)
backupKeys()
}
}
}
// Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess()
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
} else {
Timber.v("backupKeys: Continue to back up keys")
keysBackupStateManager.state = KeysBackupState.WillBackUp
override fun onFailure(failure: Throwable) {
if (failure is Failure.ServerError) {
uiHandler.post {
Timber.e(failure, "backupKeys: backupKeys failed.")
when (failure.error.code) {
MatrixError.M_NOT_FOUND,
MatrixError.M_WRONG_ROOM_KEYS_VERSION -> {
// Backup has been deleted on the server, or we are not using the last backup version
keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion
backupAllGroupSessionsCallback?.onFailure(failure)
resetBackupAllGroupSessionsListeners()
resetKeysBackupData()
keysBackupVersion = null
// Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
checkAndStartKeysBackup()
backupKeys()
}
}
}
override fun onFailure(failure: Throwable) {
if (failure is Failure.ServerError) {
uiHandler.post {
Timber.e(failure, "backupKeys: backupKeys failed.")
when (failure.error.code) {
MatrixError.M_NOT_FOUND,
MatrixError.M_WRONG_ROOM_KEYS_VERSION -> {
// Backup has been deleted on the server, or we are not using the last backup version
keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion
backupAllGroupSessionsCallback?.onFailure(failure)
resetBackupAllGroupSessionsListeners()
resetKeysBackupData()
keysBackupVersion = null
// Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
checkAndStartKeysBackup()
}
else ->
// Come back to the ready state so that we will retry on the next received key
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
}
}
} else {
uiHandler.post {
backupAllGroupSessionsCallback?.onFailure(failure)
resetBackupAllGroupSessionsListeners()
Timber.e("backupKeys: backupKeys failed.")
// Retry a bit later
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
maybeBackupKeys()
}
}
else ->
// Come back to the ready state so that we will retry on the next received key
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
}
}
} else {
uiHandler.post {
backupAllGroupSessionsCallback?.onFailure(failure)
resetBackupAllGroupSessionsListeners()
Timber.e("backupKeys: backupKeys failed.")
// Retry a bit later
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
maybeBackupKeys()
}
}
}
}
// Make the request
storeSessionDataTask
.configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData)) {
this.callback = sendingRequestCallback
}
.executeBy(taskExecutor)
}
@@ -1325,47 +1305,45 @@ internal class DefaultKeysBackupService @Inject constructor(
@VisibleForTesting
@WorkerThread
fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData {
fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData? {
// Gather information for each key
val device = cryptoStore.deviceWithIdentityKey(olmInboundGroupSessionWrapper.senderKey!!)
val device = olmInboundGroupSessionWrapper.senderKey?.let { cryptoStore.deviceWithIdentityKey(it) }
// Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at
// https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format
val sessionData = olmInboundGroupSessionWrapper.exportKeys()
val sessionData = olmInboundGroupSessionWrapper.exportKeys() ?: return null
val sessionBackupData = mapOf(
"algorithm" to sessionData!!.algorithm,
"algorithm" to sessionData.algorithm,
"sender_key" to sessionData.senderKey,
"sender_claimed_keys" to sessionData.senderClaimedKeys,
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain
?: ArrayList<Any>()),
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
"session_key" to sessionData.sessionKey)
var encryptedSessionBackupData: OlmPkMessage? = null
val json = MoshiProvider.providesMoshi()
.adapter(Map::class.java)
.toJson(sessionBackupData)
val moshi = MoshiProvider.providesMoshi()
val adapter = moshi.adapter(Map::class.java)
try {
val json = adapter.toJson(sessionBackupData)
encryptedSessionBackupData = backupOlmPkEncryption?.encrypt(json)
val encryptedSessionBackupData = try {
backupOlmPkEncryption?.encrypt(json)
} catch (e: OlmException) {
Timber.e(e, "OlmException")
null
}
?: return null
// Build backup data for that key
return KeyBackupData(
firstMessageIndex = try {
olmInboundGroupSessionWrapper.olmInboundGroupSession!!.firstKnownIndex
olmInboundGroupSessionWrapper.olmInboundGroupSession?.firstKnownIndex ?: 0
} catch (e: OlmException) {
Timber.e(e, "OlmException")
0L
},
forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain!!.size,
forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain.orEmpty().size,
isVerified = device?.isVerified == true,
sessionData = mapOf(
"ciphertext" to encryptedSessionBackupData!!.mCipherText,
"ciphertext" to encryptedSessionBackupData.mCipherText,
"mac" to encryptedSessionBackupData.mMac,
"ephemeral" to encryptedSessionBackupData.mEphemeralKey)
)
@@ -1378,9 +1356,9 @@ internal class DefaultKeysBackupService @Inject constructor(
val jsonObject = keyBackupData.sessionData
val ciphertext = jsonObject?.get("ciphertext")?.toString()
val mac = jsonObject?.get("mac")?.toString()
val ephemeralKey = jsonObject?.get("ephemeral")?.toString()
val ciphertext = jsonObject["ciphertext"]?.toString()
val mac = jsonObject["mac"]?.toString()
val ephemeralKey = jsonObject["ephemeral"]?.toString()
if (ciphertext != null && mac != null && ephemeralKey != null) {
val encrypted = OlmPkMessage()
@@ -1425,8 +1403,7 @@ internal class DefaultKeysBackupService @Inject constructor(
@Suppress("UNCHECKED_CAST")
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
algorithm = keysBackupCreationInfo.algorithm,
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
authData = keysBackupCreationInfo.authData.toJsonDict()
)
createKeysBackupVersionTask

View File

@@ -35,7 +35,7 @@ import retrofit2.http.Path
import retrofit2.http.Query
/**
* Ref: https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md
* Ref: https://matrix.org/docs/spec/client_server/unstable#server-side-key-backups
*/
internal interface RoomKeysApi {

View File

@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.di.MoshiProvider
/**
@@ -30,7 +31,7 @@ data class MegolmBackupAuthData(
* The curve25519 public key used to encrypt the backups.
*/
@Json(name = "public_key")
val publicKey: String = "",
val publicKey: String,
/**
* In case of a backup created from a password, the salt associated with the backup
@@ -50,20 +51,38 @@ data class MegolmBackupAuthData(
* userId -> (deviceSignKeyId -> signature)
*/
@Json(name = "signatures")
val signatures: Map<String, Map<String, String>>? = null
val signatures: Map<String, Map<String, String>>
) {
fun toJsonString(): String {
return MoshiProvider.providesMoshi()
fun toJsonDict(): JsonDict {
val moshi = MoshiProvider.providesMoshi()
val adapter = moshi.adapter(Map::class.java)
return moshi
.adapter(MegolmBackupAuthData::class.java)
.toJson(this)
.let {
@Suppress("UNCHECKED_CAST")
adapter.fromJson(it) as JsonDict
}
}
/**
* Same as the parent [MXJSONModel JSONDictionary] but return only
* data that must be signed.
*/
fun signalableJSONDictionary(): Map<String, Any> = HashMap<String, Any>().apply {
fun signalableJSONDictionary(): JsonDict {
return SignalableMegolmBackupAuthData(
publicKey = publicKey,
privateKeySalt = privateKeySalt,
privateKeyIterations = privateKeyIterations
)
.signalableJSONDictionary()
}
}
internal data class SignalableMegolmBackupAuthData(
val publicKey: String,
val privateKeySalt: String? = null,
val privateKeyIterations: Int? = null
) {
fun signalableJSONDictionary(): JsonDict = HashMap<String, Any>().apply {
put("public_key", publicKey)
privateKeySalt?.let {

View File

@@ -23,15 +23,15 @@ data class MegolmBackupCreationInfo(
/**
* The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
*/
val algorithm: String = "",
val algorithm: String,
/**
* Authentication data.
*/
val authData: MegolmBackupAuthData? = null,
val authData: MegolmBackupAuthData,
/**
* The Base58 recovery key.
*/
val recoveryKey: String = ""
val recoveryKey: String
)

View File

@@ -16,15 +16,16 @@
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class BackupKeysResult(
internal data class BackupKeysResult(
// The hash value which is an opaque string representing stored keys in the backup
var hash: String? = null,
@Json(name = "etag")
val hash: String,
// The number of keys stored in the backup.
var count: Int? = null
@Json(name = "count")
val count: Int
)

View File

@@ -21,17 +21,17 @@ import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.util.JsonDict
@JsonClass(generateAdapter = true)
data class CreateKeysBackupVersionBody(
internal data class CreateKeysBackupVersionBody(
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
override val algorithm: String,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null
override val authData: JsonDict
) : KeysAlgorithmAndData

View File

@@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.network.parsing.ForceToBoolean
/**
@@ -30,13 +30,13 @@ data class KeyBackupData(
* Required. The index of the first message in the session that the key can decrypt.
*/
@Json(name = "first_message_index")
val firstMessageIndex: Long = 0,
val firstMessageIndex: Long,
/**
* Required. The number of times this key has been forwarded.
*/
@Json(name = "forwarded_count")
val forwardedCount: Int = 0,
val forwardedCount: Int,
/**
* Whether the device backing up the key has verified the device that the key is from.
@@ -44,16 +44,11 @@ data class KeyBackupData(
*/
@ForceToBoolean
@Json(name = "is_verified")
val isVerified: Boolean = false,
val isVerified: Boolean,
/**
* Algorithm-dependent data.
*/
@Json(name = "session_data")
val sessionData: Map<String, Any>? = null
) {
fun toJsonString(): String {
return MoshiProvider.providesMoshi().adapter(KeyBackupData::class.java).toJson(this)
}
}
val sessionData: JsonDict
)

View File

@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
import org.matrix.android.sdk.internal.di.MoshiProvider
@@ -37,24 +38,25 @@ import org.matrix.android.sdk.internal.di.MoshiProvider
* }
* </pre>
*/
interface KeysAlgorithmAndData {
internal interface KeysAlgorithmAndData {
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
val algorithm: String?
val algorithm: String
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
val authData: JsonDict?
val authData: JsonDict
/**
* Facility method to convert authData to a MegolmBackupAuthData object
*/
fun getAuthDataAsMegolmBackupAuthData(): MegolmBackupAuthData? {
return MoshiProvider.providesMoshi()
.adapter(MegolmBackupAuthData::class.java)
.fromJsonValue(authData)
.takeIf { algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP }
?.adapter(MegolmBackupAuthData::class.java)
?.fromJsonValue(authData)
}
}

View File

@@ -23,5 +23,5 @@ import com.squareup.moshi.JsonClass
data class KeysVersion(
// the keys backup version
@Json(name = "version")
val version: String? = null
val version: String
)

View File

@@ -26,24 +26,24 @@ data class KeysVersionResult(
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
override val algorithm: String,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null,
override val authData: JsonDict,
// the backup version
@Json(name = "version")
val version: String? = null,
val version: String,
// The hash value which is an opaque string representing stored keys in the backup
@Json(name = "hash")
val hash: String? = null,
@Json(name = "etag")
val hash: String,
// The number of keys stored in the backup.
@Json(name = "count")
val count: Int? = null
val count: Int
) : KeysAlgorithmAndData

View File

@@ -26,16 +26,16 @@ data class UpdateKeysBackupVersionBody(
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
override val algorithm: String,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null,
override val authData: JsonDict,
// the backup version, mandatory
// Optional. The backup version. If present, must be the same as the path parameter.
@Json(name = "version")
val version: String
val version: String? = null
) : KeysAlgorithmAndData

View File

@@ -48,15 +48,12 @@ class OlmInboundGroupSessionWrapper2 : Serializable {
*/
val firstKnownIndex: Long?
get() {
if (null != olmInboundGroupSession) {
try {
return olmInboundGroupSession!!.firstKnownIndex
} catch (e: Exception) {
Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed")
}
return try {
olmInboundGroupSession?.firstKnownIndex
} catch (e: Exception) {
Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed")
null
}
return null
}
/**
@@ -90,11 +87,13 @@ class OlmInboundGroupSessionWrapper2 : Serializable {
@Throws(Exception::class)
constructor(megolmSessionData: MegolmSessionData) {
try {
olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!)
if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) {
throw Exception("Mismatched group session Id")
}
val safeSessionKey = megolmSessionData.sessionKey ?: throw Exception("invalid data")
olmInboundGroupSession = OlmInboundGroupSession.importSession(safeSessionKey)
.also {
if (it.sessionIdentifier() != megolmSessionData.sessionId) {
throw Exception("Mismatched group session Id")
}
}
senderKey = megolmSessionData.senderKey
keysClaimed = megolmSessionData.senderClaimedKeys
@@ -120,16 +119,18 @@ class OlmInboundGroupSessionWrapper2 : Serializable {
return null
}
val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex
val safeOlmInboundGroupSession = olmInboundGroupSession ?: return null
val wantedIndex = index ?: safeOlmInboundGroupSession.firstKnownIndex
MegolmSessionData(
senderClaimedEd25519Key = keysClaimed?.get("ed25519"),
forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!),
forwardingCurve25519KeyChain = forwardingCurve25519KeyChain?.toList().orEmpty(),
senderKey = senderKey,
senderClaimedKeys = keysClaimed,
roomId = roomId,
sessionId = olmInboundGroupSession!!.sessionIdentifier(),
sessionKey = olmInboundGroupSession!!.export(wantedIndex),
sessionId = safeOlmInboundGroupSession.sessionIdentifier(),
sessionKey = safeOlmInboundGroupSession.export(wantedIndex),
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
)
} catch (e: Exception) {
@@ -145,14 +146,11 @@ class OlmInboundGroupSessionWrapper2 : Serializable {
* @return the exported data
*/
fun exportSession(messageIndex: Long): String? {
if (null != olmInboundGroupSession) {
try {
return olmInboundGroupSession!!.export(messageIndex)
} catch (e: Exception) {
Timber.e(e, "## exportSession() : export failed")
}
return try {
return olmInboundGroupSession?.export(messageIndex)
} catch (e: Exception) {
Timber.e(e, "## exportSession() : export failed")
null
}
return null
}
}

View File

@@ -456,4 +456,6 @@ internal interface IMXCryptoStore {
fun setDeviceKeysUploaded(uploaded: Boolean)
fun getDeviceKeysUploaded(): Boolean
fun tidyUpDataBase()
fun logDbUsageInfo()
}

View File

@@ -87,6 +87,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.get
import org.matrix.android.sdk.internal.crypto.store.db.query.getById
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
import org.matrix.android.sdk.internal.di.CryptoDatabase
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider
@@ -1666,4 +1667,45 @@ internal class RealmCryptoStore @Inject constructor(
result
}
}
/**
* Some entries in the DB can get a bit out of control with time
* So we need to tidy up a bit
*/
override fun tidyUpDataBase() {
val prevWeekTs = System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1_000
doRealmTransaction(realmConfiguration) { realm ->
// Only keep one week history
realm.where<IncomingGossipingRequestEntity>()
.lessThan(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, prevWeekTs)
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity") }
.deleteAllFromRealm()
// Clean the cancelled ones?
realm.where<OutgoingGossipingRequestEntity>()
.equalTo(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, OutgoingGossipingRequestState.CANCELLED.name)
.equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity") }
.deleteAllFromRealm()
// Only keep one week history
realm.where<GossipingEventEntity>()
.lessThan(GossipingEventEntityFields.AGE_LOCAL_TS, prevWeekTs)
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields") }
.deleteAllFromRealm()
// Can we do something for WithHeldSessionEntity?
}
}
/**
* Prints out database info
*/
override fun logDbUsageInfo() {
RealmDebugTools(realmConfiguration).logInfo("Crypto")
}
}

View File

@@ -537,11 +537,10 @@ internal class DefaultVerificationService @Inject constructor(
// If there is a corresponding request, we can auto accept
// as we are the one requesting in first place (or we accepted the request)
// I need to check if the pending request was related to this device also
val autoAccept = getExistingVerificationRequest(otherUserId)?.any {
val autoAccept = getExistingVerificationRequests(otherUserId).any {
it.transactionId == startReq.transactionId
&& (it.requestInfo?.fromDevice == this.deviceId || it.readyInfo?.fromDevice == this.deviceId)
}
?: false
val tx = DefaultIncomingSASDefaultVerificationTransaction(
// this,
setDeviceVerificationAction,
@@ -837,8 +836,8 @@ internal class DefaultVerificationService @Inject constructor(
// SAS do not care for now?
}
// Now transactions are udated, let's also update Requests
val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == doneReq.transactionId }
// Now transactions are updated, let's also update Requests
val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == doneReq.transactionId }
if (existingRequest == null) {
Timber.e("## SAS Received Done for unknown request txId:${doneReq.transactionId}")
return
@@ -892,7 +891,7 @@ internal class DefaultVerificationService @Inject constructor(
private fun handleReadyReceived(senderId: String,
readyReq: ValidVerificationInfoReady,
transportCreator: (DefaultVerificationTransaction) -> VerificationTransport) {
val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == readyReq.transactionId }
val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == readyReq.transactionId }
if (existingRequest == null) {
Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionId} fromDevice ${readyReq.fromDevice}")
return
@@ -1041,9 +1040,9 @@ internal class DefaultVerificationService @Inject constructor(
}
}
override fun getExistingVerificationRequest(otherUserId: String): List<PendingVerificationRequest>? {
override fun getExistingVerificationRequests(otherUserId: String): List<PendingVerificationRequest> {
synchronized(lock = pendingRequests) {
return pendingRequests[otherUserId]
return pendingRequests[otherUserId].orEmpty()
}
}
@@ -1205,7 +1204,7 @@ internal class DefaultVerificationService @Inject constructor(
Timber.i("## Requesting verification to user: $otherUserId with device list $otherDevices")
val targetDevices = otherDevices ?: cryptoStore.getUserDevices(otherUserId)
?.values?.map { it.deviceId } ?: emptyList()
?.values?.map { it.deviceId }.orEmpty()
val requestsForUser = pendingRequests.getOrPut(otherUserId) { mutableListOf() }

View File

@@ -28,7 +28,6 @@ import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.extensions.toUnsignedInt
import org.matrix.android.sdk.internal.util.withoutPrefix
import org.matrix.olm.OlmSAS
import org.matrix.olm.OlmUtility
import timber.log.Timber
@@ -250,7 +249,7 @@ internal abstract class SASDefaultVerificationTransaction(
// cannot be empty because it has been validated
theirMacSafe.mac.keys.forEach {
val keyIDNoPrefix = it.withoutPrefix("ed25519:")
val keyIDNoPrefix = it.removePrefix("ed25519:")
val otherDeviceKey = otherUserKnownDevices?.get(keyIDNoPrefix)?.fingerprint()
if (otherDeviceKey == null) {
Timber.w("## SAS Verification: Could not find device $keyIDNoPrefix to verify")
@@ -273,7 +272,7 @@ internal abstract class SASDefaultVerificationTransaction(
if (otherCrossSigningMasterKeyPublic != null) {
// Did the user signed his master key
theirMacSafe.mac.keys.forEach {
val keyIDNoPrefix = it.withoutPrefix("ed25519:")
val keyIDNoPrefix = it.removePrefix("ed25519:")
if (keyIDNoPrefix == otherCrossSigningMasterKeyPublic) {
// Check the signature
val mac = macUsingAgreedMethod(otherCrossSigningMasterKeyPublic, baseInfo + it)

View File

@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database
import android.content.Context
import android.util.Base64
import androidx.core.content.edit
import io.realm.Realm
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.internal.session.securestorage.SecretStoringUtils
import io.realm.RealmConfiguration
@@ -46,7 +47,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.keys", Context.MODE_PRIVATE)
private fun generateKeyForRealm(): ByteArray {
val keyForRealm = ByteArray(RealmConfiguration.KEY_LENGTH)
val keyForRealm = ByteArray(Realm.ENCRYPTION_KEY_LENGTH)
rng.nextBytes(keyForRealm)
return keyForRealm
}

View File

@@ -69,6 +69,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
.apply {
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
}
.allowWritesOnUiThread(true)
.modules(SessionRealmModule())
.schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
.migration(migration)

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.database.tools
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig
import timber.log.Timber
internal class RealmDebugTools(
private val realmConfiguration: RealmConfiguration
) {
/**
* Log info about the DB
*/
fun logInfo(baseName: String) {
buildString {
append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}")
if (BuildConfig.LOG_PRIVATE_DATA) {
val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) }
append("\n$baseName Realm encryption key : $key")
}
Realm.getInstance(realmConfiguration).use { realm ->
// Check if we have data
separator()
separator()
append("\n$baseName Realm is empty: ${realm.isEmpty}")
var total = 0L
val maxNameLength = realmConfiguration.realmObjectClasses.maxOf { it.simpleName.length }
realmConfiguration.realmObjectClasses.forEach { modelClazz ->
val count = realm.where(modelClazz).count()
total += count
append("\n$baseName Realm - count ${modelClazz.simpleName.padEnd(maxNameLength)} : $count")
}
separator()
append("\n$baseName Realm - total count: $total")
separator()
separator()
}
}
.let { Timber.i(it) }
}
private fun StringBuilder.separator() = append("\n==============================================")
}

View File

@@ -52,5 +52,8 @@ internal class TimeOutInterceptor @Inject constructor() : Interceptor {
const val CONNECT_TIMEOUT = "CONNECT_TIMEOUT"
const val READ_TIMEOUT = "READ_TIMEOUT"
const val WRITE_TIMEOUT = "WRITE_TIMEOUT"
// 1 minute
const val DEFAULT_LONG_TIMEOUT: Long = 60_000
}
}

View File

@@ -16,45 +16,28 @@
package org.matrix.android.sdk.internal.raw
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.raw.RawCacheStrategy
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class DefaultRawService @Inject constructor(
private val taskExecutor: TaskExecutor,
private val getUrlTask: GetUrlTask,
private val cleanRawCacheTask: CleanRawCacheTask
) : RawService {
override fun getUrl(url: String,
rawCacheStrategy: RawCacheStrategy,
matrixCallback: MatrixCallback<String>): Cancelable {
return getUrlTask
.configureWith(GetUrlTask.Params(url, rawCacheStrategy)) {
callback = matrixCallback
}
.executeBy(taskExecutor)
override suspend fun getUrl(url: String, rawCacheStrategy: RawCacheStrategy): String {
return getUrlTask.execute(GetUrlTask.Params(url, rawCacheStrategy))
}
override fun getWellknown(userId: String,
matrixCallback: MatrixCallback<String>): Cancelable {
override suspend fun getWellknown(userId: String): String {
val homeServerDomain = userId.substringAfter(":")
return getUrl(
"https://$homeServerDomain/.well-known/matrix/client",
RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false),
matrixCallback
RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false)
)
}
override fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable {
return cleanRawCacheTask
.configureWith(Unit) {
callback = matrixCallback
}
.executeBy(taskExecutor)
override suspend fun clearCache() {
cleanRawCacheTask.execute(Unit)
}
}

View File

@@ -59,6 +59,7 @@ import org.matrix.android.sdk.api.session.user.UserService
import org.matrix.android.sdk.api.session.widgets.WidgetService
import org.matrix.android.sdk.internal.auth.SessionParamsStore
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
@@ -197,7 +198,7 @@ internal class DefaultSession @Inject constructor(
override fun close() {
assert(isOpen)
stopSync()
// timelineEventDecryptor.destroy()
// timelineEventDecryptor.destroy()
uiHandler.post {
lifecycleObservers.forEach { it.onStop() }
}
@@ -284,4 +285,8 @@ internal class DefaultSession @Inject constructor(
override fun toString(): String {
return "$myUserId - ${sessionParams.deviceId}"
}
override fun logDbUsageInfo() {
RealmDebugTools(realmConfiguration).logInfo("Session")
}
}

View File

@@ -16,30 +16,17 @@
package org.matrix.android.sdk.internal.session.account
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.account.AccountService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import javax.inject.Inject
internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask,
private val deactivateAccountTask: DeactivateAccountTask,
private val taskExecutor: TaskExecutor) : AccountService {
private val deactivateAccountTask: DeactivateAccountTask) : AccountService {
override fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable {
return changePasswordTask
.configureWith(ChangePasswordTask.Params(password, newPassword)) {
this.callback = callback
}
.executeBy(taskExecutor)
override suspend fun changePassword(password: String, newPassword: String) {
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
}
override fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback<Unit>): Cancelable {
return deactivateAccountTask
.configureWith(DeactivateAccountTask.Params(password, eraseAllData)) {
this.callback = callback
}
.executeBy(taskExecutor)
override suspend fun deactivateAccount(password: String, eraseAllData: Boolean) {
deactivateAccountTask.execute(DeactivateAccountTask.Params(password, eraseAllData))
}
}

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