Merge branch 'release/1.1.1'

This commit is contained in:
Benoit Marty 2021-03-10 22:04:26 +01:00
commit bc81931773
450 changed files with 18176 additions and 16025 deletions

23
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,23 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# Updates for Github Actions used in the repo
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# Updates for Gradle dependencies used in the app
- package-ecosystem: gradle
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 200
reviewers:
- "bmarty"
### ignore:
### - dependency-name: com.squareup.okhttp3:logging-interceptor
### versions: "> 3.12.10"

View File

@ -31,6 +31,7 @@
<w>signin</w> <w>signin</w>
<w>signout</w> <w>signout</w>
<w>signup</w> <w>signup</w>
<w>snackbar</w>
<w>ssss</w> <w>ssss</w>
<w>sygnal</w> <w>sygnal</w>
<w>threepid</w> <w>threepid</w>

View File

@ -1,3 +1,42 @@
Changes in Element 1.1.1 (2021-XX-XX)
===================================================
Features ✨:
-
Improvements 🙌:
- Allow non-HTTPS connections to homeservers on Tor (#2941)
- Fetch homeserver type and version and display in a new setting screen and add info in rageshakes (#2831)
- Improve initial sync performance - split into 2 transactions (#983)
- PIP support for Jitsi call (#2418)
- Add tooltip for room quick actions
- Pre-share session keys when opening a room or start typing (#2771)
- Sending is now queuing by room and not uniquely to the session
- Improve Snackbar duration (#2929)
- Improve sending message state (#2937)
Bugfix 🐛:
- Try to fix crash about UrlPreview (#2640)
- Be robust if Event.type is missing (#2946)
- Snappier message send status
- Fix MainActivity display (#2927)
Translations 🗣:
- All string resources and translations have been moved to the application module. Weblate project for the SDK will be removed.
SDK API changes ⚠️:
-
Build 🧱:
- Update a lot of dependencies, with the help of dependabot.
- Add a script to download and install APK from the CI
Test:
-
Other changes:
- Rework edition of event management
Changes in Element 1.1.0 (2021-02-19) Changes in Element 1.1.0 (2021-02-19)
=================================================== ===================================================
@ -1196,7 +1235,7 @@ Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-a
======================================================= =======================================================
Changes in Element 1.X.X (2021-XX-XX) Changes in Element 1.1.X (2021-XX-XX)
=================================================== ===================================================
Features ✨: Features ✨:

View File

@ -29,7 +29,7 @@ To create a new screen:
- Then right click on the package, and select `New/New Vector/RiotX Feature`. - Then right click on the package, and select `New/New Vector/RiotX Feature`.
- Follow the Wizard, especially replace `Main` by something more relevant to your feature. - Follow the Wizard, especially replace `Main` by something more relevant to your feature.
- Click on `Finish`. - Click on `Finish`.
- Remaining steps are described as TODO in the generated files, or will be pointed out by the compilator, or at runtime :) - Remaining steps are described as TODO in the generated files, or will be pointed out by the compiler, or at runtime :)
Note that if the templates are modified, the only things to do is to restart Android Studio for the change to take effect. Note that if the templates are modified, the only things to do is to restart Android Studio for the change to take effect.

View File

@ -63,13 +63,13 @@ android {
dependencies { dependencies {
implementation 'com.github.chrisbanes:PhotoView:2.1.4' implementation 'com.github.chrisbanes:PhotoView:2.1.4'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.recyclerview:recyclerview:1.2.0-beta02"
implementation 'com.google.android.material:material:1.2.1' implementation 'com.google.android.material:material:1.3.0'
} }

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/design_default_color_primary">
<TextView
android:id="@+id/testPage"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="80sp"
android:textStyle="bold" />
</RelativeLayout>

View File

@ -2,8 +2,8 @@
buildscript { buildscript {
// Ref: https://kotlinlang.org/releases.html // Ref: https://kotlinlang.org/releases.html
ext.kotlin_version = '1.4.21' ext.kotlin_version = '1.4.31'
ext.kotlin_coroutines_version = "1.4.1" ext.kotlin_coroutines_version = "1.4.2"
repositories { repositories {
google() google()
jcenter() jcenter()
@ -15,8 +15,9 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.1.2' classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.google.gms:google-services:4.3.5' classpath 'com.google.gms:google-services:4.3.5'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1.1'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.2' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.2'
classpath "com.likethesalad.android:string-reference:1.2.1"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View File

@ -0,0 +1,2 @@
Canvis principals d'aquesta versió: millora de VoIP (trucades i videotrucades en xats personals) i correcció d'errors!
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -1,2 +1,2 @@
Hlavní změny v této verzi: Náhled URL, nová klávesice s Emoji, nové možnosti nastavení místností a sníh na vánoce! Hlavní změny v této verzi: Náhled URL, nová klávesice s Emoji, nové možnosti nastavení místností a sníh na vánoce!
Plné znění změn: https://github.com/vector-im/element-android/releases/tag/v1.0.12 Plné znění změn: https://github.com/vector-im/element-android/releases/tag/v1.0.13

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Úpravy práv místností, automatický tmavý/světlý vzhled a řada oprav chyb.
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.0.14

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Podpora přihlášení v sociálních sítích.
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.0.15

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Podpora přihlášení v sociálních sítích.
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.0.15 a https://github.com/vector-im/element-android/releases/tag/v1.0.16

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Opravy chyb!
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Hlavní změny v této verzi: VoIP (audio a video hovory v DM), vylepšení a opravy chyb!
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -1,30 +1,30 @@
Element je nový typ aplikace pro výměnu zpráv a kolaboraci, která: Element je nový typ aplikace pro výměnu zpráv a spolupráci, která:
1. Vám dá moc zachovat si soukromí 1. Vám dá kontrolu nad ochranou vašeho soukromí
2. Vás nechá komunikovat s kýmkoli v síti Matrix a dokonce dále integrací s aplikacemi jako Slack 2. Umožní vám komunikovat s kýmkoli v síti Matrix a dokonce i mimo ni pomocí integrací s aplikacemi, jako je Slack
3. Vás ochrání před inzercí, těžbou dat a uzavřenými zahradami 3. Ochrání vás před inzercí, dataminingem a uzavřenými zahradami
4. Vás zabezpečí šifrováním end-to-end s křížovým podepisováním pro ověření ostatních 4. Zabezpečí vás end-to-end šifrováním s křížovým podpisem pro ověření ostatních
Element is completely different from other messaging and collaboration apps because it is decentralised and open source. Element je zcela odlišný od ostatních aplikací pro zasílání zpráv a spolupráci, protože je decentralizovaný a otevřený.
Element lets you self-host - or choose a host - so that you have privacy, ownership and control of your data and conversations. It gives you access to an open network; so youre not just stuck speaking to other Element users only. And it is very secure. Element vám umožňuje použít vlastní domovský server - nebo si vybrat hostitele - abyste měli soukromí, vlastnictví a kontrolu nad svými daty a konverzacemi. Poskytuje vám přístup k otevřené síti; takže nejste zaseknuti jen při konverzaci s ostatními uživateli Elementu. A je velmi bezpečný.
Element is able to do all this because it operates on Matrix - the standard for open, decentralised communication. Element je toho všeho schopen, protože pracuje na Matrixu - standardu otevřené, decentralizované komunikace.
Element puts you in control by letting you choose who hosts your conversations. From the Element app, you can choose to host in different ways: Element vám dává kontrolu nad tím, že si můžete vybrat, kdo bude hostovat vaše konverzace. Z aplikace Element si můžete vybrat hostování různými způsoby:
1. Get a free account on the matrix.org public server hosted by the Matrix developers, or choose from thousands of public servers hosted by volunteers 1. Získejte zdarma účet na veřejném serveru matrix.org hostovaném vývojáři Matrixu, nebo si vyberte z tisíců veřejných serverů hostovaných dobrovolníky
2. Self-host your account by running a server on your own hardware 2. Hostujte svůj účet spuštěním serveru na svém vlastním hardwaru
3. Sign up for an account on a custom server by simply subscribing to the Element Matrix Services hosting platform 3. Zaregistrujte si účet na vlastním serveru jednoduchým přihlášením k hostitelské platformě Element Matrix Services
<b>Why choose Element?</b> <b>Proč zvolit Element?</b>
<b>OWN YOUR DATA</b>: You decide where to keep your data and messages. You own it and control it, not some MEGACORP that mines your data or gives access to third parties. <b>VLASTNĚTE SVÁ DATA</b>: Vy rozhodnete, kde svá data a zprávy ponecháte. Vlastníte je a jsou pod vaší kontrolou, ne nějaký MEGACORP, který těží vaše data nebo poskytuje přístup třetím stranám.
<b>OPEN MESSAGING AND COLLABORATION</b>: You can chat with anyone else in the Matrix network, whether theyre using Element or another Matrix app, and even if they are using a different messaging system of the likes of Slack, IRC or XMPP. <b>ZPRÁVY A SPOLUPRÁCE</b>: Můžete chatovat s kýmkoli v síti Matrix, ať už používá Element nebo jinou aplikaci, a to i v případě, že používají jiný systém zasílání zpráv, jako je Slack, IRC nebo XMPP.
<b>SUPER-SECURE</b>: Real end-to-end encryption (only those in the conversation can decrypt messages), and cross-signing to verify the devices of conversation participants. <b>MAXIMÁLNĚ BEZPEČNÉ</b>: Skutečné šifrování typu end-to-end (pouze ti v konverzaci mohou dešifrovat zprávy) a křížové podepisování k ověření zařízení účastníků konverzace.
<b>COMPLETE COMMUNICATION</b>: Messaging, voice and video calls, file sharing, screen sharing and a whole bunch of integrations, bots and widgets. Build rooms, communities, stay in touch and get things done. <b>KOMPLETNÍ KOMUNIKACE</b>: Zprávy, hlasové hovory a videohovory, sdílení souborů, sdílení obrazovky a celá řada integrací, robotů a widgetů. Budujte místnosti, komunity, zůstaňte v kontaktu a spolupracujte.
<b>EVERYWHERE YOU ARE</b>: Stay in touch wherever you are with fully synchronised message history across all your devices and on the web at https://app.element.io. <b>KDEKOLIV JSTE</b>: Zůstaňte v kontaktu, ať jste kdekoli, s plně synchronizovanou historií zpráv na všech vašich zařízeních a na webu na adrese https://app.element.io.

View File

@ -1 +1 @@
Zabezpečený decentralizovaný chat & VoIP. Uchovejte svá data v bezpečí. Zabezpečený decentralizovaný chat a VoIP. Uchovejte svá data v bezpečí.

View File

@ -0,0 +1,2 @@
Hauptänderungen in dieser Version: VoIP-Verbesserung (Audio- und Video-Anrufe in Direktnachrichten) und Fehlerkorrekturen!
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -0,0 +1,2 @@
Main changes in this version: performance improvement and bug fixes!
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.1

View File

@ -0,0 +1,2 @@
Olulisemad muutused selles versioonis: Heli- ja videokõnede parandused otsevestluses ning üldised veaparandused!
Muudatuste logi täismahus: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -1,2 +1,2 @@
Tärkeimmät muutokset tässä versiossa: URL-esikatselu, uusi emoji-näppäimistö, uudet huoneasetukset ja lunta jouluna! Tärkeimmät muutokset tässä versiossa: URL-esikatselu, uusi emoji-näppäimistö, uudet huoneasetukset ja lunta jouluksi!
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.12 Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.12

View File

@ -1,2 +1,2 @@
Tärkeimmät muutokset tässä versiossa: URL-esikatselu, uusi emoji-näppäimistö, uudet huoneasetukset ja lunta jouluna! Tärkeimmät muutokset tässä versiossa: URL-esikatselu, uusi emoji-näppäimistö, uudet huoneasetukset ja lunta jouluksi!
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.12 Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.13

View File

@ -0,0 +1,2 @@
Tärkeimmät muutokset tässä versiossa: Huoneoikeuksien muokkaus, automaattinen valoisa/tumma teema ja läjäpäin virheenkorjauksia.
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.14

View File

@ -0,0 +1,2 @@
Tärkeimmät muutokset tässä versiossa: Social Login -tuki.
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.15

View File

@ -0,0 +1,2 @@
Tärkeimmät muutokset tässä versiossa: Social Login -tuki.
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16

View File

@ -0,0 +1,2 @@
Tärkeimmät muutokset tässä versiossa: Virheenkorjauksia!
Täysi muutosloki: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Principais mudanças nessa versão: correções de erros!
Registro de todas as alterações: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Основные изменения в этой версии: Исправлены ошибки!
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1 @@
ඉලෙමන්ට් (මීට පෙර Riot.im)

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Buggfixar!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Förbättringar för VoIP (ljud- och videosamtal i DM) och buggfixar!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -0,0 +1,2 @@
Основні зміни в цій версії: поліпшення VoIP (аудіо та відео дзвінки в DM) та виправлення помилок!
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -0,0 +1,2 @@
此版本中的主要變動:錯誤修復!
完整變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
此版本的主要變更VoIP直接訊息中的音訊與視訊通話改善與錯誤修復
完整變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -1,7 +1,6 @@
#Fri Jan 29 18:05:42 CET 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=1433372d903ffba27496f8d5af24265310d2da0d78bf6b4e5138831d4fe066e9 distributionSha256Sum=9af5c8e7e2cd1a3b0f694a4ac262b9f38c75262e74a9e8b5101af302a6beadd7
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -36,7 +36,7 @@ android {
dependencies { dependencies {
implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android")
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version"

View File

@ -9,7 +9,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath "io.realm:realm-gradle-plugin:10.1.2" classpath "io.realm:realm-gradle-plugin:10.3.1"
} }
} }
@ -112,9 +112,9 @@ dependencies {
def lifecycle_version = '2.2.0' def lifecycle_version = '2.2.0'
def arch_version = '2.1.0' def arch_version = '2.1.0'
def markwon_version = '3.1.0' def markwon_version = '3.1.0'
def daggerVersion = '2.31' def daggerVersion = '2.33'
def work_version = '2.4.0' def work_version = '2.5.0'
def retrofit_version = '2.6.2' def retrofit_version = '2.9.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
@ -130,7 +130,7 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.8.1")) implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.1"))
implementation 'com.squareup.okhttp3:okhttp' implementation 'com.squareup.okhttp3:okhttp'
implementation 'com.squareup.okhttp3:logging-interceptor' implementation 'com.squareup.okhttp3:logging-interceptor'
implementation 'com.squareup.okhttp3:okhttp-urlconnection' implementation 'com.squareup.okhttp3:okhttp-urlconnection'
@ -141,11 +141,11 @@ dependencies {
implementation "ru.noties.markwon:core:$markwon_version" implementation "ru.noties.markwon:core:$markwon_version"
// Image // Image
implementation 'androidx.exifinterface:exifinterface:1.3.1' implementation 'androidx.exifinterface:exifinterface:1.3.2'
// Database // Database
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1' implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
kapt 'dk.ilios:realmfieldnameshelper:1.1.1' kapt 'dk.ilios:realmfieldnameshelper:2.0.0'
// Work // Work
implementation "androidx.work:work-runtime-ktx:$work_version" implementation "androidx.work:work-runtime-ktx:$work_version"
@ -155,7 +155,7 @@ dependencies {
implementation "io.arrow-kt:arrow-instances-core:$arrow_version" implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm // olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
implementation 'org.matrix.gitlab.matrix-org:olm:3.1.2' implementation 'org.matrix.gitlab.matrix-org:olm:3.2.2'
// DI // DI
implementation "com.google.dagger:dagger:$daggerVersion" implementation "com.google.dagger:dagger:$daggerVersion"
@ -166,14 +166,14 @@ dependencies {
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1' implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.23' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.19'
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.3' testImplementation 'org.robolectric:robolectric:4.5.1'
//testImplementation 'org.robolectric:shadows-support-v4:3.0' //testImplementation 'org.robolectric:shadows-support-v4:3.0'
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
testImplementation 'io.mockk:mockk:1.9.2.kotlin12' testImplementation 'io.mockk:mockk:1.10.6'
testImplementation 'org.amshove.kluent:kluent-android:1.61' testImplementation 'org.amshove.kluent:kluent-android:1.65'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
// Plant Timber tree for test // Plant Timber tree for test
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
@ -186,7 +186,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.61' androidTestImplementation 'org.amshove.kluent:kluent-android:1.61'
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12' androidTestImplementation 'io.mockk:mockk-android:1.10.6'
androidTestImplementation "androidx.arch.core:core-testing:$arch_version" androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
// Plant Timber tree for test // Plant Timber tree for test

View File

@ -19,6 +19,15 @@ package org.matrix.android.sdk.common
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import kotlinx.coroutines.Dispatchers
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
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.MatrixConfiguration
@ -34,15 +43,6 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.SyncState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import java.util.ArrayList import java.util.ArrayList
import java.util.UUID import java.util.UUID
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@ -59,7 +59,13 @@ class CommonTestHelper(context: Context) {
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestNetworkModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestNetworkModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
init { init {
Matrix.initialize(context, MatrixConfiguration("TestFlavor")) Matrix.initialize(
context,
MatrixConfiguration(
applicationFlavor = "TestFlavor",
roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider()
)
)
matrix = Matrix.getInstance(context) matrix = Matrix.getInstance(context)
} }
@ -385,8 +391,8 @@ fun List<TimelineEvent>.checkSendOrder(baseTextMessage: String, numberOfMessages
return drop(startIndex) return drop(startIndex)
.take(numberOfMessages) .take(numberOfMessages)
.foldRightIndexed(true) { index, timelineEvent, acc -> .foldRightIndexed(true) { index, timelineEvent, acc ->
val body = timelineEvent.root.content.toModel<MessageContent>()?.body val body = timelineEvent.root.content.toModel<MessageContent>()?.body
val currentMessageSuffix = numberOfMessages - index val currentMessageSuffix = numberOfMessages - index
acc && (body == null || body.startsWith(baseTextMessage) && body.endsWith("#$currentMessageSuffix")) acc && (body == null || body.startsWith(baseTextMessage) && body.endsWith("#$currentMessageSuffix"))
} }
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2021 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.common
import org.matrix.android.sdk.api.RoomDisplayNameFallbackProvider
class TestRoomDisplayNameFallbackProvider() : RoomDisplayNameFallbackProvider {
override fun getNameForRoomInvite() =
"Room invite"
override fun getNameForEmptyRoom() =
"Empty room"
override fun getNameFor2members(name1: String?, name2: String?) =
"$name1 and $name2"
override fun getNameFor3members(name1: String?, name2: String?, name3: String?) =
"$name1, $name2 and $name3"
override fun getNameFor4members(name1: String?, name2: String?, name3: String?, name4: String?) =
"$name1, $name2, $name3 and $name4"
override fun getNameFor4membersAndMore(name1: String?, name2: String?, name3: String?, remainingCount: Int) =
"$name1, $name2, $name3 and $remainingCount others"
}

View File

@ -0,0 +1,103 @@
/*
* 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.crypto
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.FixMethodOrder
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.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class PreShareKeysTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
@Test
fun ensure_outbound_session_happy_path() {
val testData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val e2eRoomID = testData.roomId
val aliceSession = testData.firstSession
val bobSession = testData.secondSession!!
// clear any outbound session
aliceSession.cryptoService().discardOutboundSession(e2eRoomID)
val preShareCount = bobSession.cryptoService().getGossipingEvents().count {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
}
assertEquals(0, preShareCount, "Bob should not have receive any key from alice at this point")
Log.d("#Test", "Room Key Received from alice $preShareCount")
// Force presharing of new outbound key
mTestHelper.doSync<Unit> {
aliceSession.cryptoService().prepareToEncrypt(e2eRoomID, it)
}
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
val newGossipCount = bobSession.cryptoService().getGossipingEvents().count {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
}
newGossipCount > preShareCount
}
}
val latest = bobSession.cryptoService().getGossipingEvents().lastOrNull {
it.senderId == aliceSession.myUserId
&& it.getClearType() == EventType.ROOM_KEY
}
val content = latest?.getClearContent().toModel<RoomKeyContent>()
assertNotNull(content, "Bob should have received and decrypted a room key event from alice")
assertEquals(e2eRoomID, content.roomId, "Wrong room")
val megolmSessionId = content.sessionId!!
val sharedIndex = aliceSession.cryptoService().getSharedWithInfo(e2eRoomID, megolmSessionId)
.getObject(bobSession.myUserId, bobSession.sessionParams.deviceId)
assertEquals(0, sharedIndex, "The session received by bob should match what alice sent")
// Just send a real message as test
val sentEvent = mTestHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
assertEquals(megolmSessionId, sentEvent.root.content.toModel<EncryptedEventContent>()?.sessionId, "Unexpected megolm session")
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
bobSession.getRoom(e2eRoomID)?.getTimeLineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE
}
}
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
}
}

View File

@ -51,7 +51,7 @@ class WithHeldTests : InstrumentedTest {
// ============================= // =============================
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val bobSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
// Initialize cross signing on both // Initialize cross signing on both
mCryptoTestHelper.initializeCrossSigning(aliceSession) mCryptoTestHelper.initializeCrossSigning(aliceSession)

View File

@ -39,7 +39,11 @@ data class MatrixConfiguration(
/** /**
* True to advertise support for call transfers to other parties on Matrix calls. * True to advertise support for call transfers to other parties on Matrix calls.
*/ */
val supportsCallTransfer: Boolean = false val supportsCallTransfer: Boolean = false,
/**
* RoomDisplayNameFallbackProvider to provide default room display name.
*/
val roomDisplayNameFallbackProvider: RoomDisplayNameFallbackProvider
) { ) {
/** /**

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 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
interface RoomDisplayNameFallbackProvider {
fun getNameForRoomInvite(): String
fun getNameForEmptyRoom(): String
fun getNameFor2members(name1: String?, name2: String?): String
fun getNameFor3members(name1: String?, name2: String?, name3: String?): String
fun getNameFor4members(name1: String?, name2: String?, name3: String?, name4: String?): String
fun getNameFor4membersAndMore(name1: String?, name2: String?, name3: String?, remainingCount: Int): String
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 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.crypto
enum class VerificationState {
REQUEST,
WAITING,
CANCELED_BY_ME,
CANCELED_BY_OTHER,
DONE
}
fun VerificationState.isCanceled(): Boolean {
return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2021 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.federation
interface FederationService {
/**
* Get information about the homeserver
*/
suspend fun getFederationVersion(): FederationVersion
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 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.federation
/**
* Ref: https://matrix.org/docs/spec/server_server/latest#get-matrix-federation-v1-version
*/
data class FederationVersion(
/**
* Arbitrary name that identify this implementation.
*/
val name: String?,
/**
* Version of this implementation. The version format depends on the implementation.
*/
val version: String?
)

View File

@ -21,6 +21,7 @@ import androidx.lifecycle.LiveData
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.failure.GlobalError
import org.matrix.android.sdk.api.federation.FederationService
import org.matrix.android.sdk.api.pushrules.PushRuleService import org.matrix.android.sdk.api.pushrules.PushRuleService
import org.matrix.android.sdk.api.session.account.AccountService import org.matrix.android.sdk.api.session.account.AccountService
import org.matrix.android.sdk.api.session.accountdata.AccountDataService import org.matrix.android.sdk.api.session.accountdata.AccountDataService
@ -34,6 +35,7 @@ import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.api.session.group.GroupService import org.matrix.android.sdk.api.session.group.GroupService
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.session.identity.IdentityService import org.matrix.android.sdk.api.session.identity.IdentityService
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.media.MediaService
import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService
@ -213,6 +215,11 @@ interface Session :
*/ */
fun searchService(): SearchService fun searchService(): SearchService
/**
* Returns the federation service associated with the session
*/
fun federationService(): FederationService
/** /**
* Returns the third party service associated with the session * Returns the third party service associated with the session
*/ */

View File

@ -156,4 +156,10 @@ interface CryptoService {
fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
fun logDbUsageInfo() fun logDbUsageInfo()
/**
* Perform any background tasks that can be done before a message is ready to
* send, in order to speed up sending of the message.
*/
fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>)
} }

View File

@ -66,7 +66,7 @@ inline fun <reified T> T.toContent(): Content {
*/ */
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class Event( data class Event(
@Json(name = "type") val type: String, @Json(name = "type") val type: String? = null,
@Json(name = "event_id") val eventId: String? = null, @Json(name = "event_id") val eventId: String? = null,
@Json(name = "content") val content: Content? = null, @Json(name = "content") val content: Content? = null,
@Json(name = "prev_content") val prevContent: Content? = null, @Json(name = "prev_content") val prevContent: Content? = null,
@ -98,6 +98,19 @@ data class Event(
@Transient @Transient
var ageLocalTs: Long? = null var ageLocalTs: Long? = null
/**
* Copy all fields, including transient fields
*/
fun copyAll(): Event {
return copy().also {
it.mxDecryptionResult = mxDecryptionResult
it.mCryptoError = mCryptoError
it.mCryptoErrorReason = mCryptoErrorReason
it.sendState = sendState
it.ageLocalTs = ageLocalTs
}
}
/** /**
* Check if event is a state event. * Check if event is a state event.
* @return true if event is state event. * @return true if event is state event.
@ -135,7 +148,7 @@ data class Event(
* @return the event type * @return the event type
*/ */
fun getClearType(): String { fun getClearType(): String {
return mxDecryptionResult?.payload?.get("type")?.toString() ?: type return mxDecryptionResult?.payload?.get("type")?.toString() ?: type ?: EventType.MISSING_TYPE
} }
/** /**

View File

@ -20,6 +20,8 @@ package org.matrix.android.sdk.api.session.events.model
* Constants defining known event types from Matrix specifications. * Constants defining known event types from Matrix specifications.
*/ */
object EventType { object EventType {
// Used when the type is missing, which should not happen
const val MISSING_TYPE = "org.matrix.android.sdk.missing_type"
const val PRESENCE = "m.presence" const val PRESENCE = "m.presence"
const val MESSAGE = "m.room.message" const val MESSAGE = "m.room.message"

View File

@ -21,6 +21,11 @@ package org.matrix.android.sdk.api.session.homeserver
*/ */
interface HomeServerCapabilitiesService { interface HomeServerCapabilitiesService {
/**
* Force a refresh of the stored data
*/
suspend fun refreshHomeServerCapabilities()
/** /**
* Get the HomeServer capabilities * Get the HomeServer capabilities
*/ */

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2021 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.initsync
enum class InitSyncStep {
ServerComputing,
Downloading,
ImportingAccount,
ImportingAccountCrypto,
ImportingAccountRoom,
ImportingAccountGroups,
ImportingAccountData,
ImportingAccountJoinedRooms,
ImportingAccountInvitedRooms,
ImportingAccountLeftRooms
}

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.api.session package org.matrix.android.sdk.api.session.initsync
import androidx.annotation.StringRes
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
interface InitialSyncProgressService { interface InitialSyncProgressService {
@ -25,7 +24,7 @@ interface InitialSyncProgressService {
sealed class Status { sealed class Status {
object Idle : Status() object Idle : Status()
data class Progressing( data class Progressing(
@StringRes val statusText: Int, val initSyncStep: InitSyncStep,
val percentProgress: Int = 0 val percentProgress: Int = 0
) : Status() ) : Status()
} }

View File

@ -16,11 +16,9 @@
package org.matrix.android.sdk.api.session.room package org.matrix.android.sdk.api.session.room
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
import org.matrix.android.sdk.api.util.Cancelable
/** /**
* This interface defines methods to get and join public rooms. It's implemented at the session level. * This interface defines methods to get and join public rooms. It's implemented at the session level.
@ -30,9 +28,8 @@ interface RoomDirectoryService {
/** /**
* Get rooms from directory * Get rooms from directory
*/ */
fun getPublicRooms(server: String?, suspend fun getPublicRooms(server: String?,
publicRoomsParams: PublicRoomsParams, publicRoomsParams: PublicRoomsParams): PublicRoomsResponse
callback: MatrixCallback<PublicRoomsResponse>): Cancelable
/** /**
* Get the visibility of a room in the directory * Get the visibility of a room in the directory

View File

@ -30,4 +30,10 @@ interface RoomCryptoService {
* Enable encryption of the room * Enable encryption of the room
*/ */
suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM) suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM)
/**
* Ensures all members of the room are loaded and outbound session keys are shared.
* If this method is not called, CryptoService will ensure it before sending events.
*/
suspend fun prepareToEncrypt()
} }

View File

@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.room.model
import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Content
data class EditAggregatedSummary( data class EditAggregatedSummary(
val aggregatedContent: Content? = null, val latestContent: Content? = null,
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk) // The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
val sourceEvents: List<String>, val sourceEvents: List<String>,
val localEchos: List<String>, val localEchos: List<String>,

View File

@ -17,7 +17,7 @@ package org.matrix.android.sdk.api.session.room.model
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.internal.session.room.VerificationState import org.matrix.android.sdk.api.crypto.VerificationState
/** /**
* Contains an aggregated summary info of the references. * Contains an aggregated summary info of the references.

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.room.model.relation package org.matrix.android.sdk.api.session.room.model.relation
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
@ -67,11 +66,11 @@ interface RelationService {
/** /**
* Edit a text message body. Limited to "m.text" contentType * Edit a text message body. Limited to "m.text" contentType
* @param targetEventId The event to edit * @param targetEvent The event to edit
* @param newBodyText The edited body * @param newBodyText The edited body
* @param compatibilityBodyText The text that will appear on clients that don't support yet edition * @param compatibilityBodyText The text that will appear on clients that don't support yet edition
*/ */
fun editTextMessage(targetEventId: String, fun editTextMessage(targetEvent: TimelineEvent,
msgType: String, msgType: String,
newBodyText: CharSequence, newBodyText: CharSequence,
newBodyAutoMarkdown: Boolean, newBodyAutoMarkdown: Boolean,
@ -92,8 +91,11 @@ interface RelationService {
/** /**
* Get the edit history of the given event * Get the edit history of the given event
* The return list will contain the original event and all the editions of this event, done by the
* same sender, sorted in the reverse order (so the original event is the latest element, and the
* latest edition is the first element of the list)
*/ */
fun fetchEditHistory(eventId: String, callback: MatrixCallback<List<Event>>) suspend fun fetchEditHistory(eventId: String): List<Event>
/** /**
* Reply to an event in the timeline (must be in same room) * Reply to an event in the timeline (must be in same room)

View File

@ -17,14 +17,11 @@
package org.matrix.android.sdk.api.session.room.powerlevels package org.matrix.android.sdk.api.session.room.powerlevels
import androidx.annotation.StringRes sealed class Role(open val value: Int) : Comparable<Role> {
import org.matrix.android.sdk.R object Admin : Role(100)
object Moderator : Role(50)
sealed class Role(open val value: Int, @StringRes val res: Int) : Comparable<Role> { object Default : Role(0)
object Admin : Role(100, R.string.power_level_admin) data class Custom(override val value: Int) : Role(value)
object Moderator : Role(50, R.string.power_level_moderator)
object Default : Role(0, R.string.power_level_default)
data class Custom(override val value: Int) : Role(value, R.string.power_level_custom)
override fun compareTo(other: Role): Int { override fun compareTo(other: Role): Int {
return value.compareTo(other.value) return value.compareTo(other.value)

View File

@ -132,4 +132,9 @@ interface SendService {
* Resend all failed messages one by one (and keep order) * Resend all failed messages one by one (and keep order)
*/ */
fun resendAllFailedMessages() fun resendAllFailedMessages()
/**
* Cancel all failed messages
*/
fun cancelAllFailedMessages()
} }

View File

@ -38,6 +38,9 @@ import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply
*/ */
data class TimelineEvent( data class TimelineEvent(
val root: Event, val root: Event,
/**
* Uniquely identify an event, computed locally by the sdk
*/
val localId: Long, val localId: Long,
val eventId: String, val eventId: String,
val displayIndex: Int, val displayIndex: Int,
@ -123,8 +126,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {
return if (root.getClearType() == EventType.STICKER) { return if (root.getClearType() == EventType.STICKER) {
root.getClearContent().toModel<MessageStickerContent>() root.getClearContent().toModel<MessageStickerContent>()
} else { } else {
annotations?.editSummary?.aggregatedContent?.toModel() (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
?: root.getClearContent().toModel()
} }
} }

View File

@ -36,9 +36,23 @@ interface TimelineService {
*/ */
fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline
/**
* Returns a snapshot of TimelineEvent event with eventId.
* At the opposite of getTimeLineEventLive which will be updated when local echo event is synced, it will return null in this case.
* @param eventId the eventId to get the TimelineEvent
*/
fun getTimeLineEvent(eventId: String): TimelineEvent? fun getTimeLineEvent(eventId: String): TimelineEvent?
/**
* Creates a LiveData of Optional TimelineEvent event with eventId.
* If the eventId is a local echo eventId, it will make the LiveData be updated with the synced TimelineEvent when coming through the sync.
* In this case, makes sure to use the new synced eventId from the TimelineEvent class if you want to interact, as the local echo is removed from the SDK.
* @param eventId the eventId to listen for TimelineEvent
*/
fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>> fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>>
/**
* Returns a snapshot list of TimelineEvent with EventType.MESSAGE and MessageType.MSGTYPE_IMAGE or MessageType.MSGTYPE_VIDEO.
*/
fun getAttachmentMessages(): List<TimelineEvent> fun getAttachmentMessages(): List<TimelineEvent>
} }

View File

@ -22,9 +22,9 @@ interface FilterService {
NoFilter, NoFilter,
/** /**
* Filter for Riot, will include only known event type * Filter for Element, will include only known event type
*/ */
RiotFilter ElementFilter
} }
/** /**

View File

@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
import org.matrix.android.sdk.internal.crypto.algorithms.IMXWithHeldExtension import org.matrix.android.sdk.internal.crypto.algorithms.IMXWithHeldExtension
import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
@ -97,7 +98,6 @@ import org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
import kotlin.jvm.Throws
import kotlin.math.max import kotlin.math.max
/** /**
@ -667,7 +667,12 @@ internal class DefaultCryptoService @Inject constructor(
override fun discardOutboundSession(roomId: String) { override fun discardOutboundSession(roomId: String) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
roomEncryptorsStore.get(roomId)?.discardSessionKey() val roomEncryptor = roomEncryptorsStore.get(roomId)
if (roomEncryptor is IMXGroupEncryption) {
roomEncryptor.discardSessionKey()
} else {
Timber.e("## CRYPTO | discardOutboundSession() for:$roomId: Unable to handle IMXGroupEncryption")
}
} }
} }
@ -703,7 +708,7 @@ internal class DefaultCryptoService @Inject constructor(
*/ */
@Throws(MXCryptoError::class) @Throws(MXCryptoError::class)
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult { private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
return eventDecryptor.decryptEvent(event, timeline) return eventDecryptor.decryptEvent(event, timeline)
} }
/** /**
@ -1290,6 +1295,43 @@ internal class DefaultCryptoService @Inject constructor(
cryptoStore.logDbUsageInfo() cryptoStore.logDbUsageInfo()
} }
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
// Ensure to load all room members
try {
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
} catch (failure: Throwable) {
Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
callback.onFailure(failure)
return@launch
}
val userIds = getRoomUserIds(roomId)
val alg = roomEncryptorsStore.get(roomId)
?: getEncryptionAlgorithm(roomId)
?.let { setEncryptionInRoom(roomId, it, false, userIds) }
?.let { roomEncryptorsStore.get(roomId) }
if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
callback.onFailure(IllegalArgumentException("Missing algorithm"))
return@launch
}
runCatching {
(alg as? IMXGroupEncryption)?.preshareKey(userIds)
}.fold(
{ callback.onSuccess(Unit) },
{
Timber.e("## CRYPTO | prepareToEncrypt() failed.")
callback.onFailure(it)
}
)
}
}
/* ========================================================================================== /* ==========================================================================================
* For test only * For test only
* ========================================================================================== */ * ========================================================================================== */

View File

@ -105,7 +105,7 @@ internal class EventDecryptor @Inject constructor(
try { try {
return alg.decryptEvent(event, timeline) return alg.decryptEvent(event, timeline)
} catch (mxCryptoError: MXCryptoError) { } catch (mxCryptoError: MXCryptoError) {
Timber.d("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError") Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
if (algorithm == MXCRYPTO_ALGORITHM_OLM) { if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
if (mxCryptoError is MXCryptoError.Base if (mxCryptoError is MXCryptoError.Base
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) { && mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {

View File

@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListen
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
import org.matrix.android.sdk.internal.crypto.model.rest.GossipingDefaultContent import org.matrix.android.sdk.internal.crypto.model.rest.GossipingDefaultContent
@ -290,12 +291,16 @@ internal class IncomingGossipingRequestManager @Inject constructor(
.also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) }
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val isSuccess = roomEncryptor.reshareKey(sessionId, userId, deviceId, senderKey) if (roomEncryptor is IMXGroupEncryption) {
val isSuccess = roomEncryptor.reshareKey(sessionId, userId, deviceId, senderKey)
if (isSuccess) { if (isSuccess) {
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED) cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED)
} else {
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.UNABLE_TO_PROCESS)
}
} else { } else {
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.UNABLE_TO_PROCESS) Timber.e("## CRYPTO | handleKeyRequestFromOtherUser() from:$userId: Unable to handle IMXGroupEncryption.reshareKey for $alg")
} }
} }
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.RE_REQUESTED) cryptoStore.updateGossipingRequestState(request, GossipingRequestState.RE_REQUESTED)

View File

@ -32,34 +32,4 @@ internal interface IMXEncrypting {
* @return the encrypted content * @return the encrypted content
*/ */
suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content
/**
* In Megolm, each recipient maintains a record of the ratchet value which allows
* them to decrypt any messages sent in the session after the corresponding point
* in the conversation. If this value is compromised, an attacker can similarly
* decrypt past messages which were encrypted by a key derived from the
* compromised or subsequent ratchet values. This gives 'partial' forward
* secrecy.
*
* To mitigate this issue, the application should offer the user the option to
* discard historical conversations, by winding forward any stored ratchet values,
* or discarding sessions altogether.
*/
fun discardSessionKey()
/**
* Re-shares a session key with devices if the key has already been
* sent to them.
*
* @param sessionId The id of the outbound session to share.
* @param userId The id of the user who owns the target device.
* @param deviceId The id of the target device.
* @param senderKey The key of the originating device for the session.
*
* @return true in case of success
*/
suspend fun reshareKey(sessionId: String,
userId: String,
deviceId: String,
senderKey: String): Boolean
} }

View File

@ -0,0 +1,52 @@
/*
* 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.crypto.algorithms
internal interface IMXGroupEncryption {
/**
* In Megolm, each recipient maintains a record of the ratchet value which allows
* them to decrypt any messages sent in the session after the corresponding point
* in the conversation. If this value is compromised, an attacker can similarly
* decrypt past messages which were encrypted by a key derived from the
* compromised or subsequent ratchet values. This gives 'partial' forward
* secrecy.
*
* To mitigate this issue, the application should offer the user the option to
* discard historical conversations, by winding forward any stored ratchet values,
* or discarding sessions altogether.
*/
fun discardSessionKey()
suspend fun preshareKey(userIds: List<String>)
/**
* Re-shares a session key with devices if the key has already been
* sent to them.
*
* @param sessionId The id of the outbound session to share.
* @param userId The id of the user who owns the target device.
* @param deviceId The id of the target device.
* @param senderKey The key of the originating device for the session.
*
* @return true in case of success
*/
suspend fun reshareKey(sessionId: String,
userId: String,
deviceId: String,
senderKey: String): Boolean
}

View File

@ -18,8 +18,6 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
@ -30,6 +28,7 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
@ -39,8 +38,6 @@ import org.matrix.android.sdk.internal.crypto.model.forEach
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.util.convertToUTF8 import org.matrix.android.sdk.internal.util.convertToUTF8
@ -54,14 +51,14 @@ internal class MXMegolmEncryption(
private val cryptoStore: IMXCryptoStore, private val cryptoStore: IMXCryptoStore,
private val deviceListManager: DeviceListManager, private val deviceListManager: DeviceListManager,
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction, private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
private val credentials: Credentials, private val userId: String,
private val deviceId: String,
private val sendToDeviceTask: SendToDeviceTask, private val sendToDeviceTask: SendToDeviceTask,
private val messageEncrypter: MessageEncrypter, private val messageEncrypter: MessageEncrypter,
private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository, private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
private val taskExecutor: TaskExecutor,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope private val cryptoCoroutineScope: CoroutineScope
) : IMXEncrypting { ) : IMXEncrypting, IMXGroupEncryption {
// OutboundSessionInfo. Null if we haven't yet started setting one up. Note // OutboundSessionInfo. Null if we haven't yet started setting one up. Note
// that even if this is non-null, it may not be ready for use (in which // that even if this is non-null, it may not be ready for use (in which
@ -93,6 +90,7 @@ internal class MXMegolmEncryption(
// annoyingly we have to serialize again the saved outbound session to store message index :/ // annoyingly we have to serialize again the saved outbound session to store message index :/
// if not we would see duplicate message index errors // if not we would see duplicate message index errors
olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId) olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
} }
} }
@ -117,6 +115,16 @@ internal class MXMegolmEncryption(
olmDevice.discardOutboundGroupSessionForRoom(roomId) olmDevice.discardOutboundGroupSessionForRoom(roomId)
} }
override suspend fun preshareKey(userIds: List<String>) {
val ts = System.currentTimeMillis()
Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
val devices = getDevicesInRoom(userIds)
val outboundSession = ensureOutboundSession(devices.allowedDevices)
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
}
/** /**
* Prepare a new session. * Prepare a new session.
* *
@ -252,7 +260,7 @@ internal class MXMegolmEncryption(
continue continue
} }
Timber.i("## CRYPTO | shareUserDevicesKey() : Sharing keys with device $userId:$deviceID") Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo))) contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
haveTargets = true haveTargets = true
} }
@ -263,12 +271,14 @@ internal class MXMegolmEncryption(
// attempted to share with) rather than the contentMap (those we did // attempted to share with) rather than the contentMap (those we did
// share with), because we don't want to try to claim a one-time-key // share with), because we don't want to try to claim a one-time-key
// for dead devices on every message. // for dead devices on every message.
val gossipingEventBuffer = arrayListOf<Event>()
for ((userId, devicesToShareWith) in devicesByUser) { for ((userId, devicesToShareWith) in devicesByUser) {
for ((deviceId) in devicesToShareWith) { for ((deviceId) in devicesToShareWith) {
session.sharedWithHelper.markedSessionAsShared(userId, deviceId, chainIndex) session.sharedWithHelper.markedSessionAsShared(userId, deviceId, chainIndex)
cryptoStore.saveGossipingEvent(Event( gossipingEventBuffer.add(
Event(
type = EventType.ROOM_KEY, type = EventType.ROOM_KEY,
senderId = credentials.userId, senderId = this.userId,
content = submap.apply { content = submap.apply {
this["session_key"] = "" this["session_key"] = ""
// we add a fake key for trail // we add a fake key for trail
@ -278,6 +288,8 @@ internal class MXMegolmEncryption(
} }
} }
cryptoStore.saveGossipingEvents(gossipingEventBuffer)
if (haveTargets) { if (haveTargets) {
t0 = System.currentTimeMillis() t0 = System.currentTimeMillis()
Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target") Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
@ -294,8 +306,11 @@ internal class MXMegolmEncryption(
} }
} }
private fun notifyKeyWithHeld(targets: List<UserDevice>, sessionId: String, senderKey: String?, code: WithHeldCode) { private suspend fun notifyKeyWithHeld(targets: List<UserDevice>,
Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId ") sessionId: String,
senderKey: String?,
code: WithHeldCode) {
Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
val withHeldContent = RoomKeyWithHeldContent( val withHeldContent = RoomKeyWithHeldContent(
roomId = roomId, roomId = roomId,
senderKey = senderKey, senderKey = senderKey,
@ -311,13 +326,11 @@ internal class MXMegolmEncryption(
} }
} }
) )
sendToDeviceTask.configureWith(params) { try {
callback = object : MatrixCallback<Unit> { sendToDeviceTask.execute(params)
override fun onFailure(failure: Throwable) { } catch (failure: Throwable) {
Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ") Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
} }
}
}.executeBy(taskExecutor)
} }
/** /**
@ -343,7 +356,7 @@ internal class MXMegolmEncryption(
// Include our device ID so that recipients can send us a // Include our device ID so that recipients can send us a
// m.new_device message if they don't have our session key. // m.new_device message if they don't have our session key.
map["device_id"] = credentials.deviceId!! map["device_id"] = deviceId
session.useCount++ session.useCount++
return map return map
} }

View File

@ -17,7 +17,6 @@
package org.matrix.android.sdk.internal.crypto.algorithms.megolm package org.matrix.android.sdk.internal.crypto.algorithms.megolm
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.MXOlmDevice
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
@ -26,7 +25,8 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupServic
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import javax.inject.Inject import javax.inject.Inject
@ -36,29 +36,29 @@ internal class MXMegolmEncryptionFactory @Inject constructor(
private val cryptoStore: IMXCryptoStore, private val cryptoStore: IMXCryptoStore,
private val deviceListManager: DeviceListManager, private val deviceListManager: DeviceListManager,
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction, private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
private val credentials: Credentials, @UserId private val userId: String,
@DeviceId private val deviceId: String?,
private val sendToDeviceTask: SendToDeviceTask, private val sendToDeviceTask: SendToDeviceTask,
private val messageEncrypter: MessageEncrypter, private val messageEncrypter: MessageEncrypter,
private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository, private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
private val taskExecutor: TaskExecutor,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope) { private val cryptoCoroutineScope: CoroutineScope) {
fun create(roomId: String): MXMegolmEncryption { fun create(roomId: String): MXMegolmEncryption {
return MXMegolmEncryption( return MXMegolmEncryption(
roomId, roomId = roomId,
olmDevice, olmDevice = olmDevice,
defaultKeysBackupService, defaultKeysBackupService = defaultKeysBackupService,
cryptoStore, cryptoStore = cryptoStore,
deviceListManager, deviceListManager = deviceListManager,
ensureOlmSessionsForDevicesAction, ensureOlmSessionsForDevicesAction = ensureOlmSessionsForDevicesAction,
credentials, userId = userId,
sendToDeviceTask, deviceId = deviceId!!,
messageEncrypter, sendToDeviceTask = sendToDeviceTask,
warnOnUnknownDevicesRepository, messageEncrypter = messageEncrypter,
taskExecutor, warnOnUnknownDevicesRepository = warnOnUnknownDevicesRepository,
coroutineDispatchers, coroutineDispatchers = coroutineDispatchers,
cryptoCoroutineScope cryptoCoroutineScope = cryptoCoroutineScope
) )
} }
} }

View File

@ -76,13 +76,4 @@ internal class MXOlmEncryption(
deviceListManager.downloadKeys(users, false) deviceListManager.downloadKeys(users, false)
ensureOlmSessionsForUsersAction.handle(users) ensureOlmSessionsForUsersAction.handle(users)
} }
override fun discardSessionKey() {
// No need for olm
}
override suspend fun reshareKey(sessionId: String, userId: String, deviceId: String, senderKey: String): Boolean {
// No need for olm
return false
}
} }

View File

@ -45,7 +45,7 @@ internal class DefaultEncryptEventTask @Inject constructor(
// don't want to wait for any query // don't want to wait for any query
// if (!params.crypto.isRoomEncrypted(params.roomId)) return params.event // if (!params.crypto.isRoomEncrypted(params.roomId)) return params.event
val localEvent = params.event val localEvent = params.event
if (localEvent.eventId == null) { if (localEvent.eventId == null || localEvent.type == null) {
throw IllegalArgumentException() throw IllegalArgumentException()
} }

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