Merge remote-tracking branch 'origin/develop' into task/eric/when-arrow-alignment

# Conflicts:
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
#	vector/src/main/java/im/vector/app/core/ui/views/ReadReceiptsView.kt
#	vector/src/main/java/im/vector/app/core/utils/TextUtils.kt
#	vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
#	vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
#	vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
#	vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
#	vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
#	vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
#	vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationShareMessageItemFactory.kt
#	vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
#	vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt
#	vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt
#	vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
#	vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt
This commit is contained in:
ericdecanini 2022-06-03 12:06:23 +02:00
commit 5cc7deea4e
386 changed files with 8020 additions and 2472 deletions

View file

@ -73,3 +73,14 @@ body:
- 'No' - 'No'
validations: validations:
required: true required: true
- type: dropdown
id: pr
attributes:
label: Are you willing to provide a PR?
description: |
Providing a PR can drastically speed up the process of fixing this bug. Don't worry, it's still OK to answer 'No' :).
options:
- 'Yes'
- 'No'
validations:
required: true

View file

@ -34,3 +34,14 @@ body:
placeholder: Is there anything else you'd like to add? placeholder: Is there anything else you'd like to add?
validations: validations:
required: false required: false
- type: dropdown
id: pr
attributes:
label: Are you willing to provide a PR?
description: |
Don't worry, it's still OK to answer 'No' :).
options:
- 'Yes'
- 'No'
validations:
required: true

View file

@ -5,6 +5,11 @@ on:
push: push:
branches: [ main, develop ] branches: [ main, develop ]
# Enrich gradle.properties for CI/CD
env:
CI_GRADLE_ARG_PROPERTIES: >
-Porg.gradle.jvmargs=-Xmx4g
jobs: jobs:
check: check:
name: Project Check Suite name: Project Check Suite
@ -97,6 +102,25 @@ jobs:
comment_id: ${{ steps.fc.outputs.comment-id }} comment_id: ${{ steps.fc.outputs.comment-id }}
}) })
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
dependency-analysis:
name: Dependency analysis
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('dep-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('dep-develop-{0}', github.sha) || format('dep-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
- name: Dependency analysis
run: ./gradlew buildHealth $CI_GRADLE_ARG_PROPERTIES
- name: Upload dependency analysis
if: always()
uses: actions/upload-artifact@v3
with:
name: dependency-analysis
path: build/reports/dependency-analysis/build-health-report.txt
# Lint for main module # Lint for main module
android-lint: android-lint:
name: Android Linter name: Android Linter

View file

@ -105,10 +105,7 @@ jobs:
# Skip in forks # Skip in forks
if: > if: >
github.repository == 'vector-im/element-android' && github.repository == 'vector-im/element-android' &&
(contains(github.event.issue.labels.*.name, 'A-Spaces') || (contains(github.event.issue.labels.*.name, 'Team: Delight'))
contains(github.event.issue.labels.*.name, 'A-Space-Settings') ||
contains(github.event.issue.labels.*.name, 'A-Subspaces') ||
contains(github.event.issue.labels.*.name, 'Z-IA'))
steps: steps:
- uses: octokit/graphql-action@v2.x - uses: octokit/graphql-action@v2.x
with: with:

View file

@ -15,9 +15,6 @@ jobs:
!contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') && !contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') &&
!contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') && !contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') &&
!contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification') && !contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification') &&
!contains(github.event.issue.labels.*.name, 'A-Spaces') &&
!contains(github.event.issue.labels.*.name, 'A-Spaces-Settings') &&
!contains(github.event.issue.labels.*.name, 'A-Subspaces')) &&
(contains(github.event.issue.labels.*.name, 'T-Defect') && (contains(github.event.issue.labels.*.name, 'T-Defect') &&
contains(github.event.issue.labels.*.name, 'S-Critical') && contains(github.event.issue.labels.*.name, 'S-Critical') &&
(contains(github.event.issue.labels.*.name, 'O-Frequent') || (contains(github.event.issue.labels.*.name, 'O-Frequent') ||

View file

@ -1,3 +1,67 @@
Changes in Element v1.4.18 (2022-05-31)
=======================================
Features ✨
----------
- Space explore screen changes: removed space card, added rooms filtering ([#5658](https://github.com/vector-im/element-android/issues/5658))
- Adds space or user id as a subtitle under rooms in search ([#5860](https://github.com/vector-im/element-android/issues/5860))
- Adds up navigation in spaces ([#6073](https://github.com/vector-im/element-android/issues/6073))
- Labs flag for enabling live location sharing ([#6098](https://github.com/vector-im/element-android/issues/6098))
- Added support for mandatory backup or passphrase from .well-known configuration. ([#6133](https://github.com/vector-im/element-android/issues/6133))
- Security - Asking for user confirmation when tapping URLs which contain unicode directional overrides ([#6163](https://github.com/vector-im/element-android/issues/6163))
- Add settings switch to allow autoplaying animated images ([#6166](https://github.com/vector-im/element-android/issues/6166))
- Live Location Sharing - User List Bottom Sheet ([#6170](https://github.com/vector-im/element-android/issues/6170))
Bugfixes 🐛
----------
- Fix some notifications not clearing when read ([#4862](https://github.com/vector-im/element-android/issues/4862))
- Do not switch away from home space on notification when "Show all Rooms in Home" is selected. ([#5827](https://github.com/vector-im/element-android/issues/5827))
- Use fixed text size in read receipt counter ([#5856](https://github.com/vector-im/element-android/issues/5856))
- Revert: Use member name instead of room name in DM creation item ([#6032](https://github.com/vector-im/element-android/issues/6032))
- Poll refactoring with unit tests ([#6074](https://github.com/vector-im/element-android/issues/6074))
- Correct .well-known/matrix/client handling for server_names which include ports. ([#6095](https://github.com/vector-im/element-android/issues/6095))
- Glide - Use current drawable while loading new static map image ([#6103](https://github.com/vector-im/element-android/issues/6103))
- Fix sending multiple invites to a room reaching only one or two people ([#6109](https://github.com/vector-im/element-android/issues/6109))
- Prevent widget web view from reloading on screen / orientation change ([#6140](https://github.com/vector-im/element-android/issues/6140))
- Fix decrypting redacted event from sending errors ([#6148](https://github.com/vector-im/element-android/issues/6148))
- Make widget web view request system permissions for camera and microphone (PSF-1061) ([#6149](https://github.com/vector-im/element-android/issues/6149))
In development 🚧
----------------
- Adds email input and verification screens to the new FTUE onboarding flow ([#5278](https://github.com/vector-im/element-android/issues/5278))
- FTUE - Adds the redesigned Sign In screen ([#5283](https://github.com/vector-im/element-android/issues/5283))
- [Live location sharing] Update message in timeline during the live ([#5689](https://github.com/vector-im/element-android/issues/5689))
- FTUE - Overrides sign up flow ordering for matrix.org only ([#5783](https://github.com/vector-im/element-android/issues/5783))
- Live location sharing: navigation from timeline to map screen
Live location sharing: show user pins on map screen ([#6012](https://github.com/vector-im/element-android/issues/6012))
- FTUE - Adds homeserver login/register deeplink support ([#6023](https://github.com/vector-im/element-android/issues/6023))
- [Live location sharing] Update entity in DB when a live is timed out ([#6123](https://github.com/vector-im/element-android/issues/6123))
SDK API changes ⚠️
------------------
- Notifies other devices when a verification request sent from an Android device is accepted.` ([#5724](https://github.com/vector-im/element-android/issues/5724))
- Some `val` have been changed to `fun` to increase their visibility in the generated documentation. Just add `()` if you were using them.
- `KeysBackupService.state` has been replaced by `KeysBackupService.getState()`
- `KeysBackupService.isStucked` has been replaced by `KeysBackupService.isStuck()`
- SDK documentation improved ([#5952](https://github.com/vector-im/element-android/issues/5952))
- Improve replay attacks and reduce duplicate message index errors ([#6077](https://github.com/vector-im/element-android/issues/6077))
- Remove `RoomSummaryQueryParams.roomId`. If you need to observe a single room, use the new API `RoomService.getRoomSummaryLive(roomId: String)`
- `ActiveSpaceFilter` has been renamed to `SpaceFilter`
- `RoomCategoryFilter.ALL` has been removed, just pass `null` to not filter on Room category. ([#6143](https://github.com/vector-im/element-android/issues/6143))
Other changes
-------------
- leaving space experience changed to be aligned with iOS ([#5728](https://github.com/vector-im/element-android/issues/5728))
- @Ignore a number of tests that are currently failing in CI. ([#6025](https://github.com/vector-im/element-android/issues/6025))
- Remove ShortcutBadger lib and usage (it was dead code) ([#6041](https://github.com/vector-im/element-android/issues/6041))
- Test: Ensure calling 'fail()' is not caught by the catch block ([#6089](https://github.com/vector-im/element-android/issues/6089))
- Excludes transitive optional non FOSS google location dependency from fdroid builds ([#6100](https://github.com/vector-im/element-android/issues/6100))
- Fixed grammar errors in /vector/src/main/res/values/strings.xml ([#6132](https://github.com/vector-im/element-android/issues/6132))
- Downgrade gradle from 7.2.0 to 7.1.3 ([#6141](https://github.com/vector-im/element-android/issues/6141))
- Add Lao language to the in-app settings. ([#6196](https://github.com/vector-im/element-android/issues/6196))
- Remove the background location permission request ([#6198](https://github.com/vector-im/element-android/issues/6198))
Changes in Element v1.4.16 (2022-05-17) Changes in Element v1.4.16 (2022-05-17)
======================================= =======================================

View file

@ -41,6 +41,9 @@ plugins {
id "org.jlleitschuh.gradle.ktlint" version "10.3.0" id "org.jlleitschuh.gradle.ktlint" version "10.3.0"
// Detekt // Detekt
id "io.gitlab.arturbosch.detekt" version "1.20.0" id "io.gitlab.arturbosch.detekt" version "1.20.0"
// Dependency Analysis
id 'com.autonomousapps.dependency-analysis' version "1.4.0"
} }
// https://github.com/jeremylong/DependencyCheck // https://github.com/jeremylong/DependencyCheck
@ -219,3 +222,61 @@ project(":library:diff-match-patch") {
// } // }
// } // }
//} //}
dependencyAnalysis {
dependencies {
bundle("kotlin-stdlib") {
includeGroup("org.jetbrains.kotlin")
}
bundle("react") {
includeGroup("com.facebook.react")
}
}
issues {
all {
ignoreKtx(true)
onUsedTransitiveDependencies {
// Transitively used dependencies that should be declared directly
severity("ignore")
}
onUnusedDependencies {
severity("fail")
}
onUnusedAnnotationProcessors {
severity("fail")
exclude("com.airbnb.android:epoxy-processor", "com.google.dagger:hilt-compiler") // False positives
}
}
project(":library:jsonviewer") {
onUnusedDependencies {
exclude("org.json:json") // Used in unit tests, overwrites the one bundled into Android
}
}
project(":library:ui-styles") {
onUnusedDependencies {
exclude("com.github.vector-im:PFLockScreen-Android") // False positive
}
}
project(":matrix-sdk-android") {
onUnusedDependencies {
exclude("io.reactivex.rxjava2:rxkotlin") // Transitively required for mocking realm as monarchy doesn't expose Rx
}
}
project(":matrix-sdk-android-flow") {
onUnusedDependencies {
exclude("androidx.paging:paging-runtime-ktx") // False positive
}
}
project(":vector") {
onUnusedDependencies {
// False positives
exclude(
"com.vanniktech:emoji-google",
"com.vanniktech:emoji-material",
"org.maplibre.gl:android-plugin-annotation-v9",
"org.maplibre.gl:android-sdk",
)
}
}
}
}

View file

@ -1 +0,0 @@
Adds email input and verification screens to the new FTUE onboarding flow

1
changelog.d/5528.bugfix Normal file
View file

@ -0,0 +1 @@
Fix cases of missing, swapped, or duplicated messages

View file

@ -1 +0,0 @@
Space explore screen changes: removed space card, added rooms filtering

View file

@ -1 +0,0 @@
[Live location sharing] Update message in timeline during the live

View file

@ -1 +0,0 @@
- Notifies other devices when a verification request sent from an Android device is accepted.`

View file

@ -1 +0,0 @@
leaving space experience changed to be aligned with iOS

1
changelog.d/5970.feature Normal file
View file

@ -0,0 +1 @@
Make read receipt avatar list more compact

View file

@ -1 +0,0 @@
@Ignore a number of tests that are currently failing in CI.

View file

@ -1 +0,0 @@
Revert: Use member name instead of room name in DM creation item

View file

@ -1 +0,0 @@
Remove ShortcutBadger lib and usage (it was dead code)

View file

@ -1 +0,0 @@
Poll refactoring with unit tests

View file

@ -1 +0,0 @@
Test: Ensure calling 'fail()' is not caught by the catch block

1
changelog.d/6093.sdk Normal file
View file

@ -0,0 +1 @@
Allowing AuthenticationService.getLoginFlow to fail without resetting state from previously successful calls

View file

@ -1 +0,0 @@
Correct .well-known/matrix/client handling for server_names which include ports.

View file

@ -1 +0,0 @@
Labs flag for enabling live location sharing

View file

@ -1 +0,0 @@
Glide - Use current drawable while loading new static map image

View file

@ -1 +0,0 @@
Fix sending multiple invites to a room reaching only one or two people

View file

@ -7,10 +7,13 @@ ext.versions = [
'targetCompat' : JavaVersion.VERSION_11, 'targetCompat' : JavaVersion.VERSION_11,
] ]
def gradle = "7.2.0"
// Pinned to 7.1.3 because of https://github.com/vector-im/element-android/issues/6142
// Please test carefully before upgrading again.
def gradle = "7.1.3"
// Ref: https://kotlinlang.org/releases.html // Ref: https://kotlinlang.org/releases.html
def kotlin = "1.6.21" def kotlin = "1.6.21"
def kotlinCoroutines = "1.6.1" def kotlinCoroutines = "1.6.2"
def dagger = "2.42" def dagger = "2.42"
def retrofit = "2.9.0" def retrofit = "2.9.0"
def arrow = "0.8.2" def arrow = "0.8.2"
@ -23,7 +26,7 @@ def mavericks = "2.6.1"
def glide = "4.13.2" def glide = "4.13.2"
def bigImageViewer = "1.8.1" def bigImageViewer = "1.8.1"
def jjwt = "0.11.5" def jjwt = "0.11.5"
def vanniktechEmoji = "0.9.0" def vanniktechEmoji = "0.15.0"
// Testing // Testing
def mockk = "1.12.4" def mockk = "1.12.4"
@ -45,12 +48,13 @@ ext.libs = [
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines" 'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
], ],
androidx : [ androidx : [
'appCompat' : "androidx.appcompat:appcompat:1.4.1", 'activity' : "androidx.activity:activity:1.4.0",
'appCompat' : "androidx.appcompat:appcompat:1.4.2",
'core' : "androidx.core:core-ktx:1.7.0", 'core' : "androidx.core:core-ktx:1.7.0",
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1", 'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3", 'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3",
'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1", 'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1",
'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.3", 'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.4",
'work' : "androidx.work:work-runtime-ktx:2.7.1", 'work' : "androidx.work:work-runtime-ktx:2.7.1",
'autoFill' : "androidx.autofill:autofill:1.1.0", 'autoFill' : "androidx.autofill:autofill:1.1.0",
'preferenceKtx' : "androidx.preference:preference-ktx:1.2.0", 'preferenceKtx' : "androidx.preference:preference-ktx:1.2.0",
@ -69,10 +73,12 @@ ext.libs = [
'testRules' : "androidx.test:rules:$androidxTest", 'testRules' : "androidx.test:rules:$androidxTest",
'espressoCore' : "androidx.test.espresso:espresso-core:$espresso", 'espressoCore' : "androidx.test.espresso:espresso-core:$espresso",
'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso", 'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso",
'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso" 'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso",
'viewpager2' : "androidx.viewpager2:viewpager2:1.0.0",
'transition' : "androidx.transition:transition:1.2.0",
], ],
google : [ google : [
'material' : "com.google.android.material:material:1.6.0" 'material' : "com.google.android.material:material:1.6.1"
], ],
dagger : [ dagger : [
'dagger' : "com.google.dagger:dagger:$dagger", 'dagger' : "com.google.dagger:dagger:$dagger",
@ -81,7 +87,7 @@ ext.libs = [
'hiltCompiler' : "com.google.dagger:hilt-compiler:$dagger" 'hiltCompiler' : "com.google.dagger:hilt-compiler:$dagger"
], ],
squareup : [ squareup : [
'moshi' : "com.squareup.moshi:moshi-adapters:$moshi", 'moshi' : "com.squareup.moshi:moshi:$moshi",
'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi", 'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit", 'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit",
'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit" 'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit"
@ -107,6 +113,10 @@ ext.libs = [
'mavericks' : "com.airbnb.android:mavericks:$mavericks", 'mavericks' : "com.airbnb.android:mavericks:$mavericks",
'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks" 'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks"
], ],
maplibre : [
'androidSdk' : "org.maplibre.gl:android-sdk:9.5.2",
'pluginAnnotation' : "org.maplibre.gl:android-plugin-annotation-v9:1.0.0"
],
mockk : [ mockk : [
'mockk' : "io.mockk:mockk:$mockk", 'mockk' : "io.mockk:mockk:$mockk",
'mockkAndroid' : "io.mockk:mockk-android:$mockk" 'mockkAndroid' : "io.mockk:mockk-android:$mockk"

View file

@ -1,5 +1,34 @@
# Adding and removing ThreePids to an account # Adding and removing ThreePids to an account
<!--- TOC -->
* [Add email](#add-email)
* [User enter the email](#user-enter-the-email)
* [The email is already added to an account](#the-email-is-already-added-to-an-account)
* [The email is free](#the-email-is-free)
* [User receives an e-mail](#user-receives-an-e-mail)
* [User clicks on the link](#user-clicks-on-the-link)
* [User returns on Element](#user-returns-on-element)
* [User enters his password](#user-enters-his-password)
* [The link has not been clicked](#the-link-has-not-been-clicked)
* [Wrong password](#wrong-password)
* [The link has been clicked and the account password is correct](#the-link-has-been-clicked-and-the-account-password-is-correct)
* [Remove email](#remove-email)
* [User want to remove an email from his account](#user-want-to-remove-an-email-from-his-account)
* [Email was not bound to an identity server](#email-was-not-bound-to-an-identity-server)
* [Email was bound to an identity server](#email-was-bound-to-an-identity-server)
* [Add phone number](#add-phone-number)
* [The phone number is already added to an account](#the-phone-number-is-already-added-to-an-account)
* [The phone number is free](#the-phone-number-is-free)
* [User receive a text message](#user-receive-a-text-message)
* [User enter the code to the app](#user-enter-the-code-to-the-app)
* [Wrong code](#wrong-code)
* [Correct code](#correct-code)
* [Remove phone number](#remove-phone-number)
* [User wants to remove a phone number from his account](#user-wants-to-remove-a-phone-number-from-his-account)
<!--- END -->
## Add email ## Add email
### User enter the email ### User enter the email

View file

@ -1,5 +1,13 @@
# Analytics in Element # Analytics in Element
<!--- TOC -->
* [Solution](#solution)
* [How to add a new Event](#how-to-add-a-new-event)
* [Forks of Element](#forks-of-element)
<!--- END -->
## Solution ## Solution
Element is using PostHog to send analytics event. Element is using PostHog to send analytics event.

View file

@ -1,5 +1,14 @@
# Color migration # Color migration
<!--- TOC -->
* [Changes](#changes)
* [Main change for developers](#main-change-for-developers)
* [Remaining work](#remaining-work)
* [Migration guide](#migration-guide)
<!--- END -->
### Changes ### Changes
- use colors defined in https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=557%3A0 - use colors defined in https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=557%3A0

View file

@ -1,5 +1,31 @@
# Element Android design # Element Android design
<!--- TOC -->
* [Introduction](#introduction)
* [How to import from Figma to the Element Android project](#how-to-import-from-figma-to-the-element-android-project)
* [Colors](#colors)
* [Text](#text)
* [Dimension, position and margin](#dimension-position-and-margin)
* [Icons](#icons)
* [Export drawable from Figma](#export-drawable-from-figma)
* [Import in Android Studio](#import-in-android-studio)
* [Images](#images)
* [Figma links](#figma-links)
* [Coumpound](#coumpound)
* [Login](#login)
* [Login v2](#login-v2)
* [Room list](#room-list)
* [Timeline](#timeline)
* [Voice message](#voice-message)
* [Room settings](#room-settings)
* [VoIP](#voip)
* [Presence](#presence)
* [Spaces](#spaces)
* [List to be continued...](#list-to-be-continued)
<!--- END -->
## Introduction ## Introduction
Design at element.io is done using Figma - https://www.figma.com Design at element.io is done using Figma - https://www.figma.com

View file

@ -1,5 +1,19 @@
# Identity server # Identity server
<!--- TOC -->
* [Introduction](#introduction)
* [Implementation](#implementation)
* [Related MSCs](#related-mscs)
* [Steps and requirements](#steps-and-requirements)
* [Screens](#screens)
* [Settings](#settings)
* [Discovery screen](#discovery-screen)
* [Set identity server screen](#set-identity-server-screen)
* [Ref:](#ref:)
<!--- END -->
Issue: #607 Issue: #607
PR: #1354 PR: #1354

View file

@ -1,5 +1,18 @@
# Integration tests # Integration tests
<!--- TOC -->
* [Pre requirements](#pre-requirements)
* [Install and run Synapse](#install-and-run-synapse)
* [Run the test](#run-the-test)
* [Stop Synapse](#stop-synapse)
* [Troubleshoot](#troubleshoot)
* [Android Emulator does cannot reach the homeserver](#android-emulator-does-cannot-reach-the-homeserver)
* [Tests partially run but some fail with "Unable to contact localhost:8080"](#tests-partially-run-but-some-fail-with-"unable-to-contact-localhost:8080")
* [virtualenv command fails](#virtualenv-command-fails)
<!--- END -->
Integration tests are useful to ensure that the code works well for any use cases. Integration tests are useful to ensure that the code works well for any use cases.
They can also be used as sample on how to use the Matrix SDK. They can also be used as sample on how to use the Matrix SDK.

View file

@ -1,20 +1,32 @@
# Jitsi in Element Android # Jitsi in Element Android
<!--- TOC -->
* [Native Jitsi SDK](#native-jitsi-sdk)
* [How to build the Jitsi Meet SDK](#how-to-build-the-jitsi-meet-sdk)
* [Jitsi version](#jitsi-version)
* [Run the build script](#run-the-build-script)
* [Link with the new generated library](#link-with-the-new-generated-library)
* [Sanity tests](#sanity-tests)
* [Export the build library](#export-the-build-library)
<!--- END -->
Native Jitsi support has been added to Element Android by the PR [#1914](https://github.com/vector-im/element-android/pull/1914). The description of the PR contains some documentation about the behaviour in each possible room configuration. Native Jitsi support has been added to Element Android by the PR [#1914](https://github.com/vector-im/element-android/pull/1914). The description of the PR contains some documentation about the behaviour in each possible room configuration.
Also, ensure to have a look on [the documentation from Element Web](https://github.com/vector-im/element-web/blob/develop/docs/jitsi.md) Also, ensure to have a look on [the documentation from Element Web](https://github.com/vector-im/element-web/blob/develop/docs/jitsi.md)
The official documentation about how to integrate the Jitsi SDK in an Android app is available here: https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk. The official documentation about how to integrate the Jitsi SDK in an Android app is available here: https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk.
# Native Jitsi SDK ## Native Jitsi SDK
The Jitsi SDK is built by ourselves with the flag LIBRE_BUILD, to be able to be integrated on the F-Droid version of Element Android. The Jitsi SDK is built by ourselves with the flag LIBRE_BUILD, to be able to be integrated on the F-Droid version of Element Android.
The generated maven repository is then host in the project https://github.com/vector-im/jitsi_libre_maven The generated maven repository is then host in the project https://github.com/vector-im/jitsi_libre_maven
## How to build the Jitsi Meet SDK ### How to build the Jitsi Meet SDK
### Jitsi version #### Jitsi version
Update the script `./tools/jitsi/build_jisti_libs.sh` with the tag of the project `https://github.com/jitsi/jitsi-meet`. Update the script `./tools/jitsi/build_jisti_libs.sh` with the tag of the project `https://github.com/jitsi/jitsi-meet`.
@ -22,7 +34,7 @@ Latest tag can be found from this page: https://github.com/jitsi/jitsi-meet-rele
Currently we are building the version with the tag `android-sdk-3.10.0`. Currently we are building the version with the tag `android-sdk-3.10.0`.
### Run the build script #### Run the build script
At the root of the Element Android, run the following script: At the root of the Element Android, run the following script:
@ -32,7 +44,7 @@ At the root of the Element Android, run the following script:
It will build the Jitsi Meet Android library and put every generated files in the folder `/tmp/jitsi` It will build the Jitsi Meet Android library and put every generated files in the folder `/tmp/jitsi`
### Link with the new generated library #### Link with the new generated library
- Update the file `./build.gradle` to use the previously created local Maven repository. Currently we have this line: - Update the file `./build.gradle` to use the previously created local Maven repository. Currently we have this line:
@ -57,7 +69,7 @@ implementation('com.facebook.react:react-native-webrtc:1.92.1-jitsi-9093212@aar'
- Perform a gradle sync and build the project - Perform a gradle sync and build the project
- Perform test - Perform test
### Sanity tests #### Sanity tests
In order to validate that the upgrade of the Jitsi and WebRTC dependency does not break anything, the following sanity tests have to be performed, using two devices: In order to validate that the upgrade of the Jitsi and WebRTC dependency does not break anything, the following sanity tests have to be performed, using two devices:
- Make 1-1 audio call (so using WebRTC) - Make 1-1 audio call (so using WebRTC)
@ -65,7 +77,7 @@ In order to validate that the upgrade of the Jitsi and WebRTC dependency does no
- Create and join a conference call with audio only (so using Jitsi library). Leave the conference. Join it again. - Create and join a conference call with audio only (so using Jitsi library). Leave the conference. Join it again.
- Create and join a conference call with audio and video (so using Jitsi library) Leave the conference. Join it again. - Create and join a conference call with audio and video (so using Jitsi library) Leave the conference. Join it again.
### Export the build library #### Export the build library
If all the tests are passed, you can export the generated Jitsi library to our Maven repository. If all the tests are passed, you can export the generated Jitsi library to our Maven repository.

View file

@ -1,28 +1,33 @@
This document aims to describe how Element android displays notifications to the end user. It also clarifies notifications and background settings in the app. This document aims to describe how Element android displays notifications to the end user. It also clarifies notifications and background settings in the app.
# Table of Contents # Table of Contents
1. [Prerequisites Knowledge](#prerequisites-knowledge)
* [How does a matrix client get a message from a homeserver?](#how-does-a-matrix-client-get-a-message-from-a-homeserver) <!--- TOC -->
* [How does a mobile app receives push notification?](#how-does-a-mobile-app-receives-push-notification)
* [Prerequisites Knowledge](#prerequisites-knowledge)
* [How does a matrix client get a message from a homeserver?](#how-does-a-matrix-client-get-a-message-from-a-homeserver?)
* [How does a mobile app receives push notification](#how-does-a-mobile-app-receives-push-notification)
* [Push VS Notification](#push-vs-notification) * [Push VS Notification](#push-vs-notification)
* [Push in the matrix federated world](#push-in-the-matrix-federated-world) * [Push in the matrix federated world](#push-in-the-matrix-federated-world)
* [How does the homeserver know when to notify a client?](#how-does-the-homeserver-know-when-to-notify-a-client) * [How does the homeserver know when to notify a client?](#how-does-the-homeserver-know-when-to-notify-a-client?)
* [Push vs privacy, and mitigation](#push-vs-privacy-and-mitigation) * [Push vs privacy, and mitigation](#push-vs-privacy-and-mitigation)
* [Background processing limitations](#background-processing-limitations) * [Background processing limitations](#background-processing-limitations)
2. [Element Notification implementations](#element-notification-implementations) * [Element Notification implementations](#element-notification-implementations)
* [Requirements](#requirements) * [Requirements](#requirements)
* [Foreground sync mode (Gplay & F-Droid)](#foreground-sync-mode-gplay-f-droid) * [Foreground sync mode (Gplay and F-Droid)](#foreground-sync-mode-gplay-and-f-droid)
* [Push (FCM) received in background](#push-fcm-received-in-background) * [Push (FCM) received in background](#push-fcm-received-in-background)
* [FCM Fallback mode](#fcm-fallback-mode) * [FCM Fallback mode](#fcm-fallback-mode)
* [F-Droid background Mode](#f-droid-background-mode) * [F-Droid background Mode](#f-droid-background-mode)
3. [Application Settings](#application-settings) * [Application Settings](#application-settings)
<!--- END -->
First let's start with some prerequisite knowledge First let's start with some prerequisite knowledge
# Prerequisites Knowledge ## Prerequisites Knowledge
## How does a matrix client get a message from a homeserver? ### How does a matrix client get a message from a homeserver?
In order to get messages from a homeserver, a matrix client need to perform a ``sync`` operation. In order to get messages from a homeserver, a matrix client need to perform a ``sync`` operation.
@ -52,7 +57,7 @@ By default, this is 0, so the server will return immediately even if the respons
When the Element Android app is open (i.e in foreground state), the default timeout is 30 seconds, and delay is 0. When the Element Android app is open (i.e in foreground state), the default timeout is 30 seconds, and delay is 0.
## How does a mobile app receives push notification ### How does a mobile app receives push notification
Push notification is used as a way to wake up a mobile application when some important information is available and should be processed. Push notification is used as a way to wake up a mobile application when some important information is available and should be processed.
@ -67,21 +72,21 @@ FCM will only work on android devices that have Google plays services installed
De-Googlified devices need to rely on something else in order to stay up to date with a server. De-Googlified devices need to rely on something else in order to stay up to date with a server.
There some cases when devices with google services cannot use FCM (network infrastructure limitations -firewalls-, There some cases when devices with google services cannot use FCM (network infrastructure limitations -firewalls-,
privacy and or independency requirement, source code licence) privacy and or independence requirement, source code licence)
## Push VS Notification ### Push VS Notification
This need some disambiguation, because it is the source of common confusion: This need some disambiguation, because it is the source of common confusion:
*The fact that you see a notification on your screen does not mean that you have successfully configured your PUSH plateform.* *The fact that you see a notification on your screen does not mean that you have successfully configured your PUSH platform.*
Technically there is a difference between a push and a notification. A notification is what you see on screen and/or in the notification Menu/Drawer (in the top bar of the phone). Technically there is a difference between a push and a notification. A notification is what you see on screen and/or in the notification Menu/Drawer (in the top bar of the phone).
Notifications are not always triggered by a push (One can display a notification locally triggered by an alarm) Notifications are not always triggered by a push (One can display a notification locally triggered by an alarm)
## Push in the matrix federated world ### Push in the matrix federated world
In order to send a push to a mobile, App developers need to have a server that will use the FCM APIs, and these APIs requires authentication! In order to send a push to a mobile, App developers need to have a server that will use the FCM APIs, and these APIs requires authentication!
This server is called a **Push Gateway** in the matrix world This server is called a **Push Gateway** in the matrix world
@ -122,7 +127,7 @@ Recommended reading:
* https://matrix.org/docs/spec/client_server/r0.4.0.html#id128 * https://matrix.org/docs/spec/client_server/r0.4.0.html#id128
## How does the homeserver know when to notify a client? ### How does the homeserver know when to notify a client?
This is defined by [**push rules**](https://matrix.org/docs/spec/client_server/r0.4.0.html#push-rules-). This is defined by [**push rules**](https://matrix.org/docs/spec/client_server/r0.4.0.html#push-rules-).
@ -140,14 +145,14 @@ Of course, content patterns matching cannot be used for encrypted messages serve
That is why clients are able to **process the push rules client side** to decide what kind of notification should be presented for a given event. That is why clients are able to **process the push rules client side** to decide what kind of notification should be presented for a given event.
## Push vs privacy, and mitigation ### Push vs privacy, and mitigation
As seen previously, App developers don't directly send a push to the end user's device, they use a Push Provider as intermediary. So technically this intermediary is able to read the content of what is sent. As seen previously, App developers don't directly send a push to the end user's device, they use a Push Provider as intermediary. So technically this intermediary is able to read the content of what is sent.
App developers usually mitigate this by sending a `silent notification`, that is a notification with no identifiable data, or with an encrypted payload. When the push is received the app can then synchronise to it's server in order to generate a local notification. App developers usually mitigate this by sending a `silent notification`, that is a notification with no identifiable data, or with an encrypted payload. When the push is received the app can then synchronise to it's server in order to generate a local notification.
## Background processing limitations ### Background processing limitations
A mobile applications process live in a managed word, meaning that its process can be limited (e.g no network access), stopped or killed at almost anytime by the Operating System. A mobile applications process live in a managed word, meaning that its process can be limited (e.g no network access), stopped or killed at almost anytime by the Operating System.
@ -167,15 +172,15 @@ The documentation on this subject is vague, and as per our experiments not alway
It is getting more and more complex to have reliable notifications when FCM is not used. It is getting more and more complex to have reliable notifications when FCM is not used.
# Element Notification implementations ## Element Notification implementations
## Requirements ### Requirements
Element Android must work with and without FCM. Element Android must work with and without FCM.
* The Element android app published on F-Droid do not rely on FCM (all related dependencies are not present) * The Element android app published on F-Droid do not rely on FCM (all related dependencies are not present)
* The Element android app published on google play rely on FCM, with a fallback mode when FCM registration has failed (e.g outdated or missing Google Play Services) * The Element android app published on google play rely on FCM, with a fallback mode when FCM registration has failed (e.g outdated or missing Google Play Services)
## Foreground sync mode (Gplay & F-Droid) ### Foreground sync mode (Gplay and F-Droid)
When in foreground, Element performs sync continuously with a timeout value set to 10 seconds (see HttpPooling). When in foreground, Element performs sync continuously with a timeout value set to 10 seconds (see HttpPooling).
@ -183,9 +188,9 @@ As this mode does not need to live beyond the scope of the application, and as p
This mode is turned on when the app enters foreground, and off when enters background. This mode is turned on when the app enters foreground, and off when enters background.
In background, and depending on wether push is available or not, Element will use different methods to perform the syncs (Workers / Alarms / Service) In background, and depending on whether push is available or not, Element will use different methods to perform the syncs (Workers / Alarms / Service)
## Push (FCM) received in background ### Push (FCM) received in background
In order to enable Push, Element must first get a push token from the firebase SDK, then register a pusher with this token on the homeserver. In order to enable Push, Element must first get a push token from the firebase SDK, then register a pusher with this token on the homeserver.
@ -225,10 +230,10 @@ Upon reception of the FCM push, Element will perform a sync call to the homeserv
Element implements several strategies in these cases (TODO document) Element implements several strategies in these cases (TODO document)
## FCM Fallback mode ### FCM Fallback mode
It is possible that Element is not able to get a FCM push token. It is possible that Element is not able to get a FCM push token.
Common errors (amoung several others) that can cause that: Common errors (among several others) that can cause that:
* Google Play Services is outdated * Google Play Services is outdated
* Google Play Service fails in someways with FCM servers (infamous `SERVICE_NOT_AVAILABLE`) * Google Play Service fails in someways with FCM servers (infamous `SERVICE_NOT_AVAILABLE`)
@ -246,7 +251,7 @@ Usually in this mode, what happen is when you take back your phone in your hand,
The fallback mode is supposed to be a temporary state waiting for the user to fix issues for FCM, or for App Developers that has done a fork to correctly configure their FCM settings. The fallback mode is supposed to be a temporary state waiting for the user to fix issues for FCM, or for App Developers that has done a fork to correctly configure their FCM settings.
## F-Droid background Mode ### F-Droid background Mode
The F-Droid Element flavor has no dependencies to FCM, therefore cannot relies on Push. The F-Droid Element flavor has no dependencies to FCM, therefore cannot relies on Push.
@ -256,7 +261,7 @@ Only solution left is to use `AlarmManager`, that offers new API to allow launch
Notice that these alarms, due to their potential impact on battery life, can still be restricted by the system. Documentation says that they will not be triggered more than every minutes under normal system operation, and when in low power mode about every 15 mn. Notice that these alarms, due to their potential impact on battery life, can still be restricted by the system. Documentation says that they will not be triggered more than every minutes under normal system operation, and when in low power mode about every 15 mn.
These restrictions can be relaxed by requirering the app to be white listed from battery optimization. These restrictions can be relaxed by requiring the app to be white listed from battery optimization.
F-Droid version will schedule alarms that will then trigger a Broadcast Receiver, that in turn will launch a Service (in the classic android way), and the reschedule an alarm for next time. F-Droid version will schedule alarms that will then trigger a Broadcast Receiver, that in turn will launch a Service (in the classic android way), and the reschedule an alarm for next time.
@ -266,9 +271,7 @@ That is why on Element F-Droid, the broadcast receiver will acquire a temporary
Note that foreground services require to put a notification informing the user that the app is doing something even if not launched). Note that foreground services require to put a notification informing the user that the app is doing something even if not launched).
## Application Settings
# Application Settings
**Notifications > Enable notifications for this account** **Notifications > Enable notifications for this account**

View file

@ -1,5 +1,43 @@
# Pull requests # Pull requests
<!--- TOC -->
* [Introduction](#introduction)
* [Who should read this document?](#who-should-read-this-document?)
* [Submitting PR](#submitting-pr)
* [Who can submit pull requests?](#who-can-submit-pull-requests?)
* [Humans](#humans)
* [Draft PR?](#draft-pr?)
* [Base branch](#base-branch)
* [PR Review Assignment](#pr-review-assignment)
* [PR review time](#pr-review-time)
* [Re-request PR review](#re-request-pr-review)
* [When create split PR?](#when-create-split-pr?)
* [Avoid fixing other unrelated issue in a big PR](#avoid-fixing-other-unrelated-issue-in-a-big-pr)
* [Bots](#bots)
* [Dependabot](#dependabot)
* [Gradle wrapper](#gradle-wrapper)
* [Sync analytics plan](#sync-analytics-plan)
* [Reviewing PR](#reviewing-pr)
* [Who can review pull requests?](#who-can-review-pull-requests?)
* [What to have in mind when reviewing a PR](#what-to-have-in-mind-when-reviewing-a-pr)
* [Rules](#rules)
* [Check the form](#check-the-form)
* [PR title](#pr-title)
* [PR description](#pr-description)
* [File change](#file-change)
* [Check the commit](#check-the-commit)
* [Check the substance](#check-the-substance)
* [Make a dedicated meeting to review the PR](#make-a-dedicated-meeting-to-review-the-pr)
* [What happen to the issue(s)?](#what-happen-to-the-issues?)
* [Merge conflict](#merge-conflict)
* [When and who can merge PR](#when-and-who-can-merge-pr)
* [Merge type](#merge-type)
* [Resolve conversation](#resolve-conversation)
* [Responsibility](#responsibility)
<!--- END -->
## Introduction ## Introduction
This document gives some clue about how to efficiently manage Pull Requests (PR). This document is a first draft and may be improved later. This document gives some clue about how to efficiently manage Pull Requests (PR). This document is a first draft and may be improved later.

View file

@ -2,6 +2,27 @@
This document describes the flow of signin to a homeserver, and also the flow when user want to reset his password. Examples come from the `matrix.org` homeserver. This document describes the flow of signin to a homeserver, and also the flow when user want to reset his password. Examples come from the `matrix.org` homeserver.
<!--- TOC -->
* [Sign in flows](#sign-in-flows)
* [Get the flow](#get-the-flow)
* [Login with username](#login-with-username)
* [Incorrect password](#incorrect-password)
* [Correct password:](#correct-password:)
* [Login with email](#login-with-email)
* [Unknown email](#unknown-email)
* [Known email, wrong password](#known-email-wrong-password)
* [Known email, correct password](#known-email-correct-password)
* [Login with Msisdn](#login-with-msisdn)
* [Login with SSO](#login-with-sso)
* [Reset password](#reset-password)
* [Send email](#send-email)
* [When the email is not known](#when-the-email-is-not-known)
* [When the email is known](#when-the-email-is-known)
* [User clicks on the link](#user-clicks-on-the-link)
<!--- END -->
## Sign in flows ## Sign in flows
### Get the flow ### Get the flow

View file

@ -4,6 +4,20 @@ This document describes the flow of registration to a homeserver. Examples come
*Ref*: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management *Ref*: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
<!--- TOC -->
* [Sign up flows](#sign-up-flows)
* [First step](#first-step)
* [Step 1: entering user name and password](#step-1:-entering-user-name-and-password)
* [If username already exists](#if-username-already-exists)
* [Step 2: entering email](#step-2:-entering-email)
* [Step 2 bis: user enters an email](#step-2-bis:-user-enters-an-email)
* [Step 3: Accepting T&C](#step-3:-accepting-t&c)
* [Step 4: Captcha](#step-4:-captcha)
* [Step 5: MSISDN](#step-5:-msisdn)
<!--- END -->
## Sign up flows ## Sign up flows
### First step ### First step

View file

@ -10,6 +10,20 @@ Currently the test are covering a small set of application flows:
- Self verification via emoji - Self verification via emoji
- Self verification via passphrase - Self verification via passphrase
<!--- TOC -->
* [Prerequisites:](#prerequisites:)
* [Run the tests](#run-the-tests)
* [From the source code](#from-the-source-code)
* [From command line](#from-command-line)
* [Recipes](#recipes)
* [Wait for initial sync](#wait-for-initial-sync)
* [Accessing current activity](#accessing-current-activity)
* [Interact with other session](#interact-with-other-session)
* [Contributing to the UiAllScreensSanityTest](#contributing-to-the-uiallscreenssanitytest)
<!--- END -->
## Prerequisites: ## Prerequisites:
Out of the box, the tests use one of the homeservers (located at http://localhost:8080) of the "Demo Federation of Homeservers" (https://github.com/matrix-org/synapse#running-a-demo-federation-of-synapses). Out of the box, the tests use one of the homeservers (located at http://localhost:8080) of the "Demo Federation of Homeservers" (https://github.com/matrix-org/synapse#running-a-demo-federation-of-synapses).

View file

@ -0,0 +1,2 @@
Hlavní změny v této verzi: Zlepšení správy ignorovaných uživatelů. Opravy různých chyb a vylepšení stability.
Úplný seznam změn: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Main changes in this version: Various bug fixes and stability improvements.
Full changelog: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Cambios principales en esta versión: Mejoras en la administración de usuarios ignorados. Varias correciones de bugs y mejoras en la estabilidad.
Registro de cambios: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: eiratud kasutajate parem haldus ning erinevate vigade parandused ja stabiilsust edendavad kohendused.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
تغییرات عمده در این نگارش: مدیریت بهبودیافتهٔ کاربران چشم‌پوشیده. رفع اشکال‌های مختلف و بهبودهای پایداری.
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Défilement dans les messages vocaux. Plusieurs corrections de bogues et daméliorations de stabilité.
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Plusieurs corrections de bogues et daméliorations de stabilité.
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Les utilisateurs peuvent apparaître hors-ligne. Ajout dun lecteur pour les pièces jointes audio
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Les utilisateurs peuvent apparaître hors-ligne. Ajout dun lecteur pour les pièces jointes audio
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principaux changements pour cette version : Amélioration de la gestion des utilisateurs ignorés. Plusieurs corrections de bogues et daméliorations de stabilité.
Intégralité des changements : https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Perubahan utama dalam versi ini: Tingkatkan pengelolaan pengguna yang diabaikan. Beberapa perbaikan kutu dan stabilitas.
Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Modifiche principali in questa versione: migliorata la gestione degli utenti ignorati. Varie correzioni e miglioramenti della stabilità.
Cronologia completa: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
ການປ່ຽນແປງຫຼັກໃນສະບັບນີ້: ປັບປຸງການບໍລິຫານການລະເວັ້ນຜູ້ໃຊ້. ປັບປຸງບັກ ແລະຄວາມສະຖຽນ.
ບັນທຶກການປ່ຽນແປງສະບັບເຕັມ: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: aktualizacja motywu i stylu oraz naprawa awarii po rozmowie wideo
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.12

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: głównie aktualizacja stabilności i poprawki błędów.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.13

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: naprawienie problemu z zaszyfrowanymi wiadomościami.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.14

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: implementacja wiadomości głosowych w ustawieniach laboratorium.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.15

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Naprawiono błąd podczas wysyłania zaszyfrowanej wiadomości, jeśli ktoś w pokoju się wyloguje.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.1.16

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Wiadomość głosowa jest domyślnie włączona.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.2.0

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Wiele ulepszeń w VoIP i Przestrzeniach (nadal w wersji beta).
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.2.1

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Organizuj swoje pokoje za pomocą Przestrzeni!
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.3.0

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Organizuj swoje pokoje za pomocą Przestrzeni! Wersja 1.3.1 naprawia awarię, która może wystąpić w wersji 1.3.0.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.3.1

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Dodano obsługę Android Auto. Wiele poprawek błędów!
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.3.2

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Uwidocznij politykę(-i) serwera tożsamości w ustawieniach. Tymczasowo usunięto obsługę Androida Auto.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.3.3

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Dodanie obsługi obecności, dla pokoju wiadomości bezpośrednich (uwaga: obecność jest wyłączona na matrix.org). Dodano ponownie obsługę Androida Auto.
Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.3.4

View file

@ -0,0 +1,2 @@
Główne zmiany w tej wersji: Poprawa zarządzania ignorowanymi użytkownikami. Różne poprawki błędów i ulepszenia stabilności.
Pełna lista zmian: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Principais mudanças nesta versão: Melhorar gerenciamento de usuárias(os) ignoradas(os). Vários consertos de bugs e melhorias de estabilidade.
Changelog completo: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Hlavné zmeny v tejto verzii: Zlepšenie správy ignorovaných používateľov. Rôzne opravy chýb a vylepšenia stability.
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: Förbättra hantering av ignorerade användare. Diverse buggfixar och stabilitetsförbättringar.
Full ändringslogg: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
இந்த பதிப்பில் உள்ள முதன்மை மாற்றங்கள்: தவிர்க்கப்பட்ட பயனர்களின் மேலாண்மை மேம்படுத்தப்பட்டுள்ளது. வெவ்வேறு வழுக்களைச் சரிசெய்தல் மற்றும் நிலைப்புத்தன்மையை மேம்படுத்தல்.
முழு மாற்ற அறிக்கை: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,42 @@
Element is both a secure messenger and a productivity team collaboration app that is ideal for group chats while remote working. This chat app uses end-to-end encryption to provide powerful video conferencing, file sharing and voice calls.
<b>Element இன் தனிச்சிறப்புகளுள் சில:</b>
- மேம்பட்ட இயங்கலை தொடர்பு கருவிகள்
- தொலைநிலையில் உள்ள ஊழியர்களுக்கும், பாதுகாப்பான நிறும கருத்து பரிமாற்றங்களை அனுமதிப்பதற்காக, முழுவதுமாக மறைகுறியாக்கப்பட்ட செய்திகள்
- MATRIX திறந்த மூல கட்டமைப்பை அடிப்படையாக கொண்டு செயல்படும் அதிகாரப்பரவலாக்கப்பட்ட அரட்டை
- செயல்திட்டங்களை மேலாண்மை செய்யும் போது, மறைகுறியாக்கப்பட்ட தரவுடன் கூடிய பாதுகாப்பான கோப்பு பகிரல்
- IP மூலம் குரல் (VoIP) மற்றும் திரை பகிரல் உடன் கூடிய குரல் அரட்டைகள்
- உங்கள் மனம் கவர்ந்த இயங்கலை உடனிணைவு கருவிகள், செயல்திட்ட மேலாண்மை கருவிகள், VoIP சேவைகள் மற்றும் இதர குழு தூதுரை செயலிகள் உடன் கூடிய எளிமையான ஒருமைப்பாடு
Element is completely different from other messaging and collaboration apps. It operates on Matrix, an open network for secure messaging and decentralized communication. It allows self-hosting to give users maximum ownership and control of their data and messages.
<b>தனியுரிமை மற்றும் மறைகுறியாக்கப்பட்ட செய்தி அனுப்பல்</b>
தேவையில்லாத விளம்பரங்கள், தரவு சுரண்டல் மற்றும் தகவல் கட்டுப்பாடு போன்றவற்றில் இருந்து Element உங்களை பாதுகாக்கிறது. மேலும், இது முனைக்கு-முனை மறைகுறியாக்கம் மற்றும் குறுக்கு-ஒப்பமிடப்பட்ட சாதன சரிபார்ப்பு ஆகியவற்றின் மூலம் உங்கள் எல்லா தரவுகள், ஒன்றுக்கொன்றான காணொளி மற்றும் குரல் அழைப்புகளை பாதுகாக்கிறது.
Element gives you control over your privacy while allowing you to communicate securely with யாரோனும் ஒருவருடன் on the Matrix network, or other business collaboration tools by integrating with apps such as Slack.
<b>Element can be self-hosted</b>
To allow more control of your sensitive data and conversations, Element can be self-hosted or you can choose any Matrix-based host - the standard for open source, decentralized communication. Element gives you privacy, security compliance and integration flexibility.
<b>உங்கள் தரவைச் சொந்தமாக்கிக் கொள்ளுங்கள்</b>
தரவுகள் மற்றும் செய்திகளை எங்கு சேமித்து வைக்க வேண்டும் என்பதை நீங்கள் முடிவு செய்கிறீர்கள். இதன்மூலம், தரவு சுரண்டல் மற்றும் மூன்றாம் தரப்பினர் அனுகல் ஆகிய இடர்களை தவிர்க்கலாம்.
Element வெவ்வேறு வகையில் கட்டுப்பாட்டை உங்களிடம் அளிக்கிறது:
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
2. Self-host your account by running a server on your own IT infrastructure
3. Sign up for an account on a custom server by simply subscribing to the Element Matrix Services hosting platform
<b>திறந்த செய்தி அனுப்பல் மற்றும் ஒருமைப்பாடு</b>
You can chat with anyone on the Matrix network, whether theyre using Element, another Matrix app or even if they are using a different messaging app.
<b>மிகவும் பாதுகாப்பானது</b>
உண்மையான முனைக்கு-முனை மறைகுறியாக்கம் (உரையாடலில் உள்ளவர்கள் மட்டுமே மறைகுறியாக்கத்தை நீக்கி செய்தியை காண இயலும்) மற்றும் குறுக்கு-ஒப்பமிடப்பட்ட சாதன சரிபார்ப்பு.
<b>முழுமையான தொடர்பு மற்றும் ஒருமைப்பாடு</b>
செய்தி அனுப்பல், காணொளி மற்றும் குரல் அழைப்புகளை, கோப்பு பகிரல், திரை பகிரல் மற்றும் ஒருமைப்பாடுகள், இயலிகள் மற்றும் நிரல் பலகைகளின் மொத்த கொத்து. அறைகள், குழுக்களை உருவாக்கி, அவர்களுடன் உரையாடி, வேலையை எளிமையாக்கவும்.
<b>எங்கு விட்டு சென்றீர்களோ அதிலிருந்த துவங்கவும்</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>திறந்த மூலம்</b>
Element Android ஒரு திறந்த மூல செயல் திட்டமாகும். இது GitHub இல் தொகுத்து வழங்கப்பட்டுள்ளது. வழுக்கள் ஏதேனும் கண்டறிந்தால் மற்றும்/அல்லது இதன் வளர்ச்சிக்கு பங்களிக்க விரும்பினால், https://github.com/vector-im/element-android என்னும் தளத்திற்கு வருகை தரவும்.

View file

@ -0,0 +1 @@
மறைகுறியாக்கப்பட்ட செய்தி அனுப்பல், குழு அரட்டை மற்றும் காணொளி அழைப்புகள்

View file

@ -0,0 +1 @@
Element - பாதுகாப்பான தூதுரை சேவை

View file

@ -0,0 +1,2 @@
Основні зміни у цій версії: Удосконалено керування нехтуваними користувачами. Різні виправлення помилок та поліпшення стабільності.
Вичерпний журнал змін: https://github.com/vector-im/element-android/releases

View file

@ -0,0 +1,2 @@
此版本中的主要變動:改善被忽略使用者的管理。多個臭蟲修復與穩定性改善。
完整的變更紀錄https://github.com/vector-im/element-android/releases

View file

@ -55,5 +55,6 @@ dependencies {
implementation libs.androidx.appCompat implementation libs.androidx.appCompat
implementation libs.androidx.recyclerview implementation libs.androidx.recyclerview
implementation libs.google.material api libs.androidx.viewpager2
implementation libs.androidx.transition
} }

View file

@ -50,6 +50,5 @@ android {
} }
dependencies { dependencies {
implementation libs.androidx.appCompat
implementation libs.jetbrains.coroutinesAndroid implementation libs.jetbrains.coroutinesAndroid
} }

View file

@ -52,6 +52,7 @@ dependencies {
implementation libs.androidx.appCompat implementation libs.androidx.appCompat
implementation libs.androidx.core implementation libs.androidx.core
implementation libs.androidx.recyclerview
implementation libs.airbnb.epoxy implementation libs.airbnb.epoxy
kapt libs.airbnb.epoxyProcessor kapt libs.airbnb.epoxyProcessor
@ -60,7 +61,6 @@ dependencies {
// Span utils // Span utils
implementation 'me.gujun.android:span:1.7' implementation 'me.gujun.android:span:1.7'
implementation libs.google.material
implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesCore
implementation libs.jetbrains.coroutinesAndroid implementation libs.jetbrains.coroutinesAndroid

View file

@ -38,9 +38,9 @@ android {
} }
dependencies { dependencies {
implementation libs.androidx.appCompat api libs.androidx.activity
implementation libs.androidx.fragmentKtx
implementation libs.androidx.exifinterface implementation libs.androidx.exifinterface
implementation libs.androidx.core
// Log // Log
implementation libs.jakewharton.timber implementation libs.jakewharton.timber

View file

@ -18,4 +18,26 @@
<item name="android:gravity">center</item> <item name="android:gravity">center</item>
</style> </style>
<style name="TextAppearance.Vector.Body.BottomSheetDisplayName">
<item name="android:textSize">16sp</item>
</style>
<style name="TextAppearance.Vector.Body.BottomSheetRemainingTime">
<item name="android:textSize">12sp</item>
</style>
<style name="TextAppearance.Vector.Body.BottomSheetLastUpdatedAt">
<item name="android:textSize">12sp</item>
<item name="android:textColor">?vctr_content_tertiary</item>
</style>
<style name="Widget.Vector.Button.Text.BottomSheetStopSharing">
<item name="android:foreground">?selectableItemBackground</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:textAppearance">@style/TextAppearance.Vector.Body.Medium</item>
<item name="android:textColor">?colorError</item>
<item name="android:padding">0dp</item>
<item name="android:gravity">center</item>
</style>
</resources> </resources>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="TimelineContentStubBaseParams"> <style name="TimelineContentStubBaseParams">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
@ -33,5 +33,8 @@
<item name="android:gravity">center</item> <item name="android:gravity">center</item>
</style> </style>
<style name="TimelineFixedSizeCaptionStyle" parent="@style/Widget.Vector.TextView.Caption">
<item name="android:textSize" tools:ignore="SpUsage">12dp</item>
</style>
</resources> </resources>

View file

@ -31,9 +31,7 @@ android {
} }
dependencies { dependencies {
implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android")
implementation libs.androidx.appCompat
implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesCore
implementation libs.jetbrains.coroutinesAndroid implementation libs.jetbrains.coroutinesAndroid
@ -41,7 +39,4 @@ dependencies {
// Paging // Paging
implementation libs.androidx.pagingRuntimeKtx implementation libs.androidx.pagingRuntimeKtx
// Logging
implementation libs.jakewharton.timber
} }

View file

@ -45,6 +45,13 @@ import org.matrix.android.sdk.api.util.toOptional
class FlowSession(private val session: Session) { class FlowSession(private val session: Session) {
fun liveRoomSummary(roomId: String): Flow<Optional<RoomSummary>> {
return session.roomService().getRoomSummaryLive(roomId).asFlow()
.startWith(session.coroutineDispatchers.io) {
session.roomService().getRoomSummary(roomId).toOptional()
}
}
fun liveRoomSummaries(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder = RoomSortOrder.NONE): Flow<List<RoomSummary>> { fun liveRoomSummaries(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder = RoomSortOrder.NONE): Flow<List<RoomSummary>> {
return session.roomService().getRoomSummariesLive(queryParams, sortOrder).asFlow() return session.roomService().getRoomSummariesLive(queryParams, sortOrder).asFlow()
.startWith(session.coroutineDispatchers.io) { .startWith(session.coroutineDispatchers.io) {

View file

@ -56,7 +56,7 @@ android {
// that the app's state is completely cleared between tests. // that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.4.18\"" buildConfigField "String", "SDK_VERSION", "\"1.4.20\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
@ -136,7 +136,6 @@ dependencies {
implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesCore
implementation libs.jetbrains.coroutinesAndroid implementation libs.jetbrains.coroutinesAndroid
implementation libs.androidx.appCompat
implementation libs.androidx.core implementation libs.androidx.core
// Lifecycle // Lifecycle
@ -155,12 +154,11 @@ dependencies {
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3")) implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
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 libs.squareup.moshi implementation libs.squareup.moshi
kapt libs.squareup.moshiKotlin kapt libs.squareup.moshiKotlin
implementation libs.markwon.core api "com.atlassian.commonmark:commonmark:0.13.0"
// Image // Image
implementation libs.androidx.exifinterface implementation libs.androidx.exifinterface
@ -176,10 +174,6 @@ dependencies {
// Work // Work
implementation libs.androidx.work implementation libs.androidx.work
// FP
implementation libs.arrow.core
implementation libs.arrow.instances
// olm lib is now hosted in MavenCentral // olm lib is now hosted in MavenCentral
implementation 'org.matrix.android:olm-sdk:3.2.11' implementation 'org.matrix.android:olm-sdk:3.2.11'
@ -198,11 +192,9 @@ dependencies {
implementation libs.apache.commonsImaging implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.48' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.49'
testImplementation libs.tests.junit testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.7.3'
//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 libs.mockk.mockk testImplementation libs.mockk.mockk
testImplementation libs.tests.kluent testImplementation libs.tests.kluent

View file

@ -1,3 +1,7 @@
# Package org.matrix.android.sdk.userstories
This package contains some user stories (**Us** prefix) of the SDK usage. You will find example of what it is possible to do with the SDK and the API which can be used to do it.
# Package org.matrix.android.sdk.api # Package org.matrix.android.sdk.api
This is the root package of the API exposed by this SDK. This is the root package of the API exposed by this SDK.

View file

@ -24,8 +24,8 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4 import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
@ -34,32 +34,22 @@ import org.matrix.android.sdk.common.TestConstants
@LargeTest @LargeTest
class AccountCreationTest : InstrumentedTest { class AccountCreationTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
@Test @Test
fun createAccountTest() { fun createAccountTest() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
commonTestHelper.signOutAndClose(session)
} }
@Test @Test
@Ignore("This test will be ignored until it is fixed") @Ignore("This test will be ignored until it is fixed")
fun createAccountAndLoginAgainTest() { fun createAccountAndLoginAgainTest() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
// Log again to the same account // Log again to the same account
val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true)) commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
commonTestHelper.signOutAndClose(session)
commonTestHelper.signOutAndClose(session2)
} }
@Test @Test
fun simpleE2eTest() { fun simpleE2eTest() = runCryptoTest(context()) { cryptoTestHelper, _ ->
val res = cryptoTestHelper.doE2ETestWithAliceInARoom() cryptoTestHelper.doE2ETestWithAliceInARoom()
res.cleanUp(commonTestHelper)
} }
} }

View file

@ -25,7 +25,7 @@ import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
@ -34,14 +34,12 @@ import org.matrix.android.sdk.common.TestConstants
@Ignore("This test will be ignored until it is fixed") @Ignore("This test will be ignored until it is fixed")
class ChangePasswordTest : InstrumentedTest { class ChangePasswordTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
companion object { companion object {
private const val NEW_PASSWORD = "this is a new password" private const val NEW_PASSWORD = "this is a new password"
} }
@Test @Test
fun changePasswordTest() { fun changePasswordTest() = runSessionTest(context()) { commonTestHelper ->
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false)) val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
// Change password // Change password
@ -54,9 +52,6 @@ class ChangePasswordTest : InstrumentedTest {
throwable.isInvalidPassword().shouldBeTrue() throwable.isInvalidPassword().shouldBeTrue()
// Try to login with the new password, should work // Try to login with the new password, should work
val session2 = commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false)) commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false))
commonTestHelper.signOutAndClose(session)
commonTestHelper.signOutAndClose(session2)
} }
} }

View file

@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
@ -39,10 +39,8 @@ import kotlin.coroutines.resume
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
class DeactivateAccountTest : InstrumentedTest { class DeactivateAccountTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
@Test @Test
fun deactivateAccountTest() { fun deactivateAccountTest() = runSessionTest(context(), false /* session will be deactivated */) { commonTestHelper ->
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
// Deactivate the account // Deactivate the account

View file

@ -23,7 +23,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4 import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
import timber.log.Timber import timber.log.Timber
@ -32,10 +32,8 @@ import timber.log.Timber
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
class ApiInterceptorTest : InstrumentedTest { class ApiInterceptorTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
@Test @Test
fun apiInterceptorTest() { fun apiInterceptorTest() = runSessionTest(context()) { commonTestHelper ->
val responses = mutableListOf<String>() val responses = mutableListOf<String>()
val listener = object : ApiInterceptorListener { val listener = object : ApiInterceptorListener {

View file

@ -54,12 +54,39 @@ import java.util.concurrent.TimeUnit
* This class exposes methods to be used in common cases * This class exposes methods to be used in common cases
* Registration, login, Sync, Sending messages... * Registration, login, Sync, Sending messages...
*/ */
class CommonTestHelper(context: Context) { class CommonTestHelper private constructor(context: Context) {
companion object {
internal fun runSessionTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CommonTestHelper) -> Unit) {
val testHelper = CommonTestHelper(context)
return try {
block(testHelper)
} finally {
if (autoSignoutOnClose) {
testHelper.cleanUpOpenedSessions()
}
}
}
internal fun runCryptoTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CryptoTestHelper, CommonTestHelper) -> Unit) {
val testHelper = CommonTestHelper(context)
val cryptoTestHelper = CryptoTestHelper(testHelper)
return try {
block(cryptoTestHelper, testHelper)
} finally {
if (autoSignoutOnClose) {
testHelper.cleanUpOpenedSessions()
}
}
}
}
internal val matrix: TestMatrix internal val matrix: TestMatrix
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private var accountNumber = 0 private var accountNumber = 0
private val trackedSessions = mutableListOf<Session>()
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
init { init {
@ -84,6 +111,15 @@ class CommonTestHelper(context: Context) {
return logIntoAccount(userId, TestConstants.PASSWORD, testParams) return logIntoAccount(userId, TestConstants.PASSWORD, testParams)
} }
fun cleanUpOpenedSessions() {
trackedSessions.forEach {
runBlockingTest {
it.signOutService().signOut(true)
}
}
trackedSessions.clear()
}
/** /**
* Create a homeserver configuration, with Http connection allowed for test * Create a homeserver configuration, with Http connection allowed for test
*/ */
@ -248,7 +284,9 @@ class CommonTestHelper(context: Context) {
testParams testParams
) )
assertNotNull(session) assertNotNull(session)
return session return session.also {
trackedSessions.add(session)
}
} }
/** /**
@ -266,7 +304,9 @@ class CommonTestHelper(context: Context) {
): Session { ): Session {
val session = logAccountAndSync(userId, password, testParams) val session = logAccountAndSync(userId, password, testParams)
assertNotNull(session) assertNotNull(session)
return session return session.also {
trackedSessions.add(session)
}
} }
/** /**
@ -447,6 +487,7 @@ class CommonTestHelper(context: Context) {
fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) } fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) }
fun signOutAndClose(session: Session) { fun signOutAndClose(session: Session) {
trackedSessions.remove(session)
runBlockingTest(timeout = 60_000) { runBlockingTest(timeout = 60_000) {
session.signOutService().signOut(true) session.signOutService().signOut(true)
} }

View file

@ -58,7 +58,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.securestorage.EmptyKeySigner import org.matrix.android.sdk.api.session.securestorage.EmptyKeySigner
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService import org.matrix.android.sdk.api.session.securestorage.KeyRef
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.api.util.awaitCallback
import org.matrix.android.sdk.api.util.toBase64NoPadding import org.matrix.android.sdk.api.util.toBase64NoPadding
@ -66,7 +66,7 @@ import java.util.UUID
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
class CryptoTestHelper(private val testHelper: CommonTestHelper) { class CryptoTestHelper(val testHelper: CommonTestHelper) {
private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!") private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.") private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
@ -361,19 +361,19 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
ssssService.storeSecret( ssssService.storeSecret(
MASTER_KEY_SSSS_NAME, MASTER_KEY_SSSS_NAME,
session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master!!, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master!!,
listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
) )
ssssService.storeSecret( ssssService.storeSecret(
SELF_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME,
session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned!!, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned!!,
listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
) )
ssssService.storeSecret( ssssService.storeSecret(
USER_SIGNING_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME,
session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user!!, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user!!,
listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
) )
// set up megolm backup // set up megolm backup
@ -390,7 +390,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
ssssService.storeSecret( ssssService.storeSecret(
KEYBACKUP_SECRET_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME,
secret, secret,
listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
) )
} }
} }

View file

@ -40,6 +40,9 @@ class RetryTestRule(val retryCount: Int = 3) : TestRule {
for (i in 0 until retryCount) { for (i in 0 until retryCount) {
try { try {
base.evaluate() base.evaluate()
if (i > 0) {
println("Retried test $i times")
}
return return
} catch (t: Throwable) { } catch (t: Throwable) {
caughtThrowable = t caughtThrowable = t

View file

@ -0,0 +1,75 @@
/*
* Copyright 2022 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 androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert
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.Event
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class DecryptRedactedEventTest : InstrumentedTest {
@Test
fun doNotFailToDecryptRedactedEvent() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val e2eRoomID = testData.roomId
val aliceSession = testData.firstSession
val bobSession = testData.secondSession!!
val roomALicePOV = aliceSession.getRoom(e2eRoomID)!!
val timelineEvent = testHelper.sendTextMessage(roomALicePOV, "Hello", 1).first()
val redactionReason = "Wrong Room"
roomALicePOV.sendService().redactEvent(timelineEvent.root, redactionReason)
// get the event from bob
testHelper.waitWithLatch {
testHelper.retryPeriodicallyWithLatch(it) {
bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)?.root?.isRedacted() == true
}
}
val eventBobPov = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)!!
testHelper.runBlockingTest {
try {
val result = bobSession.cryptoService().decryptEvent(eventBobPov.root, "")
Assert.assertEquals(
"Unexpected redacted reason",
redactionReason,
result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.content?.get("reason")
)
Assert.assertEquals(
"Unexpected Redacted event id",
timelineEvent.eventId,
result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.redacts
)
} catch (failure: Throwable) {
Assert.fail("Should not throw when decrypting a redacted event")
}
}
}
}

View file

@ -23,6 +23,7 @@ import org.amshove.kluent.fail
import org.amshove.kluent.internal.assertEquals import org.amshove.kluent.internal.assertEquals
import org.junit.Assert import org.junit.Assert
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -57,7 +58,8 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
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.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.RetryTestRule
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
@ -68,6 +70,7 @@ import java.util.concurrent.CountDownLatch
@RunWith(JUnit4::class) @RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
@LargeTest @LargeTest
@Ignore("This test fails with an unhandled exception thrown from a coroutine which terminates the entire test run.")
class E2eeSanityTests : InstrumentedTest { class E2eeSanityTests : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3) @get:Rule val rule = RetryTestRule(3)
@ -82,9 +85,7 @@ class E2eeSanityTests : InstrumentedTest {
* Alice sends a new message, then check that the new one can be decrypted * Alice sends a new message, then check that the new one can be decrypted
*/ */
@Test @Test
fun testSendingE2EEMessages() { fun testSendingE2EEMessages() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -198,21 +199,12 @@ class E2eeSanityTests : InstrumentedTest {
} }
} }
} }
otherAccounts.forEach {
testHelper.signOutAndClose(it)
}
newAccount.forEach { testHelper.signOutAndClose(it) }
cryptoTestData.cleanUp(testHelper)
} }
@Test @Test
fun testKeyGossipingIsEnabledByDefault() { fun testKeyGossipingIsEnabledByDefault() = runSessionTest(context()) { testHelper ->
val testHelper = CommonTestHelper(context())
val session = testHelper.createAccount("alice", SessionTestParams(true)) val session = testHelper.createAccount("alice", SessionTestParams(true))
Assert.assertTrue("Key gossiping should be enabled by default", session.cryptoService().isKeyGossipingEnabled()) Assert.assertTrue("Key gossiping should be enabled by default", session.cryptoService().isKeyGossipingEnabled())
testHelper.signOutAndClose(session)
} }
/** /**
@ -230,9 +222,7 @@ class E2eeSanityTests : InstrumentedTest {
* 9. Check that new session can decrypt * 9. Check that new session can decrypt
*/ */
@Test @Test
fun testBasicBackupImport() { fun testBasicBackupImport() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -344,8 +334,6 @@ class E2eeSanityTests : InstrumentedTest {
// ensure bob can now decrypt // ensure bob can now decrypt
cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText) cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
testHelper.signOutAndClose(newBobSession)
} }
/** /**
@ -353,9 +341,7 @@ class E2eeSanityTests : InstrumentedTest {
* get them from an older one. * get them from an older one.
*/ */
@Test @Test
fun testSimpleGossip() { fun testSimpleGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -449,18 +435,13 @@ class E2eeSanityTests : InstrumentedTest {
} }
cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText) cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
cryptoTestData.cleanUp(testHelper)
testHelper.signOutAndClose(newBobSession)
} }
/** /**
* Test that if a better key is forwarded (lower index, it is then used) * Test that if a better key is forwarded (lower index, it is then used)
*/ */
@Test @Test
fun testForwardBetterKey() { fun testForwardBetterKey() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -576,10 +557,6 @@ class E2eeSanityTests : InstrumentedTest {
canDecryptFirst && canDecryptSecond canDecryptFirst && canDecryptSecond
} }
} }
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSessionWithBetterKey)
testHelper.signOutAndClose(newBobSession)
} }
private fun sendMessageInRoom(testHelper: CommonTestHelper, aliceRoomPOV: Room, text: String): String? { private fun sendMessageInRoom(testHelper: CommonTestHelper, aliceRoomPOV: Room, text: String): String? {
@ -610,9 +587,7 @@ class E2eeSanityTests : InstrumentedTest {
* Test that if a better key is forwared (lower index, it is then used) * Test that if a better key is forwared (lower index, it is then used)
*/ */
@Test @Test
fun testSelfInteractiveVerificationAndGossip() { fun testASelfInteractiveVerificationAndGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val aliceSession = testHelper.createAccount("alice", SessionTestParams(true)) val aliceSession = testHelper.createAccount("alice", SessionTestParams(true))
cryptoTestHelper.bootstrapSecurity(aliceSession) cryptoTestHelper.bootstrapSecurity(aliceSession)
@ -751,9 +726,6 @@ class E2eeSanityTests : InstrumentedTest {
aliceSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version, aliceSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version,
aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version
) )
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(aliceNewSession)
} }
private fun ensureMembersHaveJoined(testHelper: CommonTestHelper, aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String) { private fun ensureMembersHaveJoined(testHelper: CommonTestHelper, aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String) {

View file

@ -83,8 +83,8 @@ class ExportEncryptionTest {
@Test @Test
fun checkExportDecrypt1() { fun checkExportDecrypt1() {
val password = "password" val password = "password"
val input = val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
"-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----" "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"
val expectedString = "plain" val expectedString = "plain"
var decodedString: String? = null var decodedString: String? = null
@ -104,8 +104,8 @@ class ExportEncryptionTest {
@Test @Test
fun checkExportDecrypt2() { fun checkExportDecrypt2() {
val password = "betterpassword" val password = "betterpassword"
val input = val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" +
"-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----" "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"
val expectedString = "Hello, World" val expectedString = "Hello, World"
var decodedString: String? = null var decodedString: String? = null
@ -125,8 +125,8 @@ class ExportEncryptionTest {
@Test @Test
fun checkExportDecrypt3() { fun checkExportDecrypt3() {
val password = "SWORDFISH" val password = "SWORDFISH"
val input = val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" +
"-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----" "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically" val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null var decodedString: String? = null
@ -205,8 +205,8 @@ class ExportEncryptionTest {
@Test @Test
fun checkExportEncrypt4() { fun checkExportEncrypt4() {
val password = val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically" val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null var decodedString: String? = null

View file

@ -30,18 +30,14 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
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.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
class PreShareKeysTest : InstrumentedTest { class PreShareKeysTest : InstrumentedTest {
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Test @Test
fun ensure_outbound_session_happy_path() { fun ensure_outbound_session_happy_path() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val e2eRoomID = testData.roomId val e2eRoomID = testData.roomId
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -94,7 +90,5 @@ class PreShareKeysTest : InstrumentedTest {
bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE
} }
} }
testData.cleanUp(testHelper)
} }
} }

View file

@ -38,8 +38,7 @@ import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.timeline.Timeline 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.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
@ -63,8 +62,6 @@ import kotlin.coroutines.resume
class UnwedgingTest : InstrumentedTest { class UnwedgingTest : InstrumentedTest {
private lateinit var messagesReceivedByBob: List<TimelineEvent> private lateinit var messagesReceivedByBob: List<TimelineEvent>
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Before @Before
fun init() { fun init() {
@ -85,7 +82,7 @@ class UnwedgingTest : InstrumentedTest {
* -> This is automatically fixed after SDKs restarted the olm session * -> This is automatically fixed after SDKs restarted the olm session
*/ */
@Test @Test
fun testUnwedging() { fun testUnwedging() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -240,8 +237,6 @@ class UnwedgingTest : InstrumentedTest {
} }
bobTimeline.dispose() bobTimeline.dispose()
cryptoTestData.cleanUp(testHelper)
} }
private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener { private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener {

View file

@ -37,8 +37,8 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerif
import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
@ -49,11 +49,8 @@ import kotlin.coroutines.resume
@LargeTest @LargeTest
class XSigningTest : InstrumentedTest { class XSigningTest : InstrumentedTest {
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Test @Test
fun test_InitializeAndStoreKeys() { fun test_InitializeAndStoreKeys() = runSessionTest(context()) { testHelper ->
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
testHelper.doSync<Unit> { testHelper.doSync<Unit> {
@ -87,7 +84,7 @@ class XSigningTest : InstrumentedTest {
} }
@Test @Test
fun test_CrossSigningCheckBobSeesTheKeys() { fun test_CrossSigningCheckBobSeesTheKeys() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -137,12 +134,10 @@ class XSigningTest : InstrumentedTest {
) )
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted()) assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
cryptoTestData.cleanUp(testHelper)
} }
@Test @Test
fun test_CrossSigningTestAliceTrustBobNewDevice() { fun test_CrossSigningTestAliceTrustBobNewDevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -216,9 +211,5 @@ class XSigningTest : InstrumentedTest {
val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null) val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified()) assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSession)
testHelper.signOutAndClose(bobSession2)
} }
} }

View file

@ -35,6 +35,7 @@ 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.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CryptoTestHelper
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@ -42,12 +43,10 @@ import java.util.concurrent.CountDownLatch
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EncryptionTest : InstrumentedTest { class EncryptionTest : InstrumentedTest {
private val testHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(testHelper)
@Test @Test
fun test_EncryptionEvent() { fun test_EncryptionEvent() {
performTest(roomShouldBeEncrypted = false) { room -> runCryptoTest(context()) { cryptoTestHelper, testHelper ->
performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = false) { room ->
// Send an encryption Event as an Event (and not as a state event) // Send an encryption Event as an Event (and not as a state event)
room.sendService().sendEvent( room.sendService().sendEvent(
eventType = EventType.STATE_ROOM_ENCRYPTION, eventType = EventType.STATE_ROOM_ENCRYPTION,
@ -55,10 +54,12 @@ class EncryptionTest : InstrumentedTest {
) )
} }
} }
}
@Test @Test
fun test_EncryptionStateEvent() { fun test_EncryptionStateEvent() {
performTest(roomShouldBeEncrypted = true) { room -> runCryptoTest(context()) { cryptoTestHelper, testHelper ->
performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = true) { room ->
runBlocking { runBlocking {
// Send an encryption Event as a State Event // Send an encryption Event as a State Event
room.stateService().sendStateEvent( room.stateService().sendStateEvent(
@ -69,8 +70,9 @@ class EncryptionTest : InstrumentedTest {
} }
} }
} }
}
private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) { private fun performTest(cryptoTestHelper: CryptoTestHelper, testHelper: CommonTestHelper, roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) {
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false)
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
@ -109,6 +111,5 @@ class EncryptionTest : InstrumentedTest {
room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted
it.countDown() it.countDown()
} }
cryptoTestData.cleanUp(testHelper)
} }
} }

View file

@ -41,8 +41,7 @@ import org.matrix.android.sdk.api.session.room.getTimelineEvent
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.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.RetryTestRule
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
@ -56,9 +55,7 @@ class KeyShareTests : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3) @get:Rule val rule = RetryTestRule(3)
@Test @Test
fun test_DoNotSelfShareIfNotTrusted() { fun test_DoNotSelfShareIfNotTrusted() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val commonTestHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
Log.v("TEST", "=======> AliceSession 1 is ${aliceSession.sessionParams.deviceId}") Log.v("TEST", "=======> AliceSession 1 is ${aliceSession.sessionParams.deviceId}")
@ -194,9 +191,7 @@ class KeyShareTests : InstrumentedTest {
* if the key was originally shared with him * if the key was originally shared with him
*/ */
@Test @Test
fun test_reShareIfWasIntendedToBeShared() { fun test_reShareIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val commonTestHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -227,9 +222,7 @@ class KeyShareTests : InstrumentedTest {
* if the key was originally shared with him * if the key was originally shared with him
*/ */
@Test @Test
fun test_reShareToUnverifiedIfWasIntendedToBeShared() { fun test_reShareToUnverifiedIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val commonTestHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceInARoom(true) val testData = cryptoTestHelper.doE2ETestWithAliceInARoom(true)
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -266,9 +259,7 @@ class KeyShareTests : InstrumentedTest {
* Tests that keys reshared with own verified session are done from the earliest known index * Tests that keys reshared with own verified session are done from the earliest known index
*/ */
@Test @Test
fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() { fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val commonTestHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -388,10 +379,7 @@ class KeyShareTests : InstrumentedTest {
* Tests that we don't cancel a request to early on first forward if the index is not good enough * Tests that we don't cancel a request to early on first forward if the index is not good enough
*/ */
@Test @Test
fun test_dontCancelToEarly() { fun test_dontCancelToEarly() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
val commonTestHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
val bobSession = testData.secondSession!! val bobSession = testData.secondSession!!

View file

@ -36,8 +36,7 @@ import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
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.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.MockOkHttpInterceptor import org.matrix.android.sdk.common.MockOkHttpInterceptor
import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.RetryTestRule
import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.SessionTestParams
@ -52,9 +51,7 @@ class WithHeldTests : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3) @get:Rule val rule = RetryTestRule(3)
@Test @Test
fun test_WithHeldUnverifiedReason() { fun test_WithHeldUnverifiedReason() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
// ============================= // =============================
// ARRANGE // ARRANGE
@ -153,16 +150,10 @@ class WithHeldTests : InstrumentedTest {
bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "") bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "")
} }
} }
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSession)
testHelper.signOutAndClose(bobUnverifiedSession)
} }
@Test @Test
fun test_WithHeldNoOlm() { fun test_WithHeldNoOlm() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -239,14 +230,10 @@ class WithHeldTests : InstrumentedTest {
Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2) Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2)
aliceInterceptor.clearRules() aliceInterceptor.clearRules()
testData.cleanUp(testHelper)
testHelper.signOutAndClose(bobSecondSession)
} }
@Test @Test
fun test_WithHeldKeyRequest() { fun test_WithHeldKeyRequest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = testData.firstSession val aliceSession = testData.firstSession
@ -293,8 +280,5 @@ class WithHeldTests : InstrumentedTest {
wc?.code == WithHeldCode.UNAUTHORISED wc?.code == WithHeldCode.UNAUTHORISED
} }
} }
testHelper.signOutAndClose(aliceSession)
testHelper.signOutAndClose(bobSecondSession)
} }
} }

View file

@ -24,6 +24,7 @@ import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
@ -43,8 +44,9 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreation
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
import org.matrix.android.sdk.common.RetryTestRule
import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestConstants
import org.matrix.android.sdk.common.TestMatrixCallback import org.matrix.android.sdk.common.TestMatrixCallback
import java.util.Collections import java.util.Collections
@ -55,15 +57,15 @@ import java.util.concurrent.CountDownLatch
@LargeTest @LargeTest
class KeysBackupTest : InstrumentedTest { class KeysBackupTest : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3)
/** /**
* - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys * - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
* - Check backup keys after having marked one as backed up * - Check backup keys after having marked one as backed up
* - Reset keys backup markers * - Reset keys backup markers
*/ */
@Test @Test
fun roomKeysTest_testBackupStore_ok() { fun roomKeysTest_testBackupStore_ok() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@ -102,8 +104,7 @@ class KeysBackupTest : InstrumentedTest {
* Check that prepareKeysBackupVersionWithPassword returns valid data * Check that prepareKeysBackupVersionWithPassword returns valid data
*/ */
@Test @Test
fun prepareKeysBackupVersionTest() { fun prepareKeysBackupVersionTest() = runSessionTest(context()) { testHelper ->
val testHelper = CommonTestHelper(context())
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams) val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
@ -113,7 +114,7 @@ class KeysBackupTest : InstrumentedTest {
val stateObserver = StateObserver(keysBackup) val stateObserver = StateObserver(keysBackup)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> { val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(null, null, it) keysBackup.prepareKeysBackupVersion(null, null, it)
@ -125,16 +126,13 @@ class KeysBackupTest : InstrumentedTest {
assertNotNull(megolmBackupCreationInfo.recoveryKey) assertNotNull(megolmBackupCreationInfo.recoveryKey)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testHelper.signOutAndClose(bobSession)
} }
/** /**
* Test creating a keys backup version and check that createKeysBackupVersion() returns valid data * Test creating a keys backup version and check that createKeysBackupVersion() returns valid data
*/ */
@Test @Test
fun createKeysBackupVersionTest() { fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams) val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
cryptoTestHelper.initializeCrossSigning(bobSession) cryptoTestHelper.initializeCrossSigning(bobSession)
@ -143,13 +141,13 @@ class KeysBackupTest : InstrumentedTest {
val stateObserver = StateObserver(keysBackup) val stateObserver = StateObserver(keysBackup)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> { val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(null, null, it) keysBackup.prepareKeysBackupVersion(null, null, it)
} }
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
// Create the version // Create the version
val version = testHelper.doSync<KeysVersion> { val version = testHelper.doSync<KeysVersion> {
@ -157,7 +155,7 @@ class KeysBackupTest : InstrumentedTest {
} }
// Backup must be enable now // Backup must be enable now
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled())
// Check that it's signed with MSK // Check that it's signed with MSK
val versionResult = testHelper.doSync<KeysVersionResult?> { val versionResult = testHelper.doSync<KeysVersionResult?> {
@ -193,7 +191,6 @@ class KeysBackupTest : InstrumentedTest {
} }
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testHelper.signOutAndClose(bobSession)
} }
/** /**
@ -201,9 +198,7 @@ class KeysBackupTest : InstrumentedTest {
* - Check the backup completes * - Check the backup completes
*/ */
@Test @Test
fun backupAfterCreateKeysBackupVersionTest() { fun backupAfterCreateKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@ -238,16 +233,13 @@ class KeysBackupTest : InstrumentedTest {
KeysBackupState.ReadyToBackUp KeysBackupState.ReadyToBackUp
) )
) )
cryptoTestData.cleanUp(testHelper)
} }
/** /**
* Check that backupAllGroupSessions() returns valid data * Check that backupAllGroupSessions() returns valid data
*/ */
@Test @Test
fun backupAllGroupSessionsTest() { fun backupAllGroupSessionsTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@ -281,7 +273,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys) assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
cryptoTestData.cleanUp(testHelper)
} }
/** /**
@ -293,9 +284,7 @@ class KeysBackupTest : InstrumentedTest {
* - Compare the decrypted megolm key with the original one * - Compare the decrypted megolm key with the original one
*/ */
@Test @Test
fun testEncryptAndDecryptKeysBackupData() { fun testEncryptAndDecryptKeysBackupData() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@ -330,7 +319,6 @@ class KeysBackupTest : InstrumentedTest {
keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData) keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
cryptoTestData.cleanUp(testHelper)
} }
/** /**
@ -340,9 +328,7 @@ class KeysBackupTest : InstrumentedTest {
* - Restore must be successful * - Restore must be successful
*/ */
@Test @Test
fun restoreKeysBackupTest() { fun restoreKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@ -428,9 +414,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must be trusted and must have with 2 signatures now * - It must be trusted and must have with 2 signatures now
*/ */
@Test @Test
fun trustKeyBackupVersionTest() { fun trustKeyBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Do an e2e backup to the homeserver with a recovery key // - Do an e2e backup to the homeserver with a recovery key
@ -441,8 +425,8 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must see the previous backup as not trusted // - The new device must see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
// - Trust the backup from the new device // - Trust the backup from the new device
testHelper.doSync<Unit> { testHelper.doSync<Unit> {
@ -458,7 +442,7 @@ class KeysBackupTest : InstrumentedTest {
// - Backup must be enabled on the new device, on the same version // - Backup must be enabled on the new device, on the same version
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@ -477,7 +461,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(2, keysBackupVersionTrust.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cleanUp(testHelper)
} }
/** /**
@ -491,9 +474,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must be trusted and must have with 2 signatures now * - It must be trusted and must have with 2 signatures now
*/ */
@Test @Test
fun trustKeyBackupVersionWithRecoveryKeyTest() { fun trustKeyBackupVersionWithRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Do an e2e backup to the homeserver with a recovery key // - Do an e2e backup to the homeserver with a recovery key
@ -504,8 +485,8 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must see the previous backup as not trusted // - The new device must see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
// - Trust the backup from the new device with the recovery key // - Trust the backup from the new device with the recovery key
testHelper.doSync<Unit> { testHelper.doSync<Unit> {
@ -521,7 +502,7 @@ class KeysBackupTest : InstrumentedTest {
// - Backup must be enabled on the new device, on the same version // - Backup must be enabled on the new device, on the same version
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@ -540,7 +521,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(2, keysBackupVersionTrust.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cleanUp(testHelper)
} }
/** /**
@ -552,9 +532,7 @@ class KeysBackupTest : InstrumentedTest {
* - The backup must still be untrusted and disabled * - The backup must still be untrusted and disabled
*/ */
@Test @Test
fun trustKeyBackupVersionWithWrongRecoveryKeyTest() { fun trustKeyBackupVersionWithWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Do an e2e backup to the homeserver with a recovery key // - Do an e2e backup to the homeserver with a recovery key
@ -565,8 +543,8 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must see the previous backup as not trusted // - The new device must see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
// - Try to trust the backup from the new device with a wrong recovery key // - Try to trust the backup from the new device with a wrong recovery key
val latch = CountDownLatch(1) val latch = CountDownLatch(1)
@ -579,11 +557,10 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must still see the previous backup as not trusted // - The new device must still see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cleanUp(testHelper)
} }
/** /**
@ -597,9 +574,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must be trusted and must have with 2 signatures now * - It must be trusted and must have with 2 signatures now
*/ */
@Test @Test
fun trustKeyBackupVersionWithPasswordTest() { fun trustKeyBackupVersionWithPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "Password" val password = "Password"
@ -612,8 +587,8 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must see the previous backup as not trusted // - The new device must see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
// - Trust the backup from the new device with the password // - Trust the backup from the new device with the password
testHelper.doSync<Unit> { testHelper.doSync<Unit> {
@ -629,7 +604,7 @@ class KeysBackupTest : InstrumentedTest {
// - Backup must be enabled on the new device, on the same version // - Backup must be enabled on the new device, on the same version
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@ -648,7 +623,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(2, keysBackupVersionTrust.signatures.size) assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cleanUp(testHelper)
} }
/** /**
@ -660,9 +634,7 @@ class KeysBackupTest : InstrumentedTest {
* - The backup must still be untrusted and disabled * - The backup must still be untrusted and disabled
*/ */
@Test @Test
fun trustKeyBackupVersionWithWrongPasswordTest() { fun trustKeyBackupVersionWithWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "Password" val password = "Password"
@ -676,8 +648,8 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must see the previous backup as not trusted // - The new device must see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
// - Try to trust the backup from the new device with a wrong password // - Try to trust the backup from the new device with a wrong password
val latch = CountDownLatch(1) val latch = CountDownLatch(1)
@ -690,11 +662,10 @@ class KeysBackupTest : InstrumentedTest {
// - The new device must still see the previous backup as not trusted // - The new device must still see the previous backup as not trusted
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
testData.cleanUp(testHelper)
} }
/** /**
@ -704,9 +675,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must fail * - It must fail
*/ */
@Test @Test
fun restoreKeysBackupWithAWrongRecoveryKeyTest() { fun restoreKeysBackupWithAWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@ -730,8 +699,6 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called // onSuccess may not have been called
assertNull(importRoomKeysResult) assertNull(importRoomKeysResult)
testData.cleanUp(testHelper)
} }
/** /**
@ -741,9 +708,7 @@ class KeysBackupTest : InstrumentedTest {
* - Restore must be successful * - Restore must be successful
*/ */
@Test @Test
fun testBackupWithPassword() { fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "password" val password = "password"
@ -790,8 +755,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress) assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress)
keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys) keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cleanUp(testHelper)
} }
/** /**
@ -801,9 +764,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must fail * - It must fail
*/ */
@Test @Test
fun restoreKeysBackupWithAWrongPasswordTest() { fun restoreKeysBackupWithAWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "password" val password = "password"
@ -830,8 +791,6 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called // onSuccess may not have been called
assertNull(importRoomKeysResult) assertNull(importRoomKeysResult)
testData.cleanUp(testHelper)
} }
/** /**
@ -841,9 +800,7 @@ class KeysBackupTest : InstrumentedTest {
* - Restore must be successful * - Restore must be successful
*/ */
@Test @Test
fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() { fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "password" val password = "password"
@ -863,8 +820,6 @@ class KeysBackupTest : InstrumentedTest {
} }
keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys) keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cleanUp(testHelper)
} }
/** /**
@ -874,9 +829,7 @@ class KeysBackupTest : InstrumentedTest {
* - It must fail * - It must fail
*/ */
@Test @Test
fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() { fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@ -900,8 +853,6 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called // onSuccess may not have been called
assertNull(importRoomKeysResult) assertNull(importRoomKeysResult)
testData.cleanUp(testHelper)
} }
/** /**
@ -909,9 +860,7 @@ class KeysBackupTest : InstrumentedTest {
* - Check the returned KeysVersionResult is trusted * - Check the returned KeysVersionResult is trusted
*/ */
@Test @Test
fun testIsKeysBackupTrusted() { fun testIsKeysBackupTrusted() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Create a backup version // - Create a backup version
@ -945,7 +894,6 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.deviceId) assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.deviceId)
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
cryptoTestData.cleanUp(testHelper)
} }
/** /**
@ -957,9 +905,7 @@ class KeysBackupTest : InstrumentedTest {
* -> That must fail and her backup state must be WrongBackUpVersion * -> That must fail and her backup state must be WrongBackUpVersion
*/ */
@Test @Test
fun testBackupWhenAnotherBackupWasCreated() { fun testBackupWhenAnotherBackupWasCreated() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Create a backup version // - Create a backup version
@ -969,7 +915,7 @@ class KeysBackupTest : InstrumentedTest {
val stateObserver = StateObserver(keysBackup) val stateObserver = StateObserver(keysBackup)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
// Wait for keys backup to be finished // Wait for keys backup to be finished
val latch0 = CountDownLatch(1) val latch0 = CountDownLatch(1)
@ -993,7 +939,7 @@ class KeysBackupTest : InstrumentedTest {
// - Make alice back up her keys to her homeserver // - Make alice back up her keys to her homeserver
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled())
testHelper.await(latch0) testHelper.await(latch0)
@ -1012,11 +958,10 @@ class KeysBackupTest : InstrumentedTest {
testHelper.await(latch2) testHelper.await(latch2)
// -> That must fail and her backup state must be WrongBackUpVersion // -> That must fail and her backup state must be WrongBackUpVersion
assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.state) assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.getState())
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
cryptoTestData.cleanUp(testHelper)
} }
/** /**
@ -1032,9 +977,7 @@ class KeysBackupTest : InstrumentedTest {
* -> It must success * -> It must success
*/ */
@Test @Test
fun testBackupAfterVerifyingADevice() { fun testBackupAfterVerifyingADevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Create a backup version // - Create a backup version
@ -1069,7 +1012,7 @@ class KeysBackupTest : InstrumentedTest {
// - Try to backup all in aliceSession2, it must fail // - Try to backup all in aliceSession2, it must fail
val keysBackup2 = aliceSession2.cryptoService().keysBackupService() val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
assertFalse("Backup should not be enabled", keysBackup2.isEnabled) assertFalse("Backup should not be enabled", keysBackup2.isEnabled())
val stateObserver2 = StateObserver(keysBackup2) val stateObserver2 = StateObserver(keysBackup2)
@ -1088,8 +1031,8 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(isSuccessful) assertFalse(isSuccessful)
// Backup state must be NotTrusted // Backup state must be NotTrusted
assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.state) assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.getState())
assertFalse("Backup should not be enabled", keysBackup2.isEnabled) assertFalse("Backup should not be enabled", keysBackup2.isEnabled())
// - Validate the old device from the new one // - Validate the old device from the new one
aliceSession2.cryptoService().setDeviceVerification( aliceSession2.cryptoService().setDeviceVerification(
@ -1103,7 +1046,7 @@ class KeysBackupTest : InstrumentedTest {
keysBackup2.addListener(object : KeysBackupStateListener { keysBackup2.addListener(object : KeysBackupStateListener {
override fun onStateChange(newState: KeysBackupState) { override fun onStateChange(newState: KeysBackupState) {
// Check the backup completes // Check the backup completes
if (keysBackup2.state == KeysBackupState.ReadyToBackUp) { if (keysBackup2.getState() == KeysBackupState.ReadyToBackUp) {
// Remove itself from the list of listeners // Remove itself from the list of listeners
keysBackup2.removeListener(this) keysBackup2.removeListener(this)
@ -1121,12 +1064,10 @@ class KeysBackupTest : InstrumentedTest {
} }
// -> It must success // -> It must success
assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
stateObserver2.stopAndCheckStates(null) stateObserver2.stopAndCheckStates(null)
testHelper.signOutAndClose(aliceSession2)
cryptoTestData.cleanUp(testHelper)
} }
/** /**
@ -1134,9 +1075,7 @@ class KeysBackupTest : InstrumentedTest {
* - Delete the backup * - Delete the backup
*/ */
@Test @Test
fun deleteKeysBackupTest() { fun deleteKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val testHelper = CommonTestHelper(context())
val cryptoTestHelper = CryptoTestHelper(testHelper)
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
// - Create a backup version // - Create a backup version
@ -1146,19 +1085,18 @@ class KeysBackupTest : InstrumentedTest {
val stateObserver = StateObserver(keysBackup) val stateObserver = StateObserver(keysBackup)
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
assertTrue(keysBackup.isEnabled) assertTrue(keysBackup.isEnabled())
// Delete the backup // Delete the backup
testHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) } testHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
// Backup is now disabled // Backup is now disabled
assertFalse(keysBackup.isEnabled) assertFalse(keysBackup.isEnabled())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
cryptoTestData.cleanUp(testHelper)
} }
} }

View file

@ -109,7 +109,7 @@ internal class KeysBackupTestHelper(
Assert.assertNotNull(megolmBackupCreationInfo) Assert.assertNotNull(megolmBackupCreationInfo)
Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled) Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled())
// Create the version // Create the version
val keysVersion = testHelper.doSync<KeysVersion> { val keysVersion = testHelper.doSync<KeysVersion> {
@ -119,7 +119,7 @@ internal class KeysBackupTestHelper(
Assert.assertNotNull("Key backup version should not be null", keysVersion.version) Assert.assertNotNull("Key backup version should not be null", keysVersion.version)
// Backup must be enable now // Backup must be enable now
Assert.assertTrue(keysBackup.isEnabled) Assert.assertTrue(keysBackup.isEnabled())
stateObserver.stopAndCheckStates(null) stateObserver.stopAndCheckStates(null)
return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version) return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version)
@ -131,7 +131,7 @@ internal class KeysBackupTestHelper(
*/ */
fun waitForKeysBackupToBeInState(session: Session, state: KeysBackupState) { fun waitForKeysBackupToBeInState(session: Session, state: KeysBackupState) {
// If already in the wanted state, return // If already in the wanted state, return
if (session.cryptoService().keysBackupService().state == state) { if (session.cryptoService().keysBackupService().getState() == state) {
return return
} }

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