Merge branch 'develop' into feature/fga/new_voip_design
This commit is contained in:
commit
4788630949
|
@ -0,0 +1,84 @@
|
||||||
|
---
|
||||||
|
name: Release
|
||||||
|
about: Checklist for each release. To be used by the core team only.
|
||||||
|
title: "[Release] Element Android v"
|
||||||
|
labels: "\U0001F680 Release"
|
||||||
|
assignees: bmarty
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For the example, we are releasing the version 1.1.10. Delete this line and replace 1.1.10 with the version in the issue content.
|
||||||
|
|
||||||
|
### Before the release
|
||||||
|
|
||||||
|
- [ ] Weblate sync, fix lint issue if any (in a dedicated PR)
|
||||||
|
- [ ] Check the update of the store descriptions (using Google Translate if necessary) to ensure that the changes are acceptable to be published to the stores.
|
||||||
|
- [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect.
|
||||||
|
|
||||||
|
### Do the release
|
||||||
|
|
||||||
|
- [ ] Create release with gitflow, branch name `release/1.1.10`
|
||||||
|
- [ ] Run `./tools/import_emojis.py` and commit the change if any.
|
||||||
|
- [ ] Run `./tools/import_sas_strings.py` and commit the change if any. If there is no change since a while, ping Travis
|
||||||
|
- [ ] Check the crashes from the PlayStore
|
||||||
|
- [ ] Check the rageshake with the current dev version: https://github.com/matrix-org/element-android-rageshakes/labels/1.1.10-dev
|
||||||
|
- [ ] Run the integration test, and especially `UiAllScreensSanityTest.allScreensTest()`
|
||||||
|
- [ ] Create an account on matrix.org
|
||||||
|
- [ ] Run towncrier: `towncrier --version v1.1.10 --draft` (remove `--draft` do write the file CHANGES.md)
|
||||||
|
- [ ] Add file for fastlane under ./fastlane/metadata/android/en-US/changelogs
|
||||||
|
- [ ] Push the branch and start a draft PR (will not be merged), to check that the CI is happy with all the changes.
|
||||||
|
- [ ] Finish release with gitflow, delete the draft PR
|
||||||
|
- [ ] Push `main` and the new tag `v1.1.10` to origin
|
||||||
|
- [ ] Checkout `develop`
|
||||||
|
- [ ] Increase version in `./vector/build.gradle`
|
||||||
|
- [ ] Commit and push `develop`
|
||||||
|
- [ ] Wait for [Buildkite](https://buildkite.com/matrix-dot-org/element-android/builds?branch=main) to build the `main` branch.
|
||||||
|
- [ ] Run the script `~/scripts/releaseElement.sh`. It will download the APKs from Buildkite check them and sign them.
|
||||||
|
- [ ] Install the APK on your phone to check that the upgrade went well (no init sync, etc.)
|
||||||
|
- [ ] Create a new beta release on the GooglePlay console and upload the 4 signed Apks.
|
||||||
|
- [ ] Check that the version codes are correct
|
||||||
|
- [ ] Copy the fastlane change to the GooglePlay console in the section en-GB.
|
||||||
|
- [ ] Push to beta release to 100% of the users
|
||||||
|
- [ ] Create the release on gitHub [from the tag](https://github.com/vector-im/element-android/tags), copy paste the block from the file CHANGES.md
|
||||||
|
- [ ] Add the 4 signed APKs to the GitHub release
|
||||||
|
- [ ] Ping the Android Internal room
|
||||||
|
- [ ] Add an entry in the internal diary
|
||||||
|
|
||||||
|
### Once Live on PlayStore
|
||||||
|
|
||||||
|
- [ ] Ping the Android public room and update its topic
|
||||||
|
|
||||||
|
### After at least 2 days
|
||||||
|
|
||||||
|
- [ ] Check the [rageshakes](https://github.com/matrix-org/element-android-rageshakes/issues)
|
||||||
|
- [ ] Check the crash reports on the GooglePlay console
|
||||||
|
- [ ] Check the Android Element room for any reported issues on the new version
|
||||||
|
- [ ] If all is OK, push to production and notify Markus (Bubu) to release the F-Droid version
|
||||||
|
- [ ] Ping the Android public room and update its topic with the new available version
|
||||||
|
|
||||||
|
### Android SDK2
|
||||||
|
|
||||||
|
- [ ] Checkout the `main` branch on Element Android project
|
||||||
|
|
||||||
|
#### On the SDK2 project
|
||||||
|
|
||||||
|
https://github.com/matrix-org/matrix-android-sdk2
|
||||||
|
|
||||||
|
- [ ] Create a release with GitFlow
|
||||||
|
- [ ] Update the files `./build.gradle` and `./gradle/gradle-wrapper.properties` manually, to use the latest version for the dependency. You can get inspired by the same files on Element Android project.
|
||||||
|
- [ ] Run the script `./tools/import_from_element.sh`
|
||||||
|
- [ ] Update the version in `./matrix-sdk-android/build.gradle` and let the script finish to build the library
|
||||||
|
- [ ] Update the file `CHANGES.md`
|
||||||
|
- [ ] Finish the release using GitFlow
|
||||||
|
- [ ] Create the release on GitHub from [the tag](https://github.com/matrix-org/matrix-android-sdk2/tags)
|
||||||
|
- [ ] Upload the AAR on the GitHub release
|
||||||
|
|
||||||
|
### Android SDK2 sample
|
||||||
|
|
||||||
|
https://github.com/matrix-org/matrix-android-sdk2-sample
|
||||||
|
|
||||||
|
- [ ] Update the dependency to the new version of the SDK2. Jitpack will have to build the AAR, it can take a few minutes. You can check status on https://jitpack.io/#matrix-org/matrix-android-sdk2
|
||||||
|
- [ ] Build and run the sample, you may have to fix some API break
|
||||||
|
- [ ] Commit and push directly on `main`
|
||||||
|
|
||||||
|
<!-- Note: some scripts are not public because they contain some private keys -->
|
|
@ -38,6 +38,7 @@
|
||||||
<w>unpublish</w>
|
<w>unpublish</w>
|
||||||
<w>unwedging</w>
|
<w>unwedging</w>
|
||||||
<w>vctr</w>
|
<w>vctr</w>
|
||||||
|
<w>wellknown</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
49
CHANGES.md
49
CHANGES.md
|
@ -1,3 +1,52 @@
|
||||||
|
Changes in Element 1.1.14 (2021-07-23)
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Features ✨
|
||||||
|
----------
|
||||||
|
- Add low priority section in DM tab ([#3463](https://github.com/vector-im/element-android/issues/3463))
|
||||||
|
- Show missed call notification. ([#3710](https://github.com/vector-im/element-android/issues/3710))
|
||||||
|
|
||||||
|
Bugfixes 🐛
|
||||||
|
----------
|
||||||
|
- Don't use the transaction ID of the verification for the request ([#3589](https://github.com/vector-im/element-android/issues/3589))
|
||||||
|
- Avoid incomplete downloads in cache ([#3656](https://github.com/vector-im/element-android/issues/3656))
|
||||||
|
- Fix a crash which can happen when user signs out ([#3720](https://github.com/vector-im/element-android/issues/3720))
|
||||||
|
- Ensure OTKs are uploaded when the session is created ([#3724](https://github.com/vector-im/element-android/issues/3724))
|
||||||
|
|
||||||
|
SDK API changes ⚠️
|
||||||
|
------------------
|
||||||
|
- Add initialState support to CreateRoomParams (#3713) ([#3713](https://github.com/vector-im/element-android/issues/3713))
|
||||||
|
|
||||||
|
Other changes
|
||||||
|
-------------
|
||||||
|
- Apply grammatical fixes to the Server ACL timeline messages. ([#3721](https://github.com/vector-im/element-android/issues/3721))
|
||||||
|
- Add tags in the log, especially for VoIP, but can be used for other features in the future ([#3723](https://github.com/vector-im/element-android/issues/3723))
|
||||||
|
|
||||||
|
|
||||||
|
Changes in Element v1.1.13 (2021-07-19)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Features ✨
|
||||||
|
----------
|
||||||
|
- Remove redundant mimetype (vector-im/element-web#2547) ([#3273](https://github.com/vector-im/element-android/issues/3273))
|
||||||
|
- Room version capabilities and room upgrade support, better error feedback ([#3551](https://github.com/vector-im/element-android/issues/3551))
|
||||||
|
- Add retry support in room addresses screen ([#3635](https://github.com/vector-im/element-android/issues/3635))
|
||||||
|
- Better management of permission requests ([#3667](https://github.com/vector-im/element-android/issues/3667))
|
||||||
|
|
||||||
|
Bugfixes 🐛
|
||||||
|
----------
|
||||||
|
- Standardise spelling and casing of homeserver, identity server, and integration manager. ([#491](https://github.com/vector-im/element-android/issues/491))
|
||||||
|
- Perform .well-known request first, even if the entered URL is a valid homeserver base url ([#2843](https://github.com/vector-im/element-android/issues/2843))
|
||||||
|
- Use different copy for self verification. ([#3624](https://github.com/vector-im/element-android/issues/3624))
|
||||||
|
- Crash when opening room addresses screen with no internet connection ([#3634](https://github.com/vector-im/element-android/issues/3634))
|
||||||
|
- Fix unread messages marker being hidden in collapsed membership item ([#3655](https://github.com/vector-im/element-android/issues/3655))
|
||||||
|
- Ensure reaction emoji picker tabs look fine on small displays ([#3661](https://github.com/vector-im/element-android/issues/3661))
|
||||||
|
|
||||||
|
SDK API changes ⚠️
|
||||||
|
------------------
|
||||||
|
- RawService.getWellknown() now takes a domain instead of a matrixId as parameter ([#3572](https://github.com/vector-im/element-android/issues/3572))
|
||||||
|
|
||||||
|
|
||||||
Changes in Element 1.1.12 (2021-07-05)
|
Changes in Element 1.1.12 (2021-07-05)
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
|
|
68
Gemfile.lock
68
Gemfile.lock
|
@ -2,25 +2,25 @@ GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
CFPropertyList (3.0.3)
|
CFPropertyList (3.0.3)
|
||||||
addressable (2.7.0)
|
addressable (2.8.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
artifactory (3.0.15)
|
artifactory (3.0.15)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.1.1)
|
aws-eventstream (1.1.1)
|
||||||
aws-partitions (1.462.0)
|
aws-partitions (1.479.0)
|
||||||
aws-sdk-core (3.114.0)
|
aws-sdk-core (3.117.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.239.0)
|
aws-partitions (~> 1, >= 1.239.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-kms (1.43.0)
|
aws-sdk-kms (1.44.0)
|
||||||
aws-sdk-core (~> 3, >= 3.112.0)
|
aws-sdk-core (~> 3, >= 3.112.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.95.1)
|
aws-sdk-s3 (1.96.1)
|
||||||
aws-sdk-core (~> 3, >= 3.112.0)
|
aws-sdk-core (~> 3, >= 3.112.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sigv4 (1.2.3)
|
aws-sigv4 (1.2.4)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
claide (1.0.3)
|
claide (1.0.3)
|
||||||
|
@ -35,13 +35,15 @@ GEM
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.7.6)
|
dotenv (2.7.6)
|
||||||
emoji_regex (3.2.2)
|
emoji_regex (3.2.2)
|
||||||
excon (0.81.0)
|
excon (0.85.0)
|
||||||
faraday (1.4.2)
|
faraday (1.5.1)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
faraday-excon (~> 1.1)
|
faraday-excon (~> 1.1)
|
||||||
|
faraday-httpclient (~> 1.0.1)
|
||||||
faraday-net_http (~> 1.0)
|
faraday-net_http (~> 1.0)
|
||||||
faraday-net_http_persistent (~> 1.1)
|
faraday-net_http_persistent (~> 1.1)
|
||||||
|
faraday-patron (~> 1.0)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
ruby2_keywords (>= 0.0.4)
|
ruby2_keywords (>= 0.0.4)
|
||||||
faraday-cookie_jar (0.0.7)
|
faraday-cookie_jar (0.0.7)
|
||||||
|
@ -50,12 +52,14 @@ GEM
|
||||||
faraday-em_http (1.0.0)
|
faraday-em_http (1.0.0)
|
||||||
faraday-em_synchrony (1.0.0)
|
faraday-em_synchrony (1.0.0)
|
||||||
faraday-excon (1.1.0)
|
faraday-excon (1.1.0)
|
||||||
|
faraday-httpclient (1.0.1)
|
||||||
faraday-net_http (1.0.1)
|
faraday-net_http (1.0.1)
|
||||||
faraday-net_http_persistent (1.1.0)
|
faraday-net_http_persistent (1.2.0)
|
||||||
|
faraday-patron (1.0.0)
|
||||||
faraday_middleware (1.0.0)
|
faraday_middleware (1.0.0)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.2.3)
|
fastimage (2.2.4)
|
||||||
fastlane (2.184.0)
|
fastlane (2.187.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.3, < 3.0.0)
|
addressable (>= 2.3, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
|
@ -94,37 +98,36 @@ GEM
|
||||||
xcpretty (~> 0.3.0)
|
xcpretty (~> 0.3.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3)
|
xcpretty-travis-formatter (>= 0.0.3)
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
google-apis-androidpublisher_v3 (0.4.0)
|
google-apis-androidpublisher_v3 (0.8.0)
|
||||||
google-apis-core (~> 0.1)
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
google-apis-core (0.3.0)
|
google-apis-core (0.4.0)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
googleauth (~> 0.14)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
httpclient (>= 2.8.1, < 3.0)
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
representable (~> 3.0)
|
representable (~> 3.0)
|
||||||
retriable (>= 2.0, < 4.0)
|
retriable (>= 2.0, < 4.a)
|
||||||
rexml
|
rexml
|
||||||
signet (~> 0.14)
|
|
||||||
webrick
|
webrick
|
||||||
google-apis-iamcredentials_v1 (0.4.0)
|
google-apis-iamcredentials_v1 (0.6.0)
|
||||||
google-apis-core (~> 0.1)
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
google-apis-playcustomapp_v1 (0.3.0)
|
google-apis-playcustomapp_v1 (0.5.0)
|
||||||
google-apis-core (~> 0.1)
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
google-apis-storage_v1 (0.4.0)
|
google-apis-storage_v1 (0.6.0)
|
||||||
google-apis-core (~> 0.1)
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
google-cloud-core (1.6.0)
|
google-cloud-core (1.6.0)
|
||||||
google-cloud-env (~> 1.0)
|
google-cloud-env (~> 1.0)
|
||||||
google-cloud-errors (~> 1.0)
|
google-cloud-errors (~> 1.0)
|
||||||
google-cloud-env (1.5.0)
|
google-cloud-env (1.5.0)
|
||||||
faraday (>= 0.17.3, < 2.0)
|
faraday (>= 0.17.3, < 2.0)
|
||||||
google-cloud-errors (1.1.0)
|
google-cloud-errors (1.1.0)
|
||||||
google-cloud-storage (1.31.1)
|
google-cloud-storage (1.34.1)
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.5)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-apis-iamcredentials_v1 (~> 0.1)
|
google-apis-iamcredentials_v1 (~> 0.1)
|
||||||
google-apis-storage_v1 (~> 0.1)
|
google-apis-storage_v1 (~> 0.1)
|
||||||
google-cloud-core (~> 1.2)
|
google-cloud-core (~> 1.6)
|
||||||
googleauth (~> 0.9)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
googleauth (0.16.2)
|
googleauth (0.16.2)
|
||||||
faraday (>= 0.17.3, < 2.0)
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
@ -134,7 +137,7 @@ GEM
|
||||||
os (>= 0.9, < 2.0)
|
os (>= 0.9, < 2.0)
|
||||||
signet (~> 0.14)
|
signet (~> 0.14)
|
||||||
highline (2.0.3)
|
highline (2.0.3)
|
||||||
http-cookie (1.0.3)
|
http-cookie (1.0.4)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
jmespath (1.4.0)
|
jmespath (1.4.0)
|
||||||
|
@ -150,7 +153,7 @@ GEM
|
||||||
os (1.1.1)
|
os (1.1.1)
|
||||||
plist (3.6.0)
|
plist (3.6.0)
|
||||||
public_suffix (4.0.6)
|
public_suffix (4.0.6)
|
||||||
rake (13.0.3)
|
rake (13.0.6)
|
||||||
representable (3.1.1)
|
representable (3.1.1)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
|
@ -158,8 +161,8 @@ GEM
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rouge (2.0.7)
|
rouge (2.0.7)
|
||||||
ruby2_keywords (0.0.4)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.0)
|
rubyzip (2.3.2)
|
||||||
security (0.1.3)
|
security (0.1.3)
|
||||||
signet (0.15.0)
|
signet (0.15.0)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
|
@ -184,12 +187,13 @@ GEM
|
||||||
unicode-display_width (1.7.0)
|
unicode-display_width (1.7.0)
|
||||||
webrick (1.7.0)
|
webrick (1.7.0)
|
||||||
word_wrap (1.0.0)
|
word_wrap (1.0.0)
|
||||||
xcodeproj (1.19.0)
|
xcodeproj (1.20.0)
|
||||||
CFPropertyList (>= 2.3.3, < 4.0)
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
atomos (~> 0.1.3)
|
atomos (~> 0.1.3)
|
||||||
claide (>= 1.0.2, < 2.0)
|
claide (>= 1.0.2, < 2.0)
|
||||||
colored2 (~> 3.1)
|
colored2 (~> 3.1)
|
||||||
nanaimo (~> 0.3.0)
|
nanaimo (~> 0.3.0)
|
||||||
|
rexml (~> 3.2.4)
|
||||||
xcpretty (0.3.0)
|
xcpretty (0.3.0)
|
||||||
rouge (~> 2.0.7)
|
rouge (~> 2.0.7)
|
||||||
xcpretty-travis-formatter (1.0.1)
|
xcpretty-travis-formatter (1.0.1)
|
||||||
|
|
|
@ -56,8 +56,8 @@ dependencies {
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation 'androidx.core:core-ktx:1.6.0'
|
implementation 'androidx.core:core-ktx:1.6.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||||
|
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
// Ref: https://kotlinlang.org/releases.html
|
// Ref: https://kotlinlang.org/releases.html
|
||||||
ext.kotlin_version = '1.5.20'
|
ext.kotlin_version = '1.5.21'
|
||||||
ext.kotlin_coroutines_version = "1.5.0"
|
ext.kotlin_coroutines_version = "1.5.0"
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Remove redundant mimetype (vector-im/element-web#2547)
|
|
|
@ -4,7 +4,7 @@ Issue: #607
|
||||||
PR: #1354
|
PR: #1354
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
Identity Servers support contact discovery on Matrix by letting people look up Third Party Identifiers to see if the owner has publicly linked them with their Matrix ID.
|
Identity servers support contact discovery on Matrix by letting people look up Third Party Identifiers to see if the owner has publicly linked them with their Matrix ID.
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
|
@ -87,6 +87,6 @@ This screen displays the identity server configuration and the binding of the us
|
||||||
This screen is a form to set a new identity server URL
|
This screen is a form to set a new identity server URL
|
||||||
|
|
||||||
## Ref:
|
## Ref:
|
||||||
- https://matrix.org/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4 is a good summary of the role of an Identity server and the proper way to configure and use it in respect to the privacy and the consent of the user.
|
- https://matrix.org/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4 is a good summary of the role of an identity server and the proper way to configure and use it in respect to the privacy and the consent of the user.
|
||||||
- API documentation: https://matrix.org/docs/spec/identity_service/latest
|
- API documentation: https://matrix.org/docs/spec/identity_service/latest
|
||||||
- vector.im TOS: https://vector.im/identity-server-privacy-notice
|
- vector.im TOS: https://vector.im/identity-server-privacy-notice
|
||||||
|
|
|
@ -2,11 +2,11 @@ This document aims to describe how Element android displays notifications to the
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
1. [Prerequisites Knowledge](#prerequisites-knowledge)
|
1. [Prerequisites Knowledge](#prerequisites-knowledge)
|
||||||
* [How does a matrix client get a message from a Home Server?](#how-does-a-matrix-client-get-a-message-from-a-home-server)
|
* [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)
|
* [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 Home Server knows when to notify a client?](#how-does-the-home-server-knows-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)
|
2. [Element Notification implementations](#element-notification-implementations)
|
||||||
|
@ -22,9 +22,9 @@ First let's start with some prerequisite knowledge
|
||||||
|
|
||||||
# Prerequisites Knowledge
|
# Prerequisites Knowledge
|
||||||
|
|
||||||
## How does a matrix client get a message from a Home Server?
|
## How does a matrix client get a message from a homeserver?
|
||||||
|
|
||||||
In order to get messages from a home server, 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.
|
||||||
|
|
||||||
`To read events, the intended flow of operation is for clients to first call the /sync API without a since parameter. This returns the most recent message events for each room, as well as the state of the room at the start of the returned timeline. `
|
`To read events, the intended flow of operation is for clients to first call the /sync API without a since parameter. This returns the most recent message events for each room, as well as the state of the room at the start of the returned timeline. `
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ That means that Element Android, a matrix client created by New Vector, is using
|
||||||
|
|
||||||
If you create your own matrix client, you will also need to deploy an instance of a **Push Gateway** with the credentials needed to use FCM for your app.
|
If you create your own matrix client, you will also need to deploy an instance of a **Push Gateway** with the credentials needed to use FCM for your app.
|
||||||
|
|
||||||
On registration, a matrix client must tell to it's Home Server what Push Gateway to use.
|
On registration, a matrix client must tell its homeserver what Push Gateway to use.
|
||||||
|
|
||||||
See [Sygnal](https://github.com/matrix-org/sygnal/) for a reference implementation.
|
See [Sygnal](https://github.com/matrix-org/sygnal/) for a reference implementation.
|
||||||
```
|
```
|
||||||
|
@ -122,13 +122,13 @@ 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 Home Server knows 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-).
|
||||||
|
|
||||||
`A push rule is a single rule that states under what conditions an event should be passed onto a push gateway and how the notification should be presented (sound / importance).`
|
`A push rule is a single rule that states under what conditions an event should be passed onto a push gateway and how the notification should be presented (sound / importance).`
|
||||||
|
|
||||||
A Home Server can be configured with default rules (for Direct messages, group messages, mentions, etc.. ).
|
A homeserver can be configured with default rules (for Direct messages, group messages, mentions, etc.. ).
|
||||||
|
|
||||||
There are different kind of push rules, it can be per room (each new message on this room should be notified), it can also define a pattern that a message should match (when you are mentioned, or key word based).
|
There are different kind of push rules, it can be per room (each new message on this room should be notified), it can also define a pattern that a message should match (when you are mentioned, or key word based).
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ In background, and depending on wether push is available or not, Element will us
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
||||||
When a message should be notified to a user, the user's homeserver notifies the registered `push gateway` for Element, that is [sygnal](https://github.com/matrix-org/sygnal) _- The reference implementation for push gateways -_ hosted by matrix.org.
|
When a message should be notified to a user, the user's homeserver notifies the registered `push gateway` for Element, that is [sygnal](https://github.com/matrix-org/sygnal) _- The reference implementation for push gateways -_ hosted by matrix.org.
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ Homeserver ----> Sygnal (configured for Element) ----> FCM ----> Element
|
||||||
|
|
||||||
The push gateway is configured to only send `(eventId,roomId)` in the push payload (for better [privacy](#push-vs-privacy-and-mitigation)).
|
The push gateway is configured to only send `(eventId,roomId)` in the push payload (for better [privacy](#push-vs-privacy-and-mitigation)).
|
||||||
|
|
||||||
Element needs then to synchronise with the user's HomeServer, in order to resolve the event and create a notification.
|
Element needs then to synchronise with the user's homeserver, in order to resolve the event and create a notification.
|
||||||
|
|
||||||
As per [Google recommendation](https://android-developers.googleblog.com/2018/09/notifying-your-users-with-fcm.html), Element will then use the WorkManager API in order to trigger a background sync.
|
As per [Google recommendation](https://android-developers.googleblog.com/2018/09/notifying-your-users-with-fcm.html), Element will then use the WorkManager API in order to trigger a background sync.
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ Homeserver ----> Sygnal ----> FCM ----> Element
|
||||||
|
|
||||||
**Possible outcomes**
|
**Possible outcomes**
|
||||||
|
|
||||||
Upon reception of the FCM push, Element will perform a sync call to the Home Server, during this process it is possible that:
|
Upon reception of the FCM push, Element will perform a sync call to the homeserver, during this process it is possible that:
|
||||||
* Happy path, the sync is performed, the message resolved and displayed in the notification drawer
|
* Happy path, the sync is performed, the message resolved and displayed in the notification drawer
|
||||||
* The notified message is not in the sync. Can happen if a lot of things did happen since the push (`gappy sync`)
|
* The notified message is not in the sync. Can happen if a lot of things did happen since the push (`gappy sync`)
|
||||||
* The sync generates additional notifications (e.g an encrypted message where the user is mentioned detected locally)
|
* The sync generates additional notifications (e.g an encrypted message where the user is mentioned detected locally)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Hlavní změny v této verzi: aktualizace vzhledu a stylu a nové funkce prostorů.
|
||||||
|
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Hlavní změny v této verzi: aktualizace vzhledu a stylu a nové funkce prostorů (bugfix pro 1.1.10)
|
||||||
|
Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
Hauptänderungen: Design-Update und neue Features für Spaces
|
||||||
|
Vollständige Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Hauptänderungen: Design-Update und neue Features für Spaces (Bugfix für 1.1.10)
|
||||||
|
Vollständige Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: mainly stability and bugfixes update.
|
||||||
|
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.13
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: fix an issue about encrypted messages.
|
||||||
|
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.14
|
|
@ -0,0 +1,2 @@
|
||||||
|
Põhilised muutused selles versioonis: teemade ja välimuse uuendused ning mõned kogukondade uuendused
|
||||||
|
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Põhilised muutused selles versioonis: teemade ja välimuse uuendused ning mõned kogukondade uuendused (1.1.10 veaparandus)
|
||||||
|
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
Főbb változtatások ebben a verzióban: kinézet és stílus frissítések és új funkciók a terekhez
|
||||||
|
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Főbb változtatások ebben a verzióban: kinézet és stílus frissítések és új funkciók a terekhez (hibajavítás az 1.1.10-hez)
|
||||||
|
Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
Modifiche principali in questa versione: aggiornati tema e stile e nuove funzioni per gli spazi .
|
||||||
|
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Modifiche principali in questa versione: aggiornati tema e stile e nuove funzioni per gli spazi (bugfix per 1.1.10)
|
||||||
|
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -1,2 +1,2 @@
|
||||||
Principais mudanças nesta version: suporte beta para Espaços. Comprimir vídeo antes de enviar.
|
Principais mudanças nesta versão: suporte beta para Espaços. Comprimir vídeo antes de enviar.
|
||||||
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.7
|
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.7
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
Principais mudanças nesta version: melhoramento para Espaços.
|
Principais mudanças nesta versão: melhoramento para Espaços.
|
||||||
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.8
|
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.8
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
Principais mudanças nesta version: adicionar supporte a rede gitter.im.
|
Principais mudanças nesta versão: adicionar supporte a rede gitter.im.
|
||||||
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.9
|
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.9
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Principais mudanças nesta versão: atualização de tema e estilo e novas funcionalidades para espaços.
|
||||||
|
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Principais mudanças nesta versão: atualização de tema e estilo e novas funcionalidades para espaços (bugfix para 1.1.10)
|
||||||
|
Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів
|
||||||
|
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
Основні зміни цієї версії: оновлено зовнішній вигляд та нові можливості для просторів (bugfix для 1.1.10)
|
||||||
|
Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
此版本的主要变化:主题和样式更新以及空间的新功能。
|
||||||
|
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
此版本的主要变化:主题和样式更新以及空间的新功能(1.1.10 的错误修复)
|
||||||
|
完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -0,0 +1,2 @@
|
||||||
|
此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能。
|
||||||
|
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.10
|
|
@ -0,0 +1,2 @@
|
||||||
|
此版本中的主要變動:佈景主題與樣式更新,以及空間的新功能(1.1.10 的臭蟲修復版本)
|
||||||
|
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.11
|
|
@ -52,8 +52,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
// Pref theme
|
// Pref theme
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
// PFLockScreen attrs
|
// PFLockScreen attrs
|
||||||
|
|
|
@ -35,7 +35,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":matrix-sdk-android")
|
implementation project(":matrix-sdk-android")
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
|
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version"
|
||||||
|
|
|
@ -112,7 +112,7 @@ dependencies {
|
||||||
def lifecycle_version = '2.2.0'
|
def lifecycle_version = '2.2.0'
|
||||||
def arch_version = '2.1.0'
|
def arch_version = '2.1.0'
|
||||||
def markwon_version = '3.1.0'
|
def markwon_version = '3.1.0'
|
||||||
def daggerVersion = '2.37'
|
def daggerVersion = '2.38'
|
||||||
def work_version = '2.5.0'
|
def work_version = '2.5.0'
|
||||||
def retrofit_version = '2.9.0'
|
def retrofit_version = '2.9.0'
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ dependencies {
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:1.3.0"
|
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||||
implementation "androidx.core:core-ktx:1.6.0"
|
implementation "androidx.core:core-ktx:1.6.0"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||||
|
@ -169,14 +169,14 @@ dependencies {
|
||||||
implementation 'com.otaliastudios:transcoder:0.10.3'
|
implementation 'com.otaliastudios:transcoder:0.10.3'
|
||||||
|
|
||||||
// Phone number https://github.com/google/libphonenumber
|
// Phone number https://github.com/google/libphonenumber
|
||||||
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.26'
|
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
testImplementation 'org.robolectric:robolectric:4.5.1'
|
testImplementation 'org.robolectric:robolectric:4.5.1'
|
||||||
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||||
testImplementation 'io.mockk:mockk:1.12.0'
|
testImplementation 'io.mockk:mockk:1.12.0'
|
||||||
testImplementation 'org.amshove.kluent:kluent-android:1.67'
|
testImplementation 'org.amshove.kluent:kluent-android:1.68'
|
||||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
// Plant Timber tree for test
|
// Plant Timber tree for test
|
||||||
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||||
|
@ -185,9 +185,9 @@ dependencies {
|
||||||
androidTestImplementation 'androidx.test:core:1.4.0'
|
androidTestImplementation 'androidx.test:core:1.4.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||||
androidTestImplementation 'androidx.test:rules:1.4.0'
|
androidTestImplementation 'androidx.test:rules:1.4.0'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.65'
|
androidTestImplementation 'org.amshove.kluent:kluent-android:1.68'
|
||||||
androidTestImplementation 'io.mockk:mockk-android:1.12.0'
|
androidTestImplementation 'io.mockk:mockk-android:1.12.0'
|
||||||
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
|
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
|
||||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
|
|
@ -78,7 +78,7 @@ class CommonTestHelper(context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Home server configuration, with Http connection allowed for test
|
* Create a homeserver configuration, with Http connection allowed for test
|
||||||
*/
|
*/
|
||||||
fun createHomeServerConfig(): HomeServerConnectionConfig {
|
fun createHomeServerConfig(): HomeServerConnectionConfig {
|
||||||
return HomeServerConnectionConfig.Builder()
|
return HomeServerConnectionConfig.Builder()
|
||||||
|
|
|
@ -816,7 +816,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||||
// - Do an e2e backup to the homeserver
|
// - Do an e2e backup to the homeserver
|
||||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||||
|
|
||||||
// Get key backup version from the home server
|
// Get key backup version from the homeserver
|
||||||
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
||||||
keysBackup.getCurrentVersion(it)
|
keysBackup.getCurrentVersion(it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,12 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api
|
package org.matrix.android.sdk.api
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.BuildConfig
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains pattern to match the different Matrix ids
|
* This class contains pattern to match the different Matrix ids
|
||||||
|
* Ref: https://matrix.org/docs/spec/appendices#identifier-grammar
|
||||||
*/
|
*/
|
||||||
object MatrixPatterns {
|
object MatrixPatterns {
|
||||||
|
|
||||||
|
@ -25,7 +29,7 @@ object MatrixPatterns {
|
||||||
private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"
|
private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"
|
||||||
|
|
||||||
// regex pattern to find matrix user ids in a string.
|
// regex pattern to find matrix user ids in a string.
|
||||||
// See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids
|
// See https://matrix.org/docs/spec/appendices#historical-user-ids
|
||||||
private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
|
private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
|
||||||
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
|
@ -154,7 +158,7 @@ object MatrixPatterns {
|
||||||
* Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7E (~),
|
* Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7E (~),
|
||||||
* or consist of more than 50 characters, are forbidden and the field should be ignored if received.
|
* or consist of more than 50 characters, are forbidden and the field should be ignored if received.
|
||||||
*/
|
*/
|
||||||
fun isValidOrderString(order: String?) : Boolean {
|
fun isValidOrderString(order: String?): Boolean {
|
||||||
return order != null && order.length < 50 && order matches ORDER_STRING_REGEX
|
return order != null && order.length < 50 && order matches ORDER_STRING_REGEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,4 +167,18 @@ object MatrixPatterns {
|
||||||
"[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
|
"[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain form a userId
|
||||||
|
* Examples:
|
||||||
|
* - "@alice:domain.org".getDomain() will return "domain.org"
|
||||||
|
* - "@bob:domain.org:3455".getDomain() will return "domain.org:3455"
|
||||||
|
*/
|
||||||
|
fun String.getDomain(): String {
|
||||||
|
if (BuildConfig.DEBUG && !isUserId(this)) {
|
||||||
|
// They are some invalid userId localpart in the wild, but the domain part should be there anyway
|
||||||
|
Timber.w("Not a valid user ID: $this")
|
||||||
|
}
|
||||||
|
return substringAfter(":")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ package org.matrix.android.sdk.api.auth.data
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import okhttp3.CipherSuite
|
||||||
|
import okhttp3.TlsVersion
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig.Builder
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig.Builder
|
||||||
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
||||||
import org.matrix.android.sdk.internal.util.ensureTrailingSlash
|
import org.matrix.android.sdk.internal.util.ensureTrailingSlash
|
||||||
import okhttp3.CipherSuite
|
|
||||||
import okhttp3.TlsVersion
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This data class holds how to connect to a specific Homeserver.
|
* This data class holds how to connect to a specific Homeserver.
|
||||||
|
@ -31,7 +31,12 @@ import okhttp3.TlsVersion
|
||||||
*/
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class HomeServerConnectionConfig(
|
data class HomeServerConnectionConfig(
|
||||||
|
// This is the homeserver URL entered by the user
|
||||||
val homeServerUri: Uri,
|
val homeServerUri: Uri,
|
||||||
|
// This is the homeserver base URL for the client-server API. Default to homeServerUri,
|
||||||
|
// but can be updated with data from .Well-Known before login, and/or with the data
|
||||||
|
// included in the login response
|
||||||
|
val homeServerUriBase: Uri = homeServerUri,
|
||||||
val identityServerUri: Uri? = null,
|
val identityServerUri: Uri? = null,
|
||||||
val antiVirusServerUri: Uri? = null,
|
val antiVirusServerUri: Uri? = null,
|
||||||
val allowedFingerprints: List<Fingerprint> = emptyList(),
|
val allowedFingerprints: List<Fingerprint> = emptyList(),
|
||||||
|
@ -47,7 +52,6 @@ data class HomeServerConnectionConfig(
|
||||||
* This builder should be use to create a [HomeServerConnectionConfig] instance.
|
* This builder should be use to create a [HomeServerConnectionConfig] instance.
|
||||||
*/
|
*/
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
private lateinit var homeServerUri: Uri
|
private lateinit var homeServerUri: Uri
|
||||||
private var identityServerUri: Uri? = null
|
private var identityServerUri: Uri? = null
|
||||||
private var antiVirusServerUri: Uri? = null
|
private var antiVirusServerUri: Uri? = null
|
||||||
|
@ -69,14 +73,14 @@ data class HomeServerConnectionConfig(
|
||||||
*/
|
*/
|
||||||
fun withHomeServerUri(hsUri: Uri): Builder {
|
fun withHomeServerUri(hsUri: Uri): Builder {
|
||||||
if (hsUri.scheme != "http" && hsUri.scheme != "https") {
|
if (hsUri.scheme != "http" && hsUri.scheme != "https") {
|
||||||
throw RuntimeException("Invalid home server URI: $hsUri")
|
throw RuntimeException("Invalid homeserver URI: $hsUri")
|
||||||
}
|
}
|
||||||
// ensure trailing /
|
// ensure trailing /
|
||||||
val hsString = hsUri.toString().ensureTrailingSlash()
|
val hsString = hsUri.toString().ensureTrailingSlash()
|
||||||
homeServerUri = try {
|
homeServerUri = try {
|
||||||
Uri.parse(hsString)
|
Uri.parse(hsString)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw RuntimeException("Invalid home server URI: $hsUri")
|
throw RuntimeException("Invalid homeserver URI: $hsUri")
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -134,7 +138,7 @@ data class HomeServerConnectionConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an accepted TLS version for TLS connections with the home server.
|
* Add an accepted TLS version for TLS connections with the homeserver.
|
||||||
*
|
*
|
||||||
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
|
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
|
||||||
* @return this builder
|
* @return this builder
|
||||||
|
@ -156,7 +160,7 @@ data class HomeServerConnectionConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a TLS cipher suite to the list of accepted TLS connections with the home server.
|
* Add a TLS cipher suite to the list of accepted TLS connections with the homeserver.
|
||||||
*
|
*
|
||||||
* @param tlsCipherSuite the tls cipher suite to add.
|
* @param tlsCipherSuite the tls cipher suite to add.
|
||||||
* @return this builder
|
* @return this builder
|
||||||
|
@ -234,16 +238,16 @@ data class HomeServerConnectionConfig(
|
||||||
*/
|
*/
|
||||||
fun build(): HomeServerConnectionConfig {
|
fun build(): HomeServerConnectionConfig {
|
||||||
return HomeServerConnectionConfig(
|
return HomeServerConnectionConfig(
|
||||||
homeServerUri,
|
homeServerUri = homeServerUri,
|
||||||
identityServerUri,
|
identityServerUri = identityServerUri,
|
||||||
antiVirusServerUri,
|
antiVirusServerUri = antiVirusServerUri,
|
||||||
allowedFingerprints,
|
allowedFingerprints = allowedFingerprints,
|
||||||
shouldPin,
|
shouldPin = shouldPin,
|
||||||
tlsVersions,
|
tlsVersions = tlsVersions,
|
||||||
tlsCipherSuites,
|
tlsCipherSuites = tlsCipherSuites,
|
||||||
shouldAcceptTlsExtensions,
|
shouldAcceptTlsExtensions = shouldAcceptTlsExtensions,
|
||||||
allowHttpExtension,
|
allowHttpExtension = allowHttpExtension,
|
||||||
forceUsageTlsVersions
|
forceUsageTlsVersions = forceUsageTlsVersions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,18 @@ data class SessionParams(
|
||||||
val deviceId = credentials.deviceId
|
val deviceId = credentials.deviceId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current homeserver Url. It can be different that the homeserver url entered
|
* The homeserver Url entered by the user during the login phase.
|
||||||
* during login phase, because a redirection may have occurred
|
|
||||||
*/
|
*/
|
||||||
val homeServerUrl = homeServerConnectionConfig.homeServerUri.toString()
|
val homeServerUrl = homeServerConnectionConfig.homeServerUri.toString()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current homeserver host
|
* The current homeserver Url for client-server API. It can be different that the homeserver url entered
|
||||||
|
* during login phase, because a redirection may have occurred
|
||||||
|
*/
|
||||||
|
val homeServerUrlBase = homeServerConnectionConfig.homeServerUriBase.toString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current homeserver host, using what has been entered by the user during login phase
|
||||||
*/
|
*/
|
||||||
val homeServerHost = homeServerConnectionConfig.homeServerUri.host
|
val homeServerHost = homeServerConnectionConfig.homeServerUri.host
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ data class RegistrationFlowResponse(
|
||||||
val completedStages: List<String>? = null,
|
val completedStages: List<String>? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The session identifier that the client must pass back to the home server, if one is provided,
|
* The session identifier that the client must pass back to the homeserver, if one is provided,
|
||||||
* in subsequent attempts to authenticate in the same API call.
|
* in subsequent attempts to authenticate in the same API call.
|
||||||
*/
|
*/
|
||||||
@Json(name = "session")
|
@Json(name = "session")
|
||||||
|
|
|
@ -22,11 +22,6 @@ import org.matrix.android.sdk.api.auth.data.WellKnown
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#well-known-uri
|
* Ref: https://matrix.org/docs/spec/client_server/latest#well-known-uri
|
||||||
*/
|
*/
|
||||||
sealed class WellknownResult {
|
sealed class WellknownResult {
|
||||||
/**
|
|
||||||
* The provided matrixId is no valid. Unable to extract a domain name.
|
|
||||||
*/
|
|
||||||
object InvalidMatrixId : WellknownResult()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the specific piece of information from the user in a way which fits within the existing client user experience,
|
* Retrieve the specific piece of information from the user in a way which fits within the existing client user experience,
|
||||||
* if the client is inclined to do so. Failure can take place instead if no good user experience for this is possible at this point.
|
* if the client is inclined to do so. Failure can take place instead if no good user experience for this is possible at this point.
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.failure
|
||||||
|
|
||||||
|
sealed class MatrixIdFailure : Failure.FeatureFailure() {
|
||||||
|
object InvalidMatrixId : MatrixIdFailure()
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.logger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent class for custom logger tags. Can be used with Timber :
|
||||||
|
*
|
||||||
|
* val loggerTag = LoggerTag("MyTag", LoggerTag.VOIP)
|
||||||
|
* Timber.tag(loggerTag.value).v("My log message")
|
||||||
|
*/
|
||||||
|
open class LoggerTag(_value: String, parentTag: LoggerTag? = null) {
|
||||||
|
|
||||||
|
object VOIP : LoggerTag("VOIP")
|
||||||
|
|
||||||
|
val value: String = if (parentTag == null) {
|
||||||
|
_value
|
||||||
|
} else {
|
||||||
|
"${parentTag.value}/$_value"
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,8 +29,10 @@ interface RawService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific case for the well-known file. Cache validity is 8 hours
|
* Specific case for the well-known file. Cache validity is 8 hours
|
||||||
|
* @param domain the domain to get the .well-known file, for instance "matrix.org".
|
||||||
|
* The URL will be "https://{domain}/.well-known/matrix/client"
|
||||||
*/
|
*/
|
||||||
suspend fun getWellknown(userId: String): String
|
suspend fun getWellknown(domain: String): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all the cache data
|
* Clear all the cache data
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.call
|
package org.matrix.android.sdk.api.session.call
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
||||||
|
|
||||||
sealed class CallState {
|
sealed class CallState {
|
||||||
|
|
||||||
/** Idle, setting up objects */
|
/** Idle, setting up objects */
|
||||||
|
@ -42,6 +44,6 @@ sealed class CallState {
|
||||||
* */
|
* */
|
||||||
data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState()
|
data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState()
|
||||||
|
|
||||||
/** Terminated. Incoming/Outgoing call, the call is terminated */
|
/** Ended. Incoming/Outgoing call, the call is terminated */
|
||||||
object Terminated : CallState()
|
data class Ended(val reason: EndCallReason? = null) : CallState()
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.call
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
|
import org.matrix.android.sdk.api.session.room.model.call.CallCandidate
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
|
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ interface MxCall : MxCallDetail {
|
||||||
/**
|
/**
|
||||||
* End the call
|
* End the call
|
||||||
*/
|
*/
|
||||||
fun hangUp(reason: CallHangupContent.Reason? = null)
|
fun hangUp(reason: EndCallReason? = null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a call
|
* Start a call
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
|
||||||
|
|
||||||
interface KeysBackupService {
|
interface KeysBackupService {
|
||||||
/**
|
/**
|
||||||
* Retrieve the current version of the backup from the home server
|
* Retrieve the current version of the backup from the homeserver
|
||||||
*
|
*
|
||||||
* It can be different than keysBackupVersion.
|
* It can be different than keysBackupVersion.
|
||||||
* @param callback onSuccess(null) will be called if there is no backup on the server
|
* @param callback onSuccess(null) will be called if there is no backup on the server
|
||||||
|
|
|
@ -54,7 +54,7 @@ enum class KeysBackupState {
|
||||||
// Need to check the current backup version on the homeserver
|
// Need to check the current backup version on the homeserver
|
||||||
Unknown,
|
Unknown,
|
||||||
|
|
||||||
// Checking if backup is enabled on home server
|
// Checking if backup is enabled on homeserver
|
||||||
CheckingBackUpOnHomeserver,
|
CheckingBackUpOnHomeserver,
|
||||||
|
|
||||||
// Backup has been stopped because a new backup version has been detected on the homeserver
|
// Backup has been stopped because a new backup version has been detected on the homeserver
|
||||||
|
|
|
@ -104,7 +104,7 @@ data class Event(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `age` value transcoded in a timestamp based on the device clock when the SDK received
|
* The `age` value transcoded in a timestamp based on the device clock when the SDK received
|
||||||
* the event from the home server.
|
* the event from the homeserver.
|
||||||
* Unlike `age`, this value is static.
|
* Unlike `age`, this value is static.
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
|
|
|
@ -32,7 +32,13 @@ data class HomeServerCapabilities(
|
||||||
/**
|
/**
|
||||||
* Default identity server url, provided in Wellknown
|
* Default identity server url, provided in Wellknown
|
||||||
*/
|
*/
|
||||||
val defaultIdentityServerUrl: String? = null
|
val defaultIdentityServerUrl: String? = null,
|
||||||
|
/**
|
||||||
|
* Room versions supported by the server
|
||||||
|
* This capability describes the default and available room versions a server supports, and at what level of stability.
|
||||||
|
* Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms.
|
||||||
|
*/
|
||||||
|
val roomVersions: RoomVersionCapabilities? = null
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L
|
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.session.homeserver
|
||||||
|
|
||||||
|
data class RoomVersionCapabilities(
|
||||||
|
val defaultRoomVersion: String,
|
||||||
|
val supportedVersion: List<RoomVersionInfo>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class RoomVersionInfo(
|
||||||
|
val version: String,
|
||||||
|
val status: RoomVersionStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class RoomVersionStatus {
|
||||||
|
STABLE,
|
||||||
|
UNSTABLE
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
||||||
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
||||||
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
||||||
|
import org.matrix.android.sdk.api.session.room.version.RoomVersionService
|
||||||
import org.matrix.android.sdk.api.session.search.SearchResult
|
import org.matrix.android.sdk.api.session.search.SearchResult
|
||||||
import org.matrix.android.sdk.api.session.space.Space
|
import org.matrix.android.sdk.api.session.space.Space
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
@ -57,7 +58,8 @@ interface Room :
|
||||||
RelationService,
|
RelationService,
|
||||||
RoomCryptoService,
|
RoomCryptoService,
|
||||||
RoomPushRuleService,
|
RoomPushRuleService,
|
||||||
RoomAccountDataService {
|
RoomAccountDataService,
|
||||||
|
RoomVersionService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The roomId of this room
|
* The roomId of this room
|
||||||
|
|
|
@ -39,12 +39,6 @@ fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) =
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class RoomCategoryFilter {
|
|
||||||
ONLY_DM,
|
|
||||||
ONLY_ROOMS,
|
|
||||||
ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class can be used to filter room summaries to use with:
|
* This class can be used to filter room summaries to use with:
|
||||||
* [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
|
* [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
|
||||||
|
@ -59,11 +53,10 @@ data class RoomSummaryQueryParams(
|
||||||
val excludeType: List<String?>?,
|
val excludeType: List<String?>?,
|
||||||
val includeType: List<String?>?,
|
val includeType: List<String?>?,
|
||||||
val activeSpaceFilter: ActiveSpaceFilter?,
|
val activeSpaceFilter: ActiveSpaceFilter?,
|
||||||
var activeGroupId: String? = null
|
val activeGroupId: String? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
var roomId: QueryStringValue = QueryStringValue.IsNotEmpty
|
var roomId: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||||
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||||
var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition
|
var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition
|
||||||
|
|
|
@ -43,29 +43,5 @@ data class CallHangupContent(
|
||||||
* or `invite_timeout` for when the other party did not answer in time.
|
* or `invite_timeout` for when the other party did not answer in time.
|
||||||
* One of: ["ice_failed", "invite_timeout"]
|
* One of: ["ice_failed", "invite_timeout"]
|
||||||
*/
|
*/
|
||||||
@Json(name = "reason") val reason: Reason? = null
|
@Json(name = "reason") val reason: EndCallReason? = null
|
||||||
) : CallSignalingContent {
|
) : CallSignalingContent
|
||||||
@JsonClass(generateAdapter = false)
|
|
||||||
enum class Reason {
|
|
||||||
@Json(name = "ice_failed")
|
|
||||||
ICE_FAILED,
|
|
||||||
|
|
||||||
@Json(name = "ice_timeout")
|
|
||||||
ICE_TIMEOUT,
|
|
||||||
|
|
||||||
@Json(name = "user_hangup")
|
|
||||||
USER_HANGUP,
|
|
||||||
|
|
||||||
@Json(name = "replaced")
|
|
||||||
REPLACED,
|
|
||||||
|
|
||||||
@Json(name = "user_media_failed")
|
|
||||||
USER_MEDIA_FAILED,
|
|
||||||
|
|
||||||
@Json(name = "invite_timeout")
|
|
||||||
INVITE_TIMEOUT,
|
|
||||||
|
|
||||||
@Json(name = "unknown_error")
|
|
||||||
UNKWOWN_ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,5 +36,10 @@ data class CallRejectContent(
|
||||||
/**
|
/**
|
||||||
* Required. The version of the VoIP specification this message adheres to.
|
* Required. The version of the VoIP specification this message adheres to.
|
||||||
*/
|
*/
|
||||||
@Json(name = "version") override val version: String?
|
@Json(name = "version") override val version: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional error reason for the reject.
|
||||||
|
*/
|
||||||
|
@Json(name = "reason") val reason: EndCallReason? = null
|
||||||
) : CallSignalingContent
|
) : CallSignalingContent
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.session.room.model.call
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = false)
|
||||||
|
enum class EndCallReason {
|
||||||
|
@Json(name = "ice_failed")
|
||||||
|
ICE_FAILED,
|
||||||
|
|
||||||
|
@Json(name = "ice_timeout")
|
||||||
|
ICE_TIMEOUT,
|
||||||
|
|
||||||
|
@Json(name = "user_hangup")
|
||||||
|
USER_HANGUP,
|
||||||
|
|
||||||
|
@Json(name = "replaced")
|
||||||
|
REPLACED,
|
||||||
|
|
||||||
|
@Json(name = "user_media_failed")
|
||||||
|
USER_MEDIA_FAILED,
|
||||||
|
|
||||||
|
@Json(name = "invite_timeout")
|
||||||
|
INVITE_TIMEOUT,
|
||||||
|
|
||||||
|
@Json(name = "unknown_error")
|
||||||
|
UNKWOWN_ERROR,
|
||||||
|
|
||||||
|
@Json(name = "user_busy")
|
||||||
|
USER_BUSY,
|
||||||
|
|
||||||
|
@Json(name = "answered_elsewhere")
|
||||||
|
ANSWERED_ELSEWHERE
|
||||||
|
}
|
|
@ -25,7 +25,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
||||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||||
|
|
||||||
// TODO Give a way to include other initial states
|
|
||||||
open class CreateRoomParams {
|
open class CreateRoomParams {
|
||||||
/**
|
/**
|
||||||
* A public visibility indicates that the room will be shown in the published room list.
|
* A public visibility indicates that the room will be shown in the published room list.
|
||||||
|
@ -103,6 +102,13 @@ open class CreateRoomParams {
|
||||||
*/
|
*/
|
||||||
val creationContent = mutableMapOf<String, Any>()
|
val creationContent = mutableMapOf<String, Any>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of state events to set in the new room. This allows the user to override the default state events
|
||||||
|
* set in the new room. The expected format of the state events are an object with type, state_key and content keys set.
|
||||||
|
* Takes precedence over events set by preset, but gets overridden by name and topic keys.
|
||||||
|
*/
|
||||||
|
val initialStates = mutableListOf<CreateRoomStateEvent>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true to disable federation of this room.
|
* Set to true to disable federation of this room.
|
||||||
* Default: false
|
* Default: false
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.session.room.model.create
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Content
|
||||||
|
|
||||||
|
data class CreateRoomStateEvent(
|
||||||
|
/**
|
||||||
|
* Required. The type of event to send.
|
||||||
|
*/
|
||||||
|
val type: String,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. The content of the event.
|
||||||
|
*/
|
||||||
|
val content: Content,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state_key of the state event. Defaults to an empty string.
|
||||||
|
*/
|
||||||
|
val stateKey: String = ""
|
||||||
|
)
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.session.room.version
|
||||||
|
|
||||||
|
interface RoomVersionService {
|
||||||
|
/**
|
||||||
|
* Return the room version of this room
|
||||||
|
*/
|
||||||
|
fun getRoomVersion(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upgrade to the given room version
|
||||||
|
* @return the replacement room id
|
||||||
|
*/
|
||||||
|
suspend fun upgradeToVersion(version: String): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the recommended room version for the current homeserver
|
||||||
|
*/
|
||||||
|
fun getRecommendedVersion() : String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask if the user has enough power level to upgrade the room
|
||||||
|
*/
|
||||||
|
fun userMayUpgradeRoom(userId: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the current room version is declared unstable by the homeserver
|
||||||
|
*/
|
||||||
|
fun isUsingUnstableRoomVersion(): Boolean
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.space
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.room.Room
|
import org.matrix.android.sdk.api.session.room.Room
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||||
|
|
||||||
interface Space {
|
interface Space {
|
||||||
|
|
||||||
|
@ -38,6 +39,8 @@ interface Space {
|
||||||
autoJoin: Boolean = false,
|
autoJoin: Boolean = false,
|
||||||
suggested: Boolean? = false)
|
suggested: Boolean? = false)
|
||||||
|
|
||||||
|
fun getChildInfo(roomId: String): SpaceChildContent?
|
||||||
|
|
||||||
suspend fun removeChildren(roomId: String)
|
suspend fun removeChildren(roomId: String)
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
|
|
|
@ -21,8 +21,8 @@ import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.internal.auth.data.Availability
|
import org.matrix.android.sdk.internal.auth.data.Availability
|
||||||
import org.matrix.android.sdk.internal.auth.data.LoginFlowResponse
|
import org.matrix.android.sdk.internal.auth.data.LoginFlowResponse
|
||||||
import org.matrix.android.sdk.internal.auth.data.PasswordLoginParams
|
import org.matrix.android.sdk.internal.auth.data.PasswordLoginParams
|
||||||
import org.matrix.android.sdk.internal.auth.data.RiotConfig
|
|
||||||
import org.matrix.android.sdk.internal.auth.data.TokenLoginParams
|
import org.matrix.android.sdk.internal.auth.data.TokenLoginParams
|
||||||
|
import org.matrix.android.sdk.internal.auth.data.WebClientConfig
|
||||||
import org.matrix.android.sdk.internal.auth.login.ResetPasswordMailConfirmed
|
import org.matrix.android.sdk.internal.auth.login.ResetPasswordMailConfirmed
|
||||||
import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams
|
import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationParams
|
||||||
import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationResponse
|
import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationResponse
|
||||||
|
@ -44,16 +44,16 @@ import retrofit2.http.Url
|
||||||
*/
|
*/
|
||||||
internal interface AuthAPI {
|
internal interface AuthAPI {
|
||||||
/**
|
/**
|
||||||
* Get a Riot config file, using the name including the domain
|
* Get a Web client config file, using the name including the domain
|
||||||
*/
|
*/
|
||||||
@GET("config.{domain}.json")
|
@GET("config.{domain}.json")
|
||||||
suspend fun getRiotConfigDomain(@Path("domain") domain: String): RiotConfig
|
suspend fun getWebClientConfigDomain(@Path("domain") domain: String): WebClientConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a Riot config file
|
* Get a Web client default config file
|
||||||
*/
|
*/
|
||||||
@GET("config.json")
|
@GET("config.json")
|
||||||
suspend fun getRiotConfig(): RiotConfig
|
suspend fun getWebClientConfig(): WebClientConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version information of the homeserver
|
* Get the version information of the homeserver
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.auth
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
|
import org.matrix.android.sdk.api.MatrixPatterns.getDomain
|
||||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
@ -28,10 +30,11 @@ import org.matrix.android.sdk.api.auth.login.LoginWizard
|
||||||
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
||||||
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
|
import org.matrix.android.sdk.api.failure.MatrixIdFailure
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.util.appendParamToUrl
|
import org.matrix.android.sdk.api.util.appendParamToUrl
|
||||||
import org.matrix.android.sdk.internal.SessionManager
|
import org.matrix.android.sdk.internal.SessionManager
|
||||||
import org.matrix.android.sdk.internal.auth.data.RiotConfig
|
import org.matrix.android.sdk.internal.auth.data.WebClientConfig
|
||||||
import org.matrix.android.sdk.internal.auth.db.PendingSessionData
|
import org.matrix.android.sdk.internal.auth.db.PendingSessionData
|
||||||
import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
|
import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
|
||||||
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
||||||
|
@ -122,7 +125,7 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
private fun getHomeServerUrlBase(): String? {
|
private fun getHomeServerUrlBase(): String? {
|
||||||
return pendingSessionData
|
return pendingSessionData
|
||||||
?.homeServerConnectionConfig
|
?.homeServerConnectionConfig
|
||||||
?.homeServerUri
|
?.homeServerUriBase
|
||||||
?.toString()
|
?.toString()
|
||||||
?.trim { it == '/' }
|
?.trim { it == '/' }
|
||||||
}
|
}
|
||||||
|
@ -143,9 +146,9 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
return result.fold(
|
return result.fold(
|
||||||
{
|
{
|
||||||
// The homeserver exists and up to date, keep the config
|
// The homeserver exists and up to date, keep the config
|
||||||
// Homeserver url may have been changed, if it was a Riot url
|
// Homeserver url may have been changed, if it was a Web client url
|
||||||
val alteredHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
val alteredHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
||||||
homeServerUri = Uri.parse(it.homeServerUrl)
|
homeServerUriBase = Uri.parse(it.homeServerUrl)
|
||||||
)
|
)
|
||||||
|
|
||||||
pendingSessionData = PendingSessionData(alteredHomeServerConnectionConfig)
|
pendingSessionData = PendingSessionData(alteredHomeServerConnectionConfig)
|
||||||
|
@ -154,7 +157,7 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
if (it is UnrecognizedCertificateException) {
|
if (it is UnrecognizedCertificateException) {
|
||||||
throw Failure.UnrecognizedCertificateFailure(homeServerConnectionConfig.homeServerUri.toString(), it.fingerprint)
|
throw Failure.UnrecognizedCertificateFailure(homeServerConnectionConfig.homeServerUriBase.toString(), it.fingerprint)
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
@ -165,46 +168,57 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
||||||
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
||||||
|
|
||||||
// First check the homeserver version
|
// First check if there is a well-known file
|
||||||
return runCatching {
|
return try {
|
||||||
executeRequest(null) {
|
getWellknownLoginFlowInternal(homeServerConnectionConfig)
|
||||||
authAPI.versions()
|
} catch (failure: Throwable) {
|
||||||
|
if (failure is Failure.OtherServerError
|
||||||
|
&& failure.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
||||||
|
// 404, no well-known data, try direct access to the API
|
||||||
|
// First check the homeserver version
|
||||||
|
return runCatching {
|
||||||
|
executeRequest(null) {
|
||||||
|
authAPI.versions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map { versions ->
|
||||||
|
// Ok, it seems that the homeserver url is valid
|
||||||
|
getLoginFlowResult(authAPI, versions, homeServerConnectionConfig.homeServerUriBase.toString())
|
||||||
|
}
|
||||||
|
.fold(
|
||||||
|
{
|
||||||
|
it
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if (it is Failure.OtherServerError
|
||||||
|
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
||||||
|
// It's maybe a Web client url?
|
||||||
|
getWebClientDomainLoginFlowInternal(homeServerConnectionConfig)
|
||||||
|
} else {
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { versions ->
|
|
||||||
// Ok, it seems that the homeserver url is valid
|
|
||||||
getLoginFlowResult(authAPI, versions, homeServerConnectionConfig.homeServerUri.toString())
|
|
||||||
}
|
|
||||||
.fold(
|
|
||||||
{
|
|
||||||
it
|
|
||||||
},
|
|
||||||
{
|
|
||||||
if (it is Failure.OtherServerError
|
|
||||||
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
|
||||||
// It's maybe a Riot url?
|
|
||||||
getRiotDomainLoginFlowInternal(homeServerConnectionConfig)
|
|
||||||
} else {
|
|
||||||
throw it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getRiotDomainLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
private suspend fun getWebClientDomainLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
||||||
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
||||||
|
|
||||||
val domain = homeServerConnectionConfig.homeServerUri.host
|
val domain = homeServerConnectionConfig.homeServerUri.host
|
||||||
?: return getRiotLoginFlowInternal(homeServerConnectionConfig)
|
?: return getWebClientLoginFlowInternal(homeServerConnectionConfig)
|
||||||
|
|
||||||
// Ok, try to get the config.domain.json file of a RiotWeb client
|
// Ok, try to get the config.domain.json file of a Web client
|
||||||
return runCatching {
|
return runCatching {
|
||||||
executeRequest(null) {
|
executeRequest(null) {
|
||||||
authAPI.getRiotConfigDomain(domain)
|
authAPI.getWebClientConfigDomain(domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { riotConfig ->
|
.map { webClientConfig ->
|
||||||
onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig)
|
onWebClientConfigRetrieved(homeServerConnectionConfig, webClientConfig)
|
||||||
}
|
}
|
||||||
.fold(
|
.fold(
|
||||||
{
|
{
|
||||||
|
@ -214,7 +228,7 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
if (it is Failure.OtherServerError
|
if (it is Failure.OtherServerError
|
||||||
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
||||||
// Try with config.json
|
// Try with config.json
|
||||||
getRiotLoginFlowInternal(homeServerConnectionConfig)
|
getWebClientLoginFlowInternal(homeServerConnectionConfig)
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
@ -222,40 +236,24 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getRiotLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
private suspend fun getWebClientLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
|
||||||
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
||||||
|
|
||||||
// Ok, try to get the config.json file of a RiotWeb client
|
// Ok, try to get the config.json file of a Web client
|
||||||
return runCatching {
|
return executeRequest(null) {
|
||||||
executeRequest(null) {
|
authAPI.getWebClientConfig()
|
||||||
authAPI.getRiotConfig()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.map { riotConfig ->
|
.let { webClientConfig ->
|
||||||
onRiotConfigRetrieved(homeServerConnectionConfig, riotConfig)
|
onWebClientConfigRetrieved(homeServerConnectionConfig, webClientConfig)
|
||||||
}
|
}
|
||||||
.fold(
|
|
||||||
{
|
|
||||||
it
|
|
||||||
},
|
|
||||||
{
|
|
||||||
if (it is Failure.OtherServerError
|
|
||||||
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
|
|
||||||
// Try with wellknown
|
|
||||||
getWellknownLoginFlowInternal(homeServerConnectionConfig)
|
|
||||||
} else {
|
|
||||||
throw it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onRiotConfigRetrieved(homeServerConnectionConfig: HomeServerConnectionConfig, riotConfig: RiotConfig): LoginFlowResult {
|
private suspend fun onWebClientConfigRetrieved(homeServerConnectionConfig: HomeServerConnectionConfig, webClientConfig: WebClientConfig): LoginFlowResult {
|
||||||
val defaultHomeServerUrl = riotConfig.getPreferredHomeServerUrl()
|
val defaultHomeServerUrl = webClientConfig.getPreferredHomeServerUrl()
|
||||||
if (defaultHomeServerUrl?.isNotEmpty() == true) {
|
if (defaultHomeServerUrl?.isNotEmpty() == true) {
|
||||||
// Ok, good sign, we got a default hs url
|
// Ok, good sign, we got a default hs url
|
||||||
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
||||||
homeServerUri = Uri.parse(defaultHomeServerUrl)
|
homeServerUriBase = Uri.parse(defaultHomeServerUrl)
|
||||||
)
|
)
|
||||||
|
|
||||||
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
|
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
|
||||||
|
@ -275,15 +273,13 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
val domain = homeServerConnectionConfig.homeServerUri.host
|
val domain = homeServerConnectionConfig.homeServerUri.host
|
||||||
?: throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
|
?: throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
|
||||||
|
|
||||||
// Create a fake userId, for the getWellknown task
|
val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(domain, homeServerConnectionConfig))
|
||||||
val fakeUserId = "@alice:$domain"
|
|
||||||
val wellknownResult = getWellknownTask.execute(GetWellknownTask.Params(fakeUserId, homeServerConnectionConfig))
|
|
||||||
|
|
||||||
return when (wellknownResult) {
|
return when (wellknownResult) {
|
||||||
is WellknownResult.Prompt -> {
|
is WellknownResult.Prompt -> {
|
||||||
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
|
||||||
homeServerUri = Uri.parse(wellknownResult.homeServerUrl),
|
homeServerUriBase = Uri.parse(wellknownResult.homeServerUrl),
|
||||||
identityServerUri = wellknownResult.identityServerUrl?.let { Uri.parse(it) }
|
identityServerUri = wellknownResult.identityServerUrl?.let { Uri.parse(it) } ?: homeServerConnectionConfig.identityServerUri
|
||||||
)
|
)
|
||||||
|
|
||||||
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
|
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
|
||||||
|
@ -379,7 +375,14 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
|
|
||||||
override suspend fun getWellKnownData(matrixId: String,
|
override suspend fun getWellKnownData(matrixId: String,
|
||||||
homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult {
|
homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult {
|
||||||
return getWellknownTask.execute(GetWellknownTask.Params(matrixId, homeServerConnectionConfig))
|
if (!MatrixPatterns.isUserId(matrixId)) {
|
||||||
|
throw MatrixIdFailure.InvalidMatrixId
|
||||||
|
}
|
||||||
|
|
||||||
|
return getWellknownTask.execute(GetWellknownTask.Params(
|
||||||
|
domain = matrixId.getDomain(),
|
||||||
|
homeServerConnectionConfig = homeServerConnectionConfig)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
|
override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
|
@ -390,7 +393,7 @@ internal class DefaultAuthenticationService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
|
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
|
||||||
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUri.toString())
|
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString())
|
||||||
return retrofit.create(AuthAPI::class.java)
|
return retrofit.create(AuthAPI::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ internal class DefaultIsValidClientServerApiTask @Inject constructor(
|
||||||
|
|
||||||
override suspend fun execute(params: IsValidClientServerApiTask.Params): Boolean {
|
override suspend fun execute(params: IsValidClientServerApiTask.Params): Boolean {
|
||||||
val client = buildClient(params.homeServerConnectionConfig)
|
val client = buildClient(params.homeServerConnectionConfig)
|
||||||
val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString()
|
val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString()
|
||||||
|
|
||||||
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
||||||
.create(AuthAPI::class.java)
|
.create(AuthAPI::class.java)
|
||||||
|
|
|
@ -38,7 +38,7 @@ internal class DefaultSessionCreator @Inject constructor(
|
||||||
) : SessionCreator {
|
) : SessionCreator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credentials can affect the homeServerConnectionConfig, override home server url and/or
|
* Credentials can affect the homeServerConnectionConfig, override homeserver url and/or
|
||||||
* identity server url if provided in the credentials
|
* identity server url if provided in the credentials
|
||||||
*/
|
*/
|
||||||
override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
|
override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
|
||||||
|
@ -56,7 +56,7 @@ internal class DefaultSessionCreator @Inject constructor(
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
isValidClientServerApiTask.execute(
|
isValidClientServerApiTask.execute(
|
||||||
IsValidClientServerApiTask.Params(
|
IsValidClientServerApiTask.Params(
|
||||||
homeServerConnectionConfig.copy(homeServerUri = it)
|
homeServerConnectionConfig.copy(homeServerUriBase = it)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.also { Timber.d("Overriding homeserver url: $it") }
|
.also { Timber.d("Overriding homeserver url: $it") }
|
||||||
|
@ -66,7 +66,7 @@ internal class DefaultSessionCreator @Inject constructor(
|
||||||
val sessionParams = SessionParams(
|
val sessionParams = SessionParams(
|
||||||
credentials = credentials,
|
credentials = credentials,
|
||||||
homeServerConnectionConfig = homeServerConnectionConfig.copy(
|
homeServerConnectionConfig = homeServerConnectionConfig.copy(
|
||||||
homeServerUri = overriddenUrl ?: homeServerConnectionConfig.homeServerUri,
|
homeServerUriBase = overriddenUrl ?: homeServerConnectionConfig.homeServerUriBase,
|
||||||
identityServerUri = credentials.discoveryInformation?.identityServer?.baseURL
|
identityServerUri = credentials.discoveryInformation?.identityServer?.baseURL
|
||||||
// remove trailing "/"
|
// remove trailing "/"
|
||||||
?.trim { it == '/' }
|
?.trim { it == '/' }
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class RiotConfig(
|
internal data class WebClientConfig(
|
||||||
/**
|
/**
|
||||||
* This is now deprecated, but still used first, rather than value from "default_server_config"
|
* This is now deprecated, but still used first, rather than value from "default_server_config"
|
||||||
*/
|
*/
|
||||||
|
@ -28,7 +28,7 @@ internal data class RiotConfig(
|
||||||
val defaultHomeServerUrl: String?,
|
val defaultHomeServerUrl: String?,
|
||||||
|
|
||||||
@Json(name = "default_server_config")
|
@Json(name = "default_server_config")
|
||||||
val defaultServerConfig: RiotConfigDefaultServerConfig?
|
val defaultServerConfig: WebClientConfigDefaultServerConfig?
|
||||||
) {
|
) {
|
||||||
fun getPreferredHomeServerUrl(): String? {
|
fun getPreferredHomeServerUrl(): String? {
|
||||||
return defaultHomeServerUrl
|
return defaultHomeServerUrl
|
||||||
|
@ -38,13 +38,13 @@ internal data class RiotConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class RiotConfigDefaultServerConfig(
|
internal data class WebClientConfigDefaultServerConfig(
|
||||||
@Json(name = "m.homeserver")
|
@Json(name = "m.homeserver")
|
||||||
val homeServer: RiotConfigBaseConfig? = null
|
val homeServer: WebClientConfigBaseConfig? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class RiotConfigBaseConfig(
|
internal data class WebClientConfigBaseConfig(
|
||||||
@Json(name = "base_url")
|
@Json(name = "base_url")
|
||||||
val baseURL: String? = null
|
val baseURL: String? = null
|
||||||
)
|
)
|
|
@ -16,17 +16,19 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.auth.db
|
package org.matrix.android.sdk.internal.auth.db
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
import android.net.Uri
|
||||||
import org.matrix.android.sdk.api.auth.data.sessionId
|
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import io.realm.RealmMigration
|
import io.realm.RealmMigration
|
||||||
|
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||||
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import org.matrix.android.sdk.api.auth.data.sessionId
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal object AuthRealmMigration : RealmMigration {
|
internal object AuthRealmMigration : RealmMigration {
|
||||||
|
|
||||||
// Current schema version
|
// Current schema version
|
||||||
const val SCHEMA_VERSION = 3L
|
const val SCHEMA_VERSION = 4L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
|
Timber.d("Migrating Auth Realm from $oldVersion to $newVersion")
|
||||||
|
@ -34,6 +36,7 @@ internal object AuthRealmMigration : RealmMigration {
|
||||||
if (oldVersion <= 0) migrateTo1(realm)
|
if (oldVersion <= 0) migrateTo1(realm)
|
||||||
if (oldVersion <= 1) migrateTo2(realm)
|
if (oldVersion <= 1) migrateTo2(realm)
|
||||||
if (oldVersion <= 2) migrateTo3(realm)
|
if (oldVersion <= 2) migrateTo3(realm)
|
||||||
|
if (oldVersion <= 3) migrateTo4(realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
private fun migrateTo1(realm: DynamicRealm) {
|
||||||
|
@ -81,4 +84,34 @@ internal object AuthRealmMigration : RealmMigration {
|
||||||
}
|
}
|
||||||
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun migrateTo4(realm: DynamicRealm) {
|
||||||
|
Timber.d("Step 3 -> 4")
|
||||||
|
Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value")
|
||||||
|
|
||||||
|
val adapter = MoshiProvider.providesMoshi()
|
||||||
|
.adapter(HomeServerConnectionConfig::class.java)
|
||||||
|
|
||||||
|
realm.schema.get("SessionParamsEntity")
|
||||||
|
?.transform {
|
||||||
|
val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON)
|
||||||
|
|
||||||
|
val homeserverConnectionConfig = adapter
|
||||||
|
.fromJson(homeserverConnectionConfigJson)
|
||||||
|
|
||||||
|
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
|
||||||
|
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
|
||||||
|
// "https://matrix-client.matrix.org". So fix that here
|
||||||
|
val alteredHomeserverConnectionConfig =
|
||||||
|
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
|
||||||
|
homeserverConnectionConfig.copy(
|
||||||
|
homeServerUri = Uri.parse("https://matrix.org"),
|
||||||
|
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
homeserverConnectionConfig
|
||||||
|
}
|
||||||
|
it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ internal class DefaultDirectLoginTask @Inject constructor(
|
||||||
|
|
||||||
override suspend fun execute(params: DirectLoginTask.Params): Session {
|
override suspend fun execute(params: DirectLoginTask.Params): Session {
|
||||||
val client = buildClient(params.homeServerConnectionConfig)
|
val client = buildClient(params.homeServerConnectionConfig)
|
||||||
val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString()
|
val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString()
|
||||||
|
|
||||||
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
||||||
.create(AuthAPI::class.java)
|
.create(AuthAPI::class.java)
|
||||||
|
|
|
@ -314,6 +314,12 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
|
cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
|
||||||
// Open the store
|
// Open the store
|
||||||
cryptoStore.open()
|
cryptoStore.open()
|
||||||
|
|
||||||
|
if (!cryptoStore.areDeviceKeysUploaded()) {
|
||||||
|
// Schedule upload of OTK
|
||||||
|
oneTimeKeysUploader.updateOneTimeKeyCount(0)
|
||||||
|
}
|
||||||
|
|
||||||
// this can throw if no network
|
// this can throw if no network
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
uploadDeviceKeys()
|
uploadDeviceKeys()
|
||||||
|
@ -905,7 +911,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
* Upload my user's device keys.
|
* Upload my user's device keys.
|
||||||
*/
|
*/
|
||||||
private suspend fun uploadDeviceKeys() {
|
private suspend fun uploadDeviceKeys() {
|
||||||
if (cryptoStore.getDeviceKeysUploaded()) {
|
if (cryptoStore.areDeviceKeysUploaded()) {
|
||||||
Timber.d("Keys already uploaded, nothing to do")
|
Timber.d("Keys already uploaded, nothing to do")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||||
|
@ -336,7 +337,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||||
downloadKeysForUsersTask.execute(params)
|
downloadKeysForUsersTask.execute(params)
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
|
Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
|
||||||
onKeysDownloadFailed(filteredUsers)
|
if (throwable is CancellationException) {
|
||||||
|
// the crypto module is getting closed, so we cannot access the DB anymore
|
||||||
|
Timber.w("The crypto module is closed, ignoring this error")
|
||||||
|
} else {
|
||||||
|
onKeysDownloadFailed(filteredUsers)
|
||||||
|
}
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.internal.crypto.model.MXKey
|
import org.matrix.android.sdk.internal.crypto.model.MXKey
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
|
||||||
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
|
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
|
||||||
|
@ -77,6 +78,10 @@ internal class OneTimeKeysUploader @Inject constructor(
|
||||||
// discard the oldest private keys first. This will eventually clean
|
// discard the oldest private keys first. This will eventually clean
|
||||||
// out stale private keys that won't receive a message.
|
// out stale private keys that won't receive a message.
|
||||||
val keyLimit = floor(maxOneTimeKeys / 2.0).toInt()
|
val keyLimit = floor(maxOneTimeKeys / 2.0).toInt()
|
||||||
|
if (oneTimeKeyCount == null) {
|
||||||
|
// Ask the server how many otk he has
|
||||||
|
oneTimeKeyCount = fetchOtkCount()
|
||||||
|
}
|
||||||
val oneTimeKeyCountFromSync = oneTimeKeyCount
|
val oneTimeKeyCountFromSync = oneTimeKeyCount
|
||||||
if (oneTimeKeyCountFromSync != null) {
|
if (oneTimeKeyCountFromSync != null) {
|
||||||
// We need to keep a pool of one time public keys on the server so that
|
// We need to keep a pool of one time public keys on the server so that
|
||||||
|
@ -90,17 +95,22 @@ internal class OneTimeKeysUploader @Inject constructor(
|
||||||
// private keys clogging up our local storage.
|
// private keys clogging up our local storage.
|
||||||
// So we need some kind of engineering compromise to balance all of
|
// So we need some kind of engineering compromise to balance all of
|
||||||
// these factors.
|
// these factors.
|
||||||
try {
|
tryOrNull("Unable to upload OTK") {
|
||||||
val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit)
|
val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit)
|
||||||
Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent")
|
Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent")
|
||||||
} finally {
|
|
||||||
oneTimeKeyCheckInProgress = false
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.w("maybeUploadOneTimeKeys: waiting to know the number of OTK from the sync")
|
Timber.w("maybeUploadOneTimeKeys: waiting to know the number of OTK from the sync")
|
||||||
oneTimeKeyCheckInProgress = false
|
|
||||||
lastOneTimeKeyCheck = 0
|
lastOneTimeKeyCheck = 0
|
||||||
}
|
}
|
||||||
|
oneTimeKeyCheckInProgress = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchOtkCount(): Int? {
|
||||||
|
return tryOrNull("Unable to get OTK count") {
|
||||||
|
val result = uploadKeysTask.execute(UploadKeysTask.Params(null, null))
|
||||||
|
result.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -56,7 +56,7 @@ data class MXDeviceInfo(
|
||||||
val signatures: Map<String, Map<String, String>>? = null,
|
val signatures: Map<String, Map<String, String>>? = null,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Additional data from the home server.
|
* Additional data from the homeserver.
|
||||||
*/
|
*/
|
||||||
@Json(name = "unsigned")
|
@Json(name = "unsigned")
|
||||||
val unsigned: JsonDict? = null,
|
val unsigned: JsonDict? = null,
|
||||||
|
|
|
@ -475,7 +475,7 @@ internal interface IMXCryptoStore {
|
||||||
fun getGossipingEvents(): List<Event>
|
fun getGossipingEvents(): List<Event>
|
||||||
|
|
||||||
fun setDeviceKeysUploaded(uploaded: Boolean)
|
fun setDeviceKeysUploaded(uploaded: Boolean)
|
||||||
fun getDeviceKeysUploaded(): Boolean
|
fun areDeviceKeysUploaded(): Boolean
|
||||||
fun tidyUpDataBase()
|
fun tidyUpDataBase()
|
||||||
fun logDbUsageInfo()
|
fun logDbUsageInfo()
|
||||||
}
|
}
|
||||||
|
|
|
@ -937,7 +937,7 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeviceKeysUploaded(): Boolean {
|
override fun areDeviceKeysUploaded(): Boolean {
|
||||||
return doWithRealm(realmConfiguration) {
|
return doWithRealm(realmConfiguration) {
|
||||||
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
|
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
|
@ -97,7 +97,7 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor(
|
||||||
|
|
||||||
Timber.v("## CrossSigning - sskPublicKey:$sskPublicKey")
|
Timber.v("## CrossSigning - sskPublicKey:$sskPublicKey")
|
||||||
|
|
||||||
// Sign userSigningKey with master
|
// Sign selfSigningKey with master
|
||||||
val signedSSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING)
|
val signedSSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING)
|
||||||
.key(sskPublicKey)
|
.key(sskPublicKey)
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -68,7 +68,7 @@ internal class VerificationTransportToDevice(
|
||||||
contentMap.setObject(otherUserId, it, keyReq)
|
contentMap.setObject(otherUserId, it, keyReq)
|
||||||
}
|
}
|
||||||
sendToDeviceTask
|
sendToDeviceTask
|
||||||
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap, localId)) {
|
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
Timber.v("## verification [$tx.transactionId] send toDevice request success")
|
Timber.v("## verification [$tx.transactionId] send toDevice request success")
|
||||||
|
@ -124,7 +124,7 @@ internal class VerificationTransportToDevice(
|
||||||
contentMap.setObject(tx.otherUserId, tx.otherDeviceId, toSendToDeviceObject)
|
contentMap.setObject(tx.otherUserId, tx.otherDeviceId, toSendToDeviceObject)
|
||||||
|
|
||||||
sendToDeviceTask
|
sendToDeviceTask
|
||||||
.configureWith(SendToDeviceTask.Params(type, contentMap, tx.transactionId)) {
|
.configureWith(SendToDeviceTask.Params(type, contentMap)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
|
Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
|
||||||
|
@ -155,7 +155,7 @@ internal class VerificationTransportToDevice(
|
||||||
val contentMap = MXUsersDevicesMap<Any>()
|
val contentMap = MXUsersDevicesMap<Any>()
|
||||||
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
||||||
sendToDeviceTask
|
sendToDeviceTask
|
||||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap, transactionId)) {
|
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
onDone?.invoke()
|
onDone?.invoke()
|
||||||
|
@ -176,7 +176,7 @@ internal class VerificationTransportToDevice(
|
||||||
val contentMap = MXUsersDevicesMap<Any>()
|
val contentMap = MXUsersDevicesMap<Any>()
|
||||||
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
|
||||||
sendToDeviceTask
|
sendToDeviceTask
|
||||||
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) {
|
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
|
||||||
|
|
|
@ -46,7 +46,7 @@ import timber.log.Timber
|
||||||
|
|
||||||
internal object RealmSessionStoreMigration : RealmMigration {
|
internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
|
|
||||||
const val SESSION_STORE_SCHEMA_VERSION = 15L
|
const val SESSION_STORE_SCHEMA_VERSION = 16L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
|
Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
|
||||||
|
@ -66,6 +66,7 @@ internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
if (oldVersion <= 12) migrateTo13(realm)
|
if (oldVersion <= 12) migrateTo13(realm)
|
||||||
if (oldVersion <= 13) migrateTo14(realm)
|
if (oldVersion <= 13) migrateTo14(realm)
|
||||||
if (oldVersion <= 14) migrateTo15(realm)
|
if (oldVersion <= 14) migrateTo15(realm)
|
||||||
|
if (oldVersion <= 15) migrateTo16(realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
private fun migrateTo1(realm: DynamicRealm) {
|
||||||
|
@ -308,6 +309,7 @@ internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateTo15(realm: DynamicRealm) {
|
private fun migrateTo15(realm: DynamicRealm) {
|
||||||
|
Timber.d("Step 14 -> 15")
|
||||||
// fix issue with flattenParentIds on DM that kept growing with duplicate
|
// fix issue with flattenParentIds on DM that kept growing with duplicate
|
||||||
// so we reset it, will be updated next sync
|
// so we reset it, will be updated next sync
|
||||||
realm.where("RoomSummaryEntity")
|
realm.where("RoomSummaryEntity")
|
||||||
|
@ -318,4 +320,14 @@ internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null)
|
it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun migrateTo16(realm: DynamicRealm) {
|
||||||
|
Timber.d("Step 15 -> 16")
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSIONS_JSON, String::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
// Schedule a refresh of the capabilities
|
||||||
|
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,15 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.database.mapper
|
package org.matrix.android.sdk.internal.database.mapper
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionCapabilities
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionInfo
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.session.homeserver.RoomVersions
|
||||||
|
import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HomeServerCapabilitiesEntity -> HomeSeverCapabilities
|
* HomeServerCapabilitiesEntity -> HomeSeverCapabilities
|
||||||
|
@ -29,7 +36,30 @@ internal object HomeServerCapabilitiesMapper {
|
||||||
canChangePassword = entity.canChangePassword,
|
canChangePassword = entity.canChangePassword,
|
||||||
maxUploadFileSize = entity.maxUploadFileSize,
|
maxUploadFileSize = entity.maxUploadFileSize,
|
||||||
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
||||||
defaultIdentityServerUrl = entity.defaultIdentityServerUrl
|
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
|
||||||
|
roomVersions = mapRoomVersion(entity.roomVersionsJson)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun mapRoomVersion(roomVersionsJson: String?): RoomVersionCapabilities? {
|
||||||
|
roomVersionsJson ?: return null
|
||||||
|
|
||||||
|
return tryOrNull {
|
||||||
|
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(roomVersionsJson)?.let {
|
||||||
|
RoomVersionCapabilities(
|
||||||
|
defaultRoomVersion = it.default ?: DefaultRoomVersionService.DEFAULT_ROOM_VERSION,
|
||||||
|
supportedVersion = it.available.entries.map { entry ->
|
||||||
|
RoomVersionInfo(
|
||||||
|
version = entry.key,
|
||||||
|
status = if (entry.value == "stable") {
|
||||||
|
RoomVersionStatus.STABLE
|
||||||
|
} else {
|
||||||
|
RoomVersionStatus.UNSTABLE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
|
||||||
internal open class HomeServerCapabilitiesEntity(
|
internal open class HomeServerCapabilitiesEntity(
|
||||||
var canChangePassword: Boolean = true,
|
var canChangePassword: Boolean = true,
|
||||||
|
var roomVersionsJson: String? = null,
|
||||||
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
|
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
|
||||||
var lastVersionIdentityServerSupported: Boolean = false,
|
var lastVersionIdentityServerSupported: Boolean = false,
|
||||||
var defaultIdentityServerUrl: String? = null,
|
var defaultIdentityServerUrl: String? = null,
|
||||||
|
|
|
@ -20,7 +20,7 @@ import io.realm.RealmObject
|
||||||
import io.realm.annotations.Index
|
import io.realm.annotations.Index
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clients can store custom config data for their account on their HomeServer.
|
* Clients can store custom config data for their account on their homeserver.
|
||||||
* This account data will be synced between different devices and can persist across installations on a particular device.
|
* This account data will be synced between different devices and can persist across installations on a particular device.
|
||||||
* Users may only view the account data for their own account.
|
* Users may only view the account data for their own account.
|
||||||
* The account_data may be either global or scoped to a particular rooms.
|
* The account_data may be either global or scoped to a particular rooms.
|
||||||
|
|
|
@ -37,7 +37,8 @@ internal abstract class FederationModule {
|
||||||
fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
|
fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
|
||||||
sessionParams: SessionParams,
|
sessionParams: SessionParams,
|
||||||
retrofitFactory: RetrofitFactory): FederationAPI {
|
retrofitFactory: RetrofitFactory): FederationAPI {
|
||||||
return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrl).create(FederationAPI::class.java)
|
return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrlBase)
|
||||||
|
.create(FederationAPI::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class Credentials {
|
||||||
|
|
||||||
public String deviceId;
|
public String deviceId;
|
||||||
|
|
||||||
// Optional data that may contain info to override home server and/or identity server
|
// Optional data that may contain info to override homeserver and/or identity server
|
||||||
public WellKnown wellKnown;
|
public WellKnown wellKnown;
|
||||||
|
|
||||||
public JSONObject toJson() throws JSONException {
|
public JSONObject toJson() throws JSONException {
|
||||||
|
|
|
@ -44,7 +44,7 @@ import timber.log.Timber;
|
||||||
*/
|
*/
|
||||||
public class HomeServerConnectionConfig {
|
public class HomeServerConnectionConfig {
|
||||||
|
|
||||||
// the home server URI
|
// the homeserver URI
|
||||||
private Uri mHomeServerUri;
|
private Uri mHomeServerUri;
|
||||||
// the jitsi server URI. Can be null
|
// the jitsi server URI. Can be null
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -82,7 +82,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the home server URI.
|
* Update the homeserver URI.
|
||||||
*
|
*
|
||||||
* @param uri the new HS uri
|
* @param uri the new HS uri
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +91,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the home server uri
|
* @return the homeserver uri
|
||||||
*/
|
*/
|
||||||
public Uri getHomeserverUri() {
|
public Uri getHomeserverUri() {
|
||||||
return mHomeServerUri;
|
return mHomeServerUri;
|
||||||
|
@ -145,7 +145,7 @@ public class HomeServerConnectionConfig {
|
||||||
public void setCredentials(Credentials credentials) {
|
public void setCredentials(Credentials credentials) {
|
||||||
mCredentials = credentials;
|
mCredentials = credentials;
|
||||||
|
|
||||||
// Override home server url and/or identity server url if provided
|
// Override homeserver url and/or identity server url if provided
|
||||||
if (credentials.wellKnown != null) {
|
if (credentials.wellKnown != null) {
|
||||||
if (credentials.wellKnown.homeServer != null) {
|
if (credentials.wellKnown.homeServer != null) {
|
||||||
String homeServerUrl = credentials.wellKnown.homeServer.baseURL;
|
String homeServerUrl = credentials.wellKnown.homeServer.baseURL;
|
||||||
|
@ -200,7 +200,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS versions accepted for TLS connections with the home server.
|
* TLS versions accepted for TLS connections with the homeserver.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<TlsVersion> getAcceptedTlsVersions() {
|
public List<TlsVersion> getAcceptedTlsVersions() {
|
||||||
|
@ -208,7 +208,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS cipher suites accepted for TLS connections with the home server.
|
* TLS cipher suites accepted for TLS connections with the homeserver.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<CipherSuite> getAcceptedTlsCipherSuites() {
|
public List<CipherSuite> getAcceptedTlsCipherSuites() {
|
||||||
|
@ -426,7 +426,7 @@ public class HomeServerConnectionConfig {
|
||||||
*/
|
*/
|
||||||
public Builder withHomeServerUri(final Uri homeServerUri) {
|
public Builder withHomeServerUri(final Uri homeServerUri) {
|
||||||
if (homeServerUri == null || (!"http".equals(homeServerUri.getScheme()) && !"https".equals(homeServerUri.getScheme()))) {
|
if (homeServerUri == null || (!"http".equals(homeServerUri.getScheme()) && !"https".equals(homeServerUri.getScheme()))) {
|
||||||
throw new RuntimeException("Invalid home server URI: " + homeServerUri);
|
throw new RuntimeException("Invalid homeserver URI: " + homeServerUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove trailing /
|
// remove trailing /
|
||||||
|
@ -435,7 +435,7 @@ public class HomeServerConnectionConfig {
|
||||||
String url = homeServerUri.toString();
|
String url = homeServerUri.toString();
|
||||||
mHomeServerConnectionConfig.mHomeServerUri = Uri.parse(url.substring(0, url.length() - 1));
|
mHomeServerConnectionConfig.mHomeServerUri = Uri.parse(url.substring(0, url.length() - 1));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Invalid home server URI: " + homeServerUri);
|
throw new RuntimeException("Invalid homeserver URI: " + homeServerUri);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mHomeServerConnectionConfig.mHomeServerUri = homeServerUri;
|
mHomeServerConnectionConfig.mHomeServerUri = homeServerUri;
|
||||||
|
@ -549,7 +549,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an accepted TLS version for TLS connections with the home server.
|
* Add an accepted TLS version for TLS connections with the homeserver.
|
||||||
*
|
*
|
||||||
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
|
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
|
||||||
* @return this builder
|
* @return this builder
|
||||||
|
@ -577,7 +577,7 @@ public class HomeServerConnectionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a TLS cipher suite to the list of accepted TLS connections with the home server.
|
* Add a TLS cipher suite to the list of accepted TLS connections with the homeserver.
|
||||||
*
|
*
|
||||||
* @param tlsCipherSuite the tls cipher suite to add.
|
* @param tlsCipherSuite the tls cipher suite to add.
|
||||||
* @return this builder
|
* @return this builder
|
||||||
|
@ -666,7 +666,7 @@ public class HomeServerConnectionConfig {
|
||||||
public HomeServerConnectionConfig build() {
|
public HomeServerConnectionConfig build() {
|
||||||
// Check mandatory parameters
|
// Check mandatory parameters
|
||||||
if (mHomeServerConnectionConfig.mHomeServerUri == null) {
|
if (mHomeServerConnectionConfig.mHomeServerUri == null) {
|
||||||
throw new RuntimeException("Home server URI not set");
|
throw new RuntimeException("Homeserver URI not set");
|
||||||
}
|
}
|
||||||
|
|
||||||
return mHomeServerConnectionConfig;
|
return mHomeServerConnectionConfig;
|
||||||
|
|
|
@ -38,7 +38,7 @@ import timber.log.Timber;
|
||||||
public class LoginStorage {
|
public class LoginStorage {
|
||||||
private static final String PREFS_LOGIN = "Vector.LoginStorage";
|
private static final String PREFS_LOGIN = "Vector.LoginStorage";
|
||||||
|
|
||||||
// multi accounts + home server config
|
// multi accounts + homeserver config
|
||||||
private static final String PREFS_KEY_CONNECTION_CONFIGS = "PREFS_KEY_CONNECTION_CONFIGS";
|
private static final String PREFS_KEY_CONNECTION_CONFIGS = "PREFS_KEY_CONNECTION_CONFIGS";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
@ -49,7 +49,7 @@ public class LoginStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of home server configurations.
|
* @return the list of homeserver configurations.
|
||||||
*/
|
*/
|
||||||
public List<HomeServerConnectionConfig> getCredentialsList() {
|
public List<HomeServerConnectionConfig> getCredentialsList() {
|
||||||
SharedPreferences prefs = mContext.getSharedPreferences(PREFS_LOGIN, Context.MODE_PRIVATE);
|
SharedPreferences prefs = mContext.getSharedPreferences(PREFS_LOGIN, Context.MODE_PRIVATE);
|
||||||
|
@ -85,7 +85,7 @@ public class LoginStorage {
|
||||||
/**
|
/**
|
||||||
* Add a credentials to the credentials list
|
* Add a credentials to the credentials list
|
||||||
*
|
*
|
||||||
* @param config the home server config to add.
|
* @param config the homeserver config to add.
|
||||||
*/
|
*/
|
||||||
public void addCredentials(HomeServerConnectionConfig config) {
|
public void addCredentials(HomeServerConnectionConfig config) {
|
||||||
if (null != config && config.getCredentials() != null) {
|
if (null != config && config.getCredentials() != null) {
|
||||||
|
|
|
@ -253,7 +253,7 @@ internal object CertUtil {
|
||||||
val list = ArrayList<ConnectionSpec>()
|
val list = ArrayList<ConnectionSpec>()
|
||||||
list.add(builder.build())
|
list.add(builder.build())
|
||||||
// TODO: we should display a warning if user enter an http url
|
// TODO: we should display a warning if user enter an http url
|
||||||
if (hsConfig.allowHttpExtension || hsConfig.homeServerUri.toString().startsWith("http://")) {
|
if (hsConfig.allowHttpExtension || hsConfig.homeServerUriBase.toString().startsWith("http://")) {
|
||||||
list.add(ConnectionSpec.CLEARTEXT)
|
list.add(ConnectionSpec.CLEARTEXT)
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
|
|
|
@ -29,10 +29,9 @@ internal class DefaultRawService @Inject constructor(
|
||||||
return getUrlTask.execute(GetUrlTask.Params(url, cacheStrategy))
|
return getUrlTask.execute(GetUrlTask.Params(url, cacheStrategy))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getWellknown(userId: String): String {
|
override suspend fun getWellknown(domain: String): String {
|
||||||
val homeServerDomain = userId.substringAfter(":")
|
|
||||||
return getUrl(
|
return getUrl(
|
||||||
"https://$homeServerDomain/.well-known/matrix/client",
|
"https://$domain/.well-known/matrix/client",
|
||||||
CacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false)
|
CacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory
|
||||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress
|
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress
|
||||||
import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER
|
import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER
|
||||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||||
|
import org.matrix.android.sdk.internal.util.file.AtomicFileCreator
|
||||||
import org.matrix.android.sdk.internal.util.md5
|
import org.matrix.android.sdk.internal.util.md5
|
||||||
import org.matrix.android.sdk.internal.util.writeToFile
|
import org.matrix.android.sdk.internal.util.writeToFile
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -96,6 +97,9 @@ internal class DefaultFileService @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var atomicFileDownload: AtomicFileCreator? = null
|
||||||
|
var atomicFileDecrypt: AtomicFileCreator? = null
|
||||||
|
|
||||||
if (existingDownload != null) {
|
if (existingDownload != null) {
|
||||||
// FIXME If the first downloader cancels then we'll unfortunately be cancelled too.
|
// FIXME If the first downloader cancels then we'll unfortunately be cancelled too.
|
||||||
return existingDownload.await()
|
return existingDownload.await()
|
||||||
|
@ -131,8 +135,11 @@ internal class DefaultFileService @Inject constructor(
|
||||||
Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}")
|
Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}")
|
||||||
|
|
||||||
// Write the file to cache (encrypted version if the file is encrypted)
|
// Write the file to cache (encrypted version if the file is encrypted)
|
||||||
writeToFile(source.inputStream(), cachedFiles.file)
|
// Write to a part file first, so if we abort before done, we don't have a broken cached file
|
||||||
|
val atomicFileCreator = AtomicFileCreator(cachedFiles.file).also { atomicFileDownload = it }
|
||||||
|
writeToFile(source.inputStream(), atomicFileCreator.partFile)
|
||||||
response.close()
|
response.close()
|
||||||
|
atomicFileCreator.commit()
|
||||||
} else {
|
} else {
|
||||||
Timber.v("## FileService: cache hit for $url")
|
Timber.v("## FileService: cache hit for $url")
|
||||||
}
|
}
|
||||||
|
@ -145,8 +152,10 @@ internal class DefaultFileService @Inject constructor(
|
||||||
Timber.v("## FileService: decrypt file")
|
Timber.v("## FileService: decrypt file")
|
||||||
// Ensure the parent folder exists
|
// Ensure the parent folder exists
|
||||||
cachedFiles.decryptedFile.parentFile?.mkdirs()
|
cachedFiles.decryptedFile.parentFile?.mkdirs()
|
||||||
|
// Write to a part file first, so if we abort before done, we don't have a broken cached file
|
||||||
|
val atomicFileCreator = AtomicFileCreator(cachedFiles.decryptedFile).also { atomicFileDecrypt = it }
|
||||||
val decryptSuccess = cachedFiles.file.inputStream().use { inputStream ->
|
val decryptSuccess = cachedFiles.file.inputStream().use { inputStream ->
|
||||||
cachedFiles.decryptedFile.outputStream().buffered().use { outputStream ->
|
atomicFileCreator.partFile.outputStream().buffered().use { outputStream ->
|
||||||
MXEncryptedAttachments.decryptAttachment(
|
MXEncryptedAttachments.decryptAttachment(
|
||||||
inputStream,
|
inputStream,
|
||||||
elementToDecrypt,
|
elementToDecrypt,
|
||||||
|
@ -154,6 +163,7 @@ internal class DefaultFileService @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
atomicFileCreator.commit()
|
||||||
if (!decryptSuccess) {
|
if (!decryptSuccess) {
|
||||||
throw IllegalStateException("Decryption error")
|
throw IllegalStateException("Decryption error")
|
||||||
}
|
}
|
||||||
|
@ -174,6 +184,11 @@ internal class DefaultFileService @Inject constructor(
|
||||||
}
|
}
|
||||||
toNotify?.completeWith(result)
|
toNotify?.completeWith(result)
|
||||||
|
|
||||||
|
result.onFailure {
|
||||||
|
atomicFileDownload?.cancel()
|
||||||
|
atomicFileDecrypt?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
return result.getOrThrow()
|
return result.getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,7 +313,7 @@ internal class DefaultSession @Inject constructor(
|
||||||
|
|
||||||
override fun getUiaSsoFallbackUrl(authenticationSessionId: String): String {
|
override fun getUiaSsoFallbackUrl(authenticationSessionId: String): String {
|
||||||
val hsBas = sessionParams.homeServerConnectionConfig
|
val hsBas = sessionParams.homeServerConnectionConfig
|
||||||
.homeServerUri
|
.homeServerUriBase
|
||||||
.toString()
|
.toString()
|
||||||
.trim { it == '/' }
|
.trim { it == '/' }
|
||||||
return buildString {
|
return buildString {
|
||||||
|
|
|
@ -261,7 +261,7 @@ internal abstract class SessionModule {
|
||||||
sessionParams: SessionParams,
|
sessionParams: SessionParams,
|
||||||
retrofitFactory: RetrofitFactory): Retrofit {
|
retrofitFactory: RetrofitFactory): Retrofit {
|
||||||
return retrofitFactory
|
return retrofitFactory
|
||||||
.create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString())
|
.create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|
|
@ -20,11 +20,14 @@ import io.realm.Realm
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.internal.database.model.EventInsertType
|
import org.matrix.android.sdk.internal.database.model.EventInsertType
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("CallEventProcessor", LoggerTag.VOIP)
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler)
|
internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler)
|
||||||
: EventInsertLiveProcessor {
|
: EventInsertLiveProcessor {
|
||||||
|
@ -71,14 +74,8 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) {
|
private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) {
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
event.roomId ?: return Unit.also {
|
event.roomId ?: return Unit.also {
|
||||||
Timber.w("Event with no room id ${event.eventId}")
|
Timber.tag(loggerTag.value).w("Event with no room id ${event.eventId}")
|
||||||
}
|
|
||||||
val age = now - (event.ageLocalTs ?: now)
|
|
||||||
if (age > 40_000) {
|
|
||||||
// Too old to ring?
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
callSignalingHandler.onCallEvent(event)
|
callSignalingHandler.onCallEvent(event)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.call
|
package org.matrix.android.sdk.internal.session.call
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.call.CallListener
|
import org.matrix.android.sdk.api.session.call.CallListener
|
||||||
import org.matrix.android.sdk.api.session.call.CallState
|
import org.matrix.android.sdk.api.session.call.CallState
|
||||||
import org.matrix.android.sdk.api.session.call.MxCall
|
import org.matrix.android.sdk.api.session.call.MxCall
|
||||||
|
@ -36,6 +37,9 @@ import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP)
|
||||||
|
private const val MAX_AGE_TO_RING = 40_000
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler,
|
internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler,
|
||||||
private val mxCallFactory: MxCallFactory,
|
private val mxCallFactory: MxCallFactory,
|
||||||
|
@ -111,12 +115,12 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (call.isOutgoing) {
|
if (call.isOutgoing) {
|
||||||
Timber.v("Got selectAnswer for an outbound call: ignoring")
|
Timber.tag(loggerTag.value).v("Got selectAnswer for an outbound call: ignoring")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val selectedPartyId = content.selectedPartyId
|
val selectedPartyId = content.selectedPartyId
|
||||||
if (selectedPartyId == null) {
|
if (selectedPartyId == null) {
|
||||||
Timber.w("Got nonsensical select_answer with null selected_party_id: ignoring")
|
Timber.tag(loggerTag.value).w("Got nonsensical select_answer with null selected_party_id: ignoring")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
callListenersDispatcher.onCallSelectAnswerReceived(content)
|
callListenersDispatcher.onCallSelectAnswerReceived(content)
|
||||||
|
@ -130,7 +134,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
||||||
Timber.v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
Timber.tag(loggerTag.value).v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
callListenersDispatcher.onCallIceCandidateReceived(call, content)
|
callListenersDispatcher.onCallIceCandidateReceived(call, content)
|
||||||
|
@ -163,10 +167,10 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
// party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen
|
// party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen
|
||||||
// a partner yet but we're treating the hangup as a reject as per VoIP v0)
|
// a partner yet but we're treating the hangup as a reject as per VoIP v0)
|
||||||
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
if (call.opponentPartyId != null && !call.partyIdsMatches(content)) {
|
||||||
Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
Timber.tag(loggerTag.value).v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (call.state != CallState.Terminated) {
|
if (call.state !is CallState.Ended) {
|
||||||
activeCallHandler.removeCall(content.callId)
|
activeCallHandler.removeCall(content.callId)
|
||||||
callListenersDispatcher.onCallHangupReceived(content)
|
callListenersDispatcher.onCallHangupReceived(content)
|
||||||
}
|
}
|
||||||
|
@ -180,12 +184,18 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
if (event.roomId == null || event.senderId == null) {
|
if (event.roomId == null || event.senderId == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val age = now - (event.ageLocalTs ?: now)
|
||||||
|
if (age > MAX_AGE_TO_RING) {
|
||||||
|
Timber.tag(loggerTag.value).w("Call invite is too old to ring.")
|
||||||
|
return
|
||||||
|
}
|
||||||
val content = event.getClearContent().toModel<CallInviteContent>() ?: return
|
val content = event.getClearContent().toModel<CallInviteContent>() ?: return
|
||||||
|
|
||||||
content.callId ?: return
|
content.callId ?: return
|
||||||
if (invitedCallIds.contains(content.callId)) {
|
if (invitedCallIds.contains(content.callId)) {
|
||||||
// Call is already known, maybe due to fast lane. Ignore
|
// Call is already known, maybe due to fast lane. Ignore
|
||||||
Timber.d("Ignoring already known call invite")
|
Timber.tag(loggerTag.value).d("Ignoring already known call invite")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val incomingCall = mxCallFactory.createIncomingCall(
|
val incomingCall = mxCallFactory.createIncomingCall(
|
||||||
|
@ -214,7 +224,8 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
callListenersDispatcher.onCallManagedByOtherSession(content.callId)
|
callListenersDispatcher.onCallManagedByOtherSession(content.callId)
|
||||||
} else {
|
} else {
|
||||||
if (call.opponentPartyId != null) {
|
if (call.opponentPartyId != null) {
|
||||||
Timber.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}")
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities)
|
mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities)
|
||||||
|
@ -231,7 +242,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
||||||
activeCallHandler.getCallWithId(it)
|
activeCallHandler.getCallWithId(it)
|
||||||
}
|
}
|
||||||
if (currentCall == null) {
|
if (currentCall == null) {
|
||||||
Timber.v("Call with id $callId is null")
|
Timber.tag(loggerTag.value).v("Call with id $callId is null")
|
||||||
}
|
}
|
||||||
return currentCall
|
return currentCall
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import org.matrix.android.sdk.api.session.call.CallSignalingService
|
||||||
import org.matrix.android.sdk.api.session.call.MxCall
|
import org.matrix.android.sdk.api.session.call.MxCall
|
||||||
import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
|
@ -51,7 +50,6 @@ internal class DefaultCallSignalingService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCallWithId(callId: String): MxCall? {
|
override fun getCallWithId(callId: String): MxCall? {
|
||||||
Timber.v("## VOIP getCallWithId $callId all calls ${activeCallHandler.getActiveCallsLiveData().value?.map { it.callId }}")
|
|
||||||
return activeCallHandler.getCallWithId(callId)
|
return activeCallHandler.getCallWithId(callId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.matrix.android.sdk.internal.session.call.model
|
package org.matrix.android.sdk.internal.session.call.model
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.call.CallIdGenerator
|
import org.matrix.android.sdk.api.session.call.CallIdGenerator
|
||||||
import org.matrix.android.sdk.api.session.call.CallState
|
import org.matrix.android.sdk.api.session.call.CallState
|
||||||
import org.matrix.android.sdk.api.session.call.MxCall
|
import org.matrix.android.sdk.api.session.call.MxCall
|
||||||
|
@ -38,6 +39,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent
|
import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent
|
import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
|
import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService
|
||||||
|
@ -47,6 +49,8 @@ import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProces
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("MxCallImpl", LoggerTag.VOIP)
|
||||||
|
|
||||||
internal class MxCallImpl(
|
internal class MxCallImpl(
|
||||||
override val callId: String,
|
override val callId: String,
|
||||||
override val isOutgoing: Boolean,
|
override val isOutgoing: Boolean,
|
||||||
|
@ -93,7 +97,7 @@ internal class MxCallImpl(
|
||||||
try {
|
try {
|
||||||
it.onStateUpdate(this)
|
it.onStateUpdate(this)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}")
|
Timber.tag(loggerTag.value).d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +113,7 @@ internal class MxCallImpl(
|
||||||
|
|
||||||
override fun offerSdp(sdpString: String) {
|
override fun offerSdp(sdpString: String) {
|
||||||
if (!isOutgoing) return
|
if (!isOutgoing) return
|
||||||
Timber.v("## VOIP offerSdp $callId")
|
Timber.tag(loggerTag.value).v("offerSdp $callId")
|
||||||
state = CallState.Dialing
|
state = CallState.Dialing
|
||||||
CallInviteContent(
|
CallInviteContent(
|
||||||
callId = callId,
|
callId = callId,
|
||||||
|
@ -124,7 +128,7 @@ internal class MxCallImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendLocalCallCandidates(candidates: List<CallCandidate>) {
|
override fun sendLocalCallCandidates(candidates: List<CallCandidate>) {
|
||||||
Timber.v("Send local call canditates $callId: $candidates")
|
Timber.tag(loggerTag.value).v("Send local call canditates $callId: $candidates")
|
||||||
CallCandidatesContent(
|
CallCandidatesContent(
|
||||||
callId = callId,
|
callId = callId,
|
||||||
partyId = ourPartyId,
|
partyId = ourPartyId,
|
||||||
|
@ -141,11 +145,11 @@ internal class MxCallImpl(
|
||||||
|
|
||||||
override fun reject() {
|
override fun reject() {
|
||||||
if (opponentVersion < 1) {
|
if (opponentVersion < 1) {
|
||||||
Timber.v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject")
|
Timber.tag(loggerTag.value).v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject")
|
||||||
hangUp()
|
hangUp(EndCallReason.USER_HANGUP)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Timber.v("## VOIP reject $callId")
|
Timber.tag(loggerTag.value).v("reject $callId")
|
||||||
CallRejectContent(
|
CallRejectContent(
|
||||||
callId = callId,
|
callId = callId,
|
||||||
partyId = ourPartyId,
|
partyId = ourPartyId,
|
||||||
|
@ -153,24 +157,24 @@ internal class MxCallImpl(
|
||||||
)
|
)
|
||||||
.let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) }
|
.let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) }
|
||||||
.also { eventSenderProcessor.postEvent(it) }
|
.also { eventSenderProcessor.postEvent(it) }
|
||||||
state = CallState.Terminated
|
state = CallState.Ended(reason = EndCallReason.USER_HANGUP)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hangUp(reason: CallHangupContent.Reason?) {
|
override fun hangUp(reason: EndCallReason?) {
|
||||||
Timber.v("## VOIP hangup $callId")
|
Timber.tag(loggerTag.value).v("hangup $callId")
|
||||||
CallHangupContent(
|
CallHangupContent(
|
||||||
callId = callId,
|
callId = callId,
|
||||||
partyId = ourPartyId,
|
partyId = ourPartyId,
|
||||||
reason = reason ?: CallHangupContent.Reason.USER_HANGUP,
|
reason = reason,
|
||||||
version = MxCall.VOIP_PROTO_VERSION.toString()
|
version = MxCall.VOIP_PROTO_VERSION.toString()
|
||||||
)
|
)
|
||||||
.let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) }
|
.let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) }
|
||||||
.also { eventSenderProcessor.postEvent(it) }
|
.also { eventSenderProcessor.postEvent(it) }
|
||||||
state = CallState.Terminated
|
state = CallState.Ended(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun accept(sdpString: String) {
|
override fun accept(sdpString: String) {
|
||||||
Timber.v("## VOIP accept $callId")
|
Timber.tag(loggerTag.value).v("accept $callId")
|
||||||
if (isOutgoing) return
|
if (isOutgoing) return
|
||||||
state = CallState.Answering
|
state = CallState.Answering
|
||||||
CallAnswerContent(
|
CallAnswerContent(
|
||||||
|
@ -185,7 +189,7 @@ internal class MxCallImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun negotiate(sdpString: String, type: SdpType) {
|
override fun negotiate(sdpString: String, type: SdpType) {
|
||||||
Timber.v("## VOIP negotiate $callId")
|
Timber.tag(loggerTag.value).v("negotiate $callId")
|
||||||
CallNegotiateContent(
|
CallNegotiateContent(
|
||||||
callId = callId,
|
callId = callId,
|
||||||
partyId = ourPartyId,
|
partyId = ourPartyId,
|
||||||
|
@ -198,7 +202,7 @@ internal class MxCallImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun selectAnswer() {
|
override fun selectAnswer() {
|
||||||
Timber.v("## VOIP select answer $callId")
|
Timber.tag(loggerTag.value).v("select answer $callId")
|
||||||
if (isOutgoing) return
|
if (isOutgoing) return
|
||||||
state = CallState.Answering
|
state = CallState.Answering
|
||||||
CallSelectAnswerContent(
|
CallSelectAnswerContent(
|
||||||
|
@ -219,7 +223,7 @@ internal class MxCallImpl(
|
||||||
val profileInfo = try {
|
val profileInfo = try {
|
||||||
getProfileInfoTask.execute(profileInfoParams)
|
getProfileInfoTask.execute(profileInfoParams)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.v("Fail fetching profile info of $targetUserId while transferring call")
|
Timber.tag(loggerTag.value).v("Fail fetching profile info of $targetUserId while transferring call")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
CallReplacesContent(
|
CallReplacesContent(
|
||||||
|
|
|
@ -26,7 +26,7 @@ private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
|
||||||
|
|
||||||
internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
|
internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
|
||||||
|
|
||||||
private val baseUrl = homeServerConnectionConfig.homeServerUri.toString().ensureTrailingSlash()
|
private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash()
|
||||||
|
|
||||||
override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload"
|
override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload"
|
||||||
|
|
||||||
|
|
|
@ -16,18 +16,12 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.homeserver
|
package org.matrix.android.sdk.internal.session.homeserver
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
|
||||||
import io.realm.Realm
|
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper
|
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
|
||||||
import org.matrix.android.sdk.internal.database.query.get
|
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class DefaultHomeServerCapabilitiesService @Inject constructor(
|
internal class DefaultHomeServerCapabilitiesService @Inject constructor(
|
||||||
@SessionDatabase private val monarchy: Monarchy,
|
private val homeServerCapabilitiesDataSource: HomeServerCapabilitiesDataSource,
|
||||||
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask
|
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask
|
||||||
) : HomeServerCapabilitiesService {
|
) : HomeServerCapabilitiesService {
|
||||||
|
|
||||||
|
@ -36,11 +30,7 @@ internal class DefaultHomeServerCapabilitiesService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getHomeServerCapabilities(): HomeServerCapabilities {
|
override fun getHomeServerCapabilities(): HomeServerCapabilities {
|
||||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
return homeServerCapabilitiesDataSource.getHomeServerCapabilities()
|
||||||
HomeServerCapabilitiesEntity.get(realm)?.let {
|
|
||||||
HomeServerCapabilitiesMapper.map(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?: HomeServerCapabilities()
|
?: HomeServerCapabilities()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.homeserver
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import org.matrix.android.sdk.api.extensions.orTrue
|
import org.matrix.android.sdk.api.extensions.orTrue
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
|
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
|
||||||
|
@ -38,9 +39,14 @@ internal data class Capabilities(
|
||||||
* Capability to indicate if the user can change their password.
|
* Capability to indicate if the user can change their password.
|
||||||
*/
|
*/
|
||||||
@Json(name = "m.change_password")
|
@Json(name = "m.change_password")
|
||||||
val changePassword: ChangePassword? = null
|
val changePassword: ChangePassword? = null,
|
||||||
|
|
||||||
// No need for m.room_versions for the moment
|
/**
|
||||||
|
* This capability describes the default and available room versions a server supports, and at what level of stability.
|
||||||
|
* Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms.
|
||||||
|
*/
|
||||||
|
@Json(name = "m.room_versions")
|
||||||
|
val roomVersions: RoomVersions? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
|
@ -52,6 +58,21 @@ internal data class ChangePassword(
|
||||||
val enabled: Boolean?
|
val enabled: Boolean?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class RoomVersions(
|
||||||
|
/**
|
||||||
|
* Required. The default room version the server is using for new rooms.
|
||||||
|
*/
|
||||||
|
@Json(name = "default")
|
||||||
|
val default: String?,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. A detailed description of the room versions the server supports.
|
||||||
|
*/
|
||||||
|
@Json(name = "available")
|
||||||
|
val available: JsonDict
|
||||||
|
)
|
||||||
|
|
||||||
// The spec says: If not present, the client should assume that password changes are possible via the API
|
// The spec says: If not present, the client should assume that password changes are possible via the API
|
||||||
internal fun GetCapabilitiesResult.canChangePassword(): Boolean {
|
internal fun GetCapabilitiesResult.canChangePassword(): Boolean {
|
||||||
return capabilities?.changePassword?.enabled.orTrue()
|
return capabilities?.changePassword?.enabled.orTrue()
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.matrix.android.sdk.internal.session.homeserver
|
package org.matrix.android.sdk.internal.session.homeserver
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import org.matrix.android.sdk.api.MatrixPatterns.getDomain
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
@ -24,6 +25,7 @@ import org.matrix.android.sdk.internal.auth.version.Versions
|
||||||
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
|
@ -89,7 +91,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
|
|
||||||
val wellknownResult = runCatching {
|
val wellknownResult = runCatching {
|
||||||
getWellknownTask.execute(GetWellknownTask.Params(userId, homeServerConnectionConfig))
|
getWellknownTask.execute(GetWellknownTask.Params(
|
||||||
|
domain = userId.getDomain(),
|
||||||
|
homeServerConnectionConfig = homeServerConnectionConfig
|
||||||
|
))
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
|
|
||||||
insertInDb(capabilities, mediaConfig, versions, wellknownResult)
|
insertInDb(capabilities, mediaConfig, versions, wellknownResult)
|
||||||
|
@ -104,6 +109,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
|
|
||||||
if (getCapabilitiesResult != null) {
|
if (getCapabilitiesResult != null) {
|
||||||
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
|
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
|
||||||
|
|
||||||
|
homeServerCapabilitiesEntity.roomVersionsJson = getCapabilitiesResult.capabilities?.roomVersions?.let {
|
||||||
|
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getMediaConfigResult != null) {
|
if (getMediaConfigResult != null) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.session.homeserver
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import io.realm.Realm
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.query.get
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class HomeServerCapabilitiesDataSource @Inject constructor(
|
||||||
|
@SessionDatabase private val monarchy: Monarchy
|
||||||
|
) {
|
||||||
|
fun getHomeServerCapabilities(): HomeServerCapabilities? {
|
||||||
|
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||||
|
HomeServerCapabilitiesEntity.get(realm)?.let {
|
||||||
|
HomeServerCapabilitiesMapper.map(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -191,7 +191,7 @@ internal class DefaultIdentityService @Inject constructor(
|
||||||
} else {
|
} else {
|
||||||
// Disconnect previous one if any, first, because the token will change.
|
// Disconnect previous one if any, first, because the token will change.
|
||||||
// In case of error when configuring the new identity server, this is not a big deal,
|
// In case of error when configuring the new identity server, this is not a big deal,
|
||||||
// we will ask for a new token on the previous Identity server
|
// we will ask for a new token on the previous identity server
|
||||||
runCatching { identityDisconnectTask.execute(Unit) }
|
runCatching { identityDisconnectTask.execute(Unit) }
|
||||||
.onFailure { Timber.w(it, "Unable to disconnect identity server") }
|
.onFailure { Timber.w(it, "Unable to disconnect identity server") }
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ internal class DefaultIdentityService @Inject constructor(
|
||||||
|
|
||||||
override suspend fun getShareStatus(threePids: List<ThreePid>): Map<ThreePid, SharedState> {
|
override suspend fun getShareStatus(threePids: List<ThreePid>): Map<ThreePid, SharedState> {
|
||||||
// Note: we do not require user consent here, because it is used for emails and phone numbers that the user has already sent
|
// Note: we do not require user consent here, because it is used for emails and phone numbers that the user has already sent
|
||||||
// to the home server, and not emails and phone numbers from the contact book of the user
|
// to the homeserver, and not emails and phone numbers from the contact book of the user
|
||||||
|
|
||||||
if (threePids.isEmpty()) {
|
if (threePids.isEmpty()) {
|
||||||
return emptyMap()
|
return emptyMap()
|
||||||
|
|
|
@ -42,7 +42,7 @@ internal interface IdentityAuthAPI {
|
||||||
suspend fun ping()
|
suspend fun ping()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ping v1 will be used to check outdated Identity server
|
* Ping v1 will be used to check outdated identity server
|
||||||
*/
|
*/
|
||||||
@GET("_matrix/identity/api/v1")
|
@GET("_matrix/identity/api/v1")
|
||||||
suspend fun pingV1()
|
suspend fun pingV1()
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue