WIP integration with old SDK (not working)

This commit is contained in:
ganfra 2018-10-10 19:46:43 +02:00
parent 3215fa47d5
commit 108fae2f28
87 changed files with 2233 additions and 1937 deletions

View File

@ -5,9 +5,9 @@ import android.view.View
import android.widget.Toast
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.Session
import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.RiotActivity
import im.vector.riotredesign.features.home.HomeActivity
@ -17,7 +17,6 @@ import org.koin.android.ext.android.inject
class LoginActivity : RiotActivity() {

private val matrix by inject<Matrix>()
private val homeServerConnectionConfig = HomeServerConnectionConfig("https://matrix.org/")
private val authenticator = matrix.authenticator()

override fun onCreate(savedInstanceState: Bundle?) {
@ -30,6 +29,11 @@ class LoginActivity : RiotActivity() {
val login = loginField.text.trim().toString()
val password = passwordField.text.trim().toString()
progressBar.visibility = View.VISIBLE
val homeServerConnectionConfig = HomeServerConnectionConfig.Builder()
.withHomeServerUri("https://matrix.org/")
.withIdentityServerUri("https://vector.im")
.build()

authenticator.authenticate(homeServerConnectionConfig, login, password, object : MatrixCallback<Session> {
override fun onSuccess(data: Session?) {
matrix.currentSession = data

View File

@ -3,9 +3,6 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'io.objectbox'

ext.support_version = '28.0.0'
ext.moshi_version = '1.7.0'

buildscript {

repositories {
@ -43,6 +40,11 @@ android {
}

dependencies {

def arrow_version = "0.7.3"
def support_version = '28.0.0'
def moshi_version = '1.7.0'

implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

@ -65,6 +67,8 @@ dependencies {
// Paging
implementation "android.arch.paging:runtime:1.0.1"

implementation "io.arrow-kt:arrow-core:$arrow_version"

// DI
implementation "org.koin:koin-core:$koin_version"
implementation "org.koin:koin-core-ext:$koin_version"

View File

@ -4,50 +4,77 @@
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "3:213989653016909134",
"lastPropertyId": "6:8192129106205548340",
"id": "6:5991986256653472999",
"lastPropertyId": "6:5675340775405504775",
"name": "Credentials",
"properties": [
{
"id": "1:3516672544602138732",
"id": "1:904844404428661340",
"name": "id"
},
{
"id": "2:8457998089049891725",
"indexId": "1:7573100044105293219",
"id": "2:4962733318674873893",
"name": "userId"
},
{
"id": "3:878535388660167894",
"id": "3:6496111157191804406",
"name": "homeServer"
},
{
"id": "4:7030303501035684102",
"id": "4:6583709765305423919",
"name": "accessToken"
},
{
"id": "5:7193051897929077560",
"id": "5:865976960498370870",
"name": "refreshToken"
},
{
"id": "6:8192129106205548340",
"id": "6:5675340775405504775",
"name": "deviceId"
}
],
"relations": []
},
{
"id": "7:6920598293865885979",
"lastPropertyId": "3:5795529890406591571",
"name": "ObjectBoxSessionParams",
"properties": [
{
"id": "1:7073183456619398402",
"name": "credentialsJson"
},
{
"id": "2:8905537494398356078",
"name": "homeServerConnectionConfigJson"
},
{
"id": "3:5795529890406591571",
"name": "id"
}
],
"relations": []
}
],
"lastEntityId": "3:213989653016909134",
"lastIndexId": "1:7573100044105293219",
"lastEntityId": "7:6920598293865885979",
"lastIndexId": "4:1616715309690181473",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 4,
"modelVersionParserMinimum": 4,
"retiredEntityUids": [
637433444018824383,
5577202525246066978
5577202525246066978,
213989653016909134,
826321009570992494,
1775102368193732759
],
"retiredIndexUids": [
7573100044105293219,
7664899561635023422,
762622607983996029,
1616715309690181473
],
"retiredIndexUids": [],
"retiredPropertyUids": [
6211403495341530846,
1774175862476960436,
@ -60,7 +87,25 @@
8258973118557394726,
4167129800901721265,
4654729568692986907,
958528673818813300
958528673818813300,
3516672544602138732,
8457998089049891725,
878535388660167894,
7030303501035684102,
7193051897929077560,
8192129106205548340,
7632656533038841948,
1390065349267803135,
6024884732066241356,
3502558420506448922,
3999645739247298623,
8488502568193639300,
594512591943458255,
5113574037182501000,
4929796643260285955,
5690571528511905880,
1811444397594387116,
8817556524159529201
],
"retiredRelationUids": [],
"version": 1

View File

@ -4,49 +4,76 @@
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "3:213989653016909134",
"lastPropertyId": "6:8192129106205548340",
"name": "Credentials",
"id": "4:1775102368193732759",
"lastPropertyId": "6:8817556524159529201",
"name": "SessionParams",
"properties": [
{
"id": "1:3516672544602138732",
"id": "2:5690571528511905880",
"name": "homeServerConnectionConfig"
},
{
"id": "3:1811444397594387116",
"name": "id"
},
{
"id": "2:8457998089049891725",
"id": "6:8817556524159529201",
"indexId": "4:1616715309690181473",
"name": "credentialsRelationId"
}
],
"relations": []
},
{
"id": "6:5991986256653472999",
"lastPropertyId": "6:5675340775405504775",
"name": "Credentials",
"properties": [
{
"id": "1:904844404428661340",
"name": "id"
},
{
"id": "2:4962733318674873893",
"name": "userId"
},
{
"id": "3:878535388660167894",
"id": "3:6496111157191804406",
"name": "homeServer"
},
{
"id": "4:7030303501035684102",
"id": "4:6583709765305423919",
"name": "accessToken"
},
{
"id": "5:7193051897929077560",
"id": "5:865976960498370870",
"name": "refreshToken"
},
{
"id": "6:8192129106205548340",
"id": "6:5675340775405504775",
"name": "deviceId"
}
],
"relations": []
}
],
"lastEntityId": "3:213989653016909134",
"lastIndexId": "0:0",
"lastEntityId": "6:5991986256653472999",
"lastIndexId": "4:1616715309690181473",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 4,
"modelVersionParserMinimum": 4,
"retiredEntityUids": [
637433444018824383,
5577202525246066978
5577202525246066978,
213989653016909134,
826321009570992494
],
"retiredIndexUids": [
7573100044105293219,
7664899561635023422,
762622607983996029
],
"retiredIndexUids": [],
"retiredPropertyUids": [
6211403495341530846,
1774175862476960436,
@ -59,7 +86,22 @@
8258973118557394726,
4167129800901721265,
4654729568692986907,
958528673818813300
958528673818813300,
3516672544602138732,
8457998089049891725,
878535388660167894,
7030303501035684102,
7193051897929077560,
8192129106205548340,
7632656533038841948,
1390065349267803135,
6024884732066241356,
3502558420506448922,
3999645739247298623,
8488502568193639300,
594512591943458255,
5113574037182501000,
4929796643260285955
],
"retiredRelationUids": [],
"version": 1

View File

@ -1,11 +0,0 @@
package im.vector.matrix.android.api.auth

import im.vector.matrix.android.internal.auth.data.Credentials

interface CredentialsStore {

fun get(): Credentials?

fun save(credentials: Credentials)

}

View File

@ -0,0 +1,11 @@
package im.vector.matrix.android.api.auth

import im.vector.matrix.android.internal.auth.data.SessionParams

interface SessionParamsStore {

fun get(): SessionParams?

fun save(sessionParams: SessionParams)

}

View File

@ -1,9 +1,225 @@
package im.vector.matrix.android.api.auth.data

import android.net.Uri
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.network.ssl.Fingerprint
import okhttp3.CipherSuite
import okhttp3.TlsVersion

@JsonClass(generateAdapter = true)
data class HomeServerConnectionConfig(
// the home server URI
val hsUri: String
)
val homeServerUri: Uri,
val identityServerUri: Uri,
val antiVirusServerUri: Uri? = null,
val allowedFingerprints: MutableList<Fingerprint> = ArrayList(),
val shouldPin: Boolean = false,
val tlsVersions: MutableList<TlsVersion>? = null,
val tlsCipherSuites: MutableList<CipherSuite>? = null,
val shouldAcceptTlsExtensions: Boolean = true,
val allowHttpExtension: Boolean = false,
val forceUsageTlsVersions: Boolean = false
) {

class Builder {

private lateinit var homeServerUri: Uri
private lateinit var identityServerUri: Uri
private var antiVirusServerUri: Uri? = null
private val allowedFingerprints: MutableList<Fingerprint> = ArrayList()
private var shouldPin: Boolean = false
private val tlsVersions: MutableList<TlsVersion> = ArrayList()
private val tlsCipherSuites: MutableList<CipherSuite> = ArrayList()
private var shouldAcceptTlsExtensions: Boolean = true
private var allowHttpExtension: Boolean = false
private var forceUsageTlsVersions: Boolean = false

fun withHomeServerUri(hsUriString: String): Builder {
return withHomeServerUri(Uri.parse(hsUriString))
}

/**
* @param hsUri The URI to use to connect to the homeserver.
* @return this builder
*/
fun withHomeServerUri(hsUri: Uri): Builder {
if (hsUri.scheme != "http" && hsUri.scheme != "https") {
throw RuntimeException("Invalid home server URI: " + hsUri!!)
}
// remove trailing /
homeServerUri = if (hsUri.toString().endsWith("/")) {
try {
val url = hsUri.toString()
Uri.parse(url.substring(0, url.length - 1))
} catch (e: Exception) {
throw RuntimeException("Invalid home server URI: $hsUri")
}
} else {
hsUri
}
return this
}

fun withIdentityServerUri(identityServerUriString: String): Builder {
return withIdentityServerUri(Uri.parse(identityServerUriString))
}

/**
* @param identityServerUri The URI to use to manage identity.
* @return this builder
*/
fun withIdentityServerUri(identityServerUri: Uri): Builder {
if (identityServerUri.scheme != "http" && identityServerUri.scheme != "https") {
throw RuntimeException("Invalid identity server URI: $identityServerUri")
}
// remove trailing /
if (identityServerUri.toString().endsWith("/")) {
try {
val url = identityServerUri.toString()
this.identityServerUri = Uri.parse(url.substring(0, url.length - 1))
} catch (e: Exception) {
throw RuntimeException("Invalid identity server URI: $identityServerUri")
}
} else {
this.identityServerUri = identityServerUri
}
return this
}

/**
* @param allowedFingerprints If using SSL, allow server certs that match these fingerprints.
* @return this builder
*/
fun withAllowedFingerPrints(allowedFingerprints: List<Fingerprint>?): Builder {
if (allowedFingerprints != null) {
this.allowedFingerprints.addAll(allowedFingerprints)
}
return this
}

/**
* @param pin If true only allow certs matching given fingerprints, otherwise fallback to
* standard X509 checks.
* @return this builder
*/
fun withPin(pin: Boolean): Builder {
this.shouldPin = pin
return this
}

/**
* @param shouldAcceptTlsExtension
* @return this builder
*/
fun withShouldAcceptTlsExtensions(shouldAcceptTlsExtension: Boolean): Builder {
this.shouldAcceptTlsExtensions = shouldAcceptTlsExtension
return this
}

/**
* Add an accepted TLS version for TLS connections with the home server.
*
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
* @return this builder
*/
fun addAcceptedTlsVersion(tlsVersion: TlsVersion): Builder {
this.tlsVersions.add(tlsVersion)
return this
}

/**
* Force the usage of TlsVersion. This can be usefull for device on Android version < 20
*
* @param forceUsageOfTlsVersions set to true to force the usage of specified TlsVersions (with [.addAcceptedTlsVersion]
* @return this builder
*/
fun forceUsageOfTlsVersions(forceUsageOfTlsVersions: Boolean): Builder {
this.forceUsageTlsVersions = forceUsageOfTlsVersions
return this
}

/**
* Add a TLS cipher suite to the list of accepted TLS connections with the home server.
*
* @param tlsCipherSuite the tls cipher suite to add.
* @return this builder
*/
fun addAcceptedTlsCipherSuite(tlsCipherSuite: CipherSuite): Builder {
this.tlsCipherSuites.add(tlsCipherSuite)
return this
}

/**
* Update the anti-virus server URI.
*
* @param antivirusServerUri the new anti-virus uri. Can be null
* @return this builder
*/
fun withAntiVirusServerUri(antivirusServerUri: Uri?): Builder {
if (null != antivirusServerUri && "http" != antivirusServerUri.scheme && "https" != antivirusServerUri.scheme) {
throw RuntimeException("Invalid antivirus server URI: $antivirusServerUri")
}
this.antiVirusServerUri = antivirusServerUri
return this
}

/**
* Convenient method to limit the TLS versions and cipher suites for this Builder
* Ref:
* - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf
* - https://developer.android.com/reference/javax/net/ssl/SSLEngine
*
* @param tlsLimitations true to use Tls limitations
* @param enableCompatibilityMode set to true for Android < 20
* @return this builder
*/
fun withTlsLimitations(tlsLimitations: Boolean, enableCompatibilityMode: Boolean): Builder {
if (tlsLimitations) {
withShouldAcceptTlsExtensions(false)

// Tls versions
addAcceptedTlsVersion(TlsVersion.TLS_1_2)
addAcceptedTlsVersion(TlsVersion.TLS_1_3)

forceUsageOfTlsVersions(enableCompatibilityMode)

// Cipher suites
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)

if (enableCompatibilityMode) {
// Adopt some preceding cipher suites for Android < 20 to be able to negotiate
// a TLS session.
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
}
}
return this
}

fun withAllowHttpConnection(allowHttpExtension: Boolean): Builder {
this.allowHttpExtension = allowHttpExtension
return this
}

/**
* @return the [HomeServerConnectionConfig]
*/
fun build(): HomeServerConnectionConfig {
return HomeServerConnectionConfig(homeServerUri, identityServerUri, antiVirusServerUri, allowedFingerprints, shouldPin, tlsVersions, tlsCipherSuites, shouldAcceptTlsExtensions, allowHttpExtension, forceUsageTlsVersions)
}

}


}






View File

@ -1,7 +1,9 @@
package im.vector.matrix.android.api.events

import com.google.gson.JsonObject
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.legacy.util.JsonUtils

@JsonClass(generateAdapter = true)
data class Event(
@ -14,4 +16,14 @@ data class Event(
@Json(name = "state_key") val stateKey: String? = null,
@Json(name = "room_id") val roomId: String? = null,
@Json(name = "unsigned_data") val unsignedData: UnsignedData? = null
)
){

fun contentAsJsonObject(): JsonObject? {
return JsonUtils.toJson(content)
}



}



View File

@ -1,43 +1,42 @@
package im.vector.matrix.android.api.events

import com.squareup.moshi.Json

object EventType {

enum class EventType {

@Json(name ="m.presence") PRESENCE,
@Json(name ="m.room.message") MESSAGE,
@Json(name ="m.sticker") STICKER,
@Json(name ="m.room.encrypted") ENCRYPTED,
@Json(name ="m.room.encryption") ENCRYPTION,
@Json(name ="m.room.message.feedback") FEEDBACK,
@Json(name ="m.typing") TYPING,
@Json(name ="m.room.redaction") REDACTION,
@Json(name ="m.receipt") RECEIPT,
@Json(name ="m.tag") TAG,
@Json(name ="m.room_key") ROOM_KEY,
@Json(name ="m.fully_read") FULLY_READ,
@Json(name ="m.room.plumbing") PLUMBING,
@Json(name ="m.room.bot.options") BOT_OPTIONS,
@Json(name ="m.room_key_request") KEY_REQUEST,
@Json(name ="m.forwarded_room_key") FORWARDED_ROOM_KEY,
@Json(name ="org.matrix.room.preview_urls") PREVIEW_URLS,
const val PRESENCE = "m.presence"
const val MESSAGE = "m.room.message"
const val STICKER = "m.sticker"
const val ENCRYPTED = "m.room.encrypted"
const val ENCRYPTION = "m.room.encryption"
const val FEEDBACK = "m.room.message.feedback"
const val TYPING = "m.typing"
const val REDACTION = "m.room.redaction"
const val RECEIPT = "m.receipt"
const val TAG = "m.tag"
const val ROOM_KEY = "m.room_key"
const val FULLY_READ = "m.fully_read"
const val PLUMBING = "m.room.plumbing"
const val BOT_OPTIONS = "m.room.bot.options"
const val KEY_REQUEST = "m.room_key_request"
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
const val PREVIEW_URLS = "org.matrix.room.preview_urls"

// State Events
@Json(name ="m.room.name") STATE_ROOM_NAME,
@Json(name ="m.room.topic") STATE_ROOM_TOPIC,
@Json(name ="m.room.avatar") STATE_ROOM_AVATAR,
@Json(name ="m.room.member") STATE_ROOM_MEMBER,
@Json(name ="m.room.third_party_invite") STATE_ROOM_THIRD_PARTY_INVITE,
@Json(name ="m.room.create") STATE_ROOM_CREATE,
@Json(name ="m.room.join_rules") STATE_ROOM_JOIN_RULES,
@Json(name ="m.room.guest_access") STATE_ROOM_GUEST_ACCESS,
@Json(name ="m.room.power_levels") STATE_ROOM_POWER_LEVELS,
@Json(name ="m.room.aliases") STATE_ROOM_ALIASES,
@Json(name ="m.room.tombstone") STATE_ROOM_TOMBSTONE,
@Json(name ="m.room.canonical_alias") STATE_CANONICAL_ALIAS,
@Json(name ="m.room.history_visibility") STATE_HISTORY_VISIBILITY,
@Json(name ="m.room.related_groups") STATE_RELATED_GROUPS,
@Json(name ="m.room.pinned_events") STATE_PINNED_EVENT

const val STATE_ROOM_NAME = "m.room.name"
const val STATE_ROOM_TOPIC = "m.room.topic"
const val STATE_ROOM_AVATAR = "m.room.avatar"
const val STATE_ROOM_MEMBER = "m.room.member"
const val STATE_ROOM_THIRD_PARTY_INVITE = "m.room.third_party_invite"
const val STATE_ROOM_CREATE = "m.room.create"
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
const val STATE_ROOM_ALIASES = "m.room.aliases"
const val STATE_ROOM_TOMBSTONE = "m.room.tombstone"
const val STATE_CANONICAL_ALIAS = "m.room.canonical_alias"
const val STATE_HISTORY_VISIBILITY = "m.room.history_visibility"
const val STATE_RELATED_GROUPS = "m.room.related_groups"
const val STATE_PINNED_EVENT = "m.room.pinned_events"

}

View File

@ -1,7 +1,9 @@
package im.vector.matrix.android.api.rooms

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class Invite(
@Json(name = "display_name") val displayName: String,
@Json(name = "signed") val signed: Signed

View File

@ -1,12 +1,15 @@
package im.vector.matrix.android.api.rooms

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.events.UnsignedData

@JsonClass(generateAdapter = true)
data class RoomMember(
val membership: Membership,
val displayDame: String? = null,
val avatarUrl: String? = null,
val isDirect: Boolean = false,
val thirdPartyInvite: Invite? = null,
val unsignedData: UnsignedData? = null
@Json(name = "membership") val membership: Membership,
@Json(name = "display_name") val displayDame: String? = null,
@Json(name = "avatar_url") val avatarUrl: String? = null,
@Json(name = "is_direct") val isDirect: Boolean = false,
@Json(name = "third_party_invite") val thirdPartyInvite: Invite? = null,
@Json(name = "unsigned_data") val unsignedData: UnsignedData? = null
)

View File

@ -2,10 +2,10 @@ package im.vector.matrix.android.internal.auth

import android.content.Context
import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.auth.CredentialsStore
import im.vector.matrix.android.internal.auth.data.Credentials
import im.vector.matrix.android.internal.auth.data.MyObjectBox
import im.vector.matrix.android.internal.auth.db.ObjectBoxCredentialsStore
import im.vector.matrix.android.api.auth.SessionParamsStore
import im.vector.matrix.android.internal.auth.db.ObjectBoxSessionParams
import im.vector.matrix.android.internal.auth.db.ObjectBoxSessionParamsMapper
import im.vector.matrix.android.internal.auth.db.ObjectBoxSessionParamsStore
import io.objectbox.Box
import io.objectbox.BoxStore
import org.koin.dsl.context.ModuleDefinition
@ -26,13 +26,14 @@ class AuthModule(private val context: Context) : Module {
MyObjectBox.builder().androidContext(context).build()
}


single {
val boxStore = get(name = AUTH_BOX_STORE) as BoxStore
boxStore.boxFor(Credentials::class.java) as Box<Credentials>
boxStore.boxFor(ObjectBoxSessionParams::class.java) as Box<ObjectBoxSessionParams>
}

single {
ObjectBoxCredentialsStore(get()) as CredentialsStore
ObjectBoxSessionParamsStore(ObjectBoxSessionParamsMapper((get())), get()) as SessionParamsStore
}

}.invoke()

View File

@ -1,19 +1,21 @@
package im.vector.matrix.android.internal.auth

import arrow.core.leftIfNull
import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.auth.CredentialsStore
import im.vector.matrix.android.api.auth.SessionParamsStore
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.session.DefaultSession
import im.vector.matrix.android.internal.auth.data.Credentials
import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
import im.vector.matrix.android.internal.auth.data.SessionParams
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.DefaultSession
import im.vector.matrix.android.internal.util.CancelableCoroutine
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.map
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import retrofit2.Retrofit
@ -21,28 +23,34 @@ import retrofit2.Retrofit
class DefaultAuthenticator(private val retrofitBuilder: Retrofit.Builder,
private val jsonMapper: Moshi,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val credentialsStore: CredentialsStore) : Authenticator {
private val sessionParamsStore: SessionParamsStore) : Authenticator {

override fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback<Session>): Cancelable {
val authAPI = buildAuthAPI(homeServerConnectionConfig)

val job = GlobalScope.launch(coroutineDispatchers.main) {
val loginParams = PasswordLoginParams.userIdentifier(login, password, "Mobile")
val loginResult = executeRequest<Credentials> {
executeRequest<Credentials> {
apiCall = authAPI.login(loginParams)
moshi = jsonMapper
dispatcher = coroutineDispatchers.io
}.leftIfNull {
Failure.Unknown(IllegalArgumentException("Credentials shouldn't not be null"))
}.map {
it?.apply { credentialsStore.save(it) }
val sessionParams = SessionParams(it, homeServerConnectionConfig)
sessionParamsStore.save(sessionParams)
sessionParams
}.map {
DefaultSession(homeServerConnectionConfig)
}
loginResult.either({ callback.onFailure(it) }, { callback.onSuccess(it) })
DefaultSession(it)
}.bimap(
{ callback.onFailure(it) }, { callback.onSuccess(it) }
)
}
return CancelableCoroutine(job)
}

private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
val retrofit = retrofitBuilder.baseUrl(homeServerConnectionConfig.hsUri).build()
val retrofit = retrofitBuilder.baseUrl(homeServerConnectionConfig.homeServerUri.toString()).build()
return retrofit.create(AuthAPI::class.java)
}


View File

@ -4,13 +4,12 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id
import io.objectbox.annotation.Index

@Entity
@JsonClass(generateAdapter = true)
@Entity
data class Credentials(
@Id var id: Long = 0,
@Index @Json(name = "user_id") val userId: String,
@Json(name = "user_id") val userId: String,
@Json(name = "home_server") val homeServer: String,
@Json(name = "access_token") val accessToken: String,
@Json(name = "refresh_token") val refreshToken: String?,

View File

@ -0,0 +1,8 @@
package im.vector.matrix.android.internal.auth.data

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig

data class SessionParams(
val credentials: Credentials,
val homeServerConnectionConfig: HomeServerConnectionConfig
)

View File

@ -1,17 +0,0 @@
package im.vector.matrix.android.internal.auth.db

import im.vector.matrix.android.api.auth.CredentialsStore
import im.vector.matrix.android.internal.auth.data.Credentials
import io.objectbox.Box

class ObjectBoxCredentialsStore(private val box: Box<Credentials>) : CredentialsStore {

override fun save(credentials: Credentials) {
box.put(credentials)
}

override fun get(): Credentials? {
return box.all.lastOrNull()
}

}

View File

@ -0,0 +1,11 @@
package im.vector.matrix.android.internal.auth.db

import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id

@Entity
data class ObjectBoxSessionParams(
val credentialsJson: String,
val homeServerConnectionConfigJson: String,
@Id var id: Long = 0
)

View File

@ -0,0 +1,38 @@
package im.vector.matrix.android.internal.auth.db

import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.internal.auth.data.Credentials
import im.vector.matrix.android.internal.auth.data.SessionParams

class ObjectBoxSessionParamsMapper(moshi: Moshi) {

private val credentialsAdapter = moshi.adapter(Credentials::class.java)
private val homeServerConnectionConfigAdapter = moshi.adapter(HomeServerConnectionConfig::class.java)

fun map(objectBoxSessionParams: ObjectBoxSessionParams?): SessionParams? {
if (objectBoxSessionParams == null) {
return null
}
val credentials = credentialsAdapter.fromJson(objectBoxSessionParams.credentialsJson)
val homeServerConnectionConfig = homeServerConnectionConfigAdapter.fromJson(objectBoxSessionParams.homeServerConnectionConfigJson)
if (credentials == null || homeServerConnectionConfig == null) {
return null
}
return SessionParams(credentials, homeServerConnectionConfig)
}

fun map(sessionParams: SessionParams?): ObjectBoxSessionParams? {
if (sessionParams == null) {
return null
}
val credentialsJson = credentialsAdapter.toJson(sessionParams.credentials)
val homeServerConnectionConfigJson = homeServerConnectionConfigAdapter.toJson(sessionParams.homeServerConnectionConfig)
if (credentialsJson == null || homeServerConnectionConfigJson == null) {
return null
}
return ObjectBoxSessionParams(credentialsJson, homeServerConnectionConfigJson)
}


}

View File

@ -0,0 +1,21 @@
package im.vector.matrix.android.internal.auth.db

import im.vector.matrix.android.api.auth.SessionParamsStore
import im.vector.matrix.android.internal.auth.data.SessionParams
import io.objectbox.Box

class ObjectBoxSessionParamsStore(private val mapper: ObjectBoxSessionParamsMapper,
private val box: Box<ObjectBoxSessionParams>) : SessionParamsStore {

override fun save(sessionParams: SessionParams) {
val objectBoxSessionParams = mapper.map(sessionParams)
objectBoxSessionParams?.let {
box.put(it)
}
}

override fun get(): SessionParams? {
return box.all.map { mapper.map(it) }.lastOrNull()
}

}

View File

@ -14,6 +14,10 @@ class MatrixModule(private val options: MatrixOptions) : Module {

override fun invoke(): ModuleDefinition = module {

single {
options.context
}

single {
MatrixCoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.IO, main = options.mainExecutor.asCoroutineDispatcher())
}

View File

@ -0,0 +1,13 @@
package im.vector.matrix.android.internal.di

import com.squareup.moshi.Moshi

object MoshiProvider {

private val moshi: Moshi = Moshi.Builder().build()

fun providesMoshi(): Moshi {
return moshi
}

}

View File

@ -1,7 +1,6 @@
package im.vector.matrix.android.internal.di

import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import com.squareup.moshi.Moshi
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@ -25,7 +24,7 @@ class NetworkModule : Module {

single {
val logger = HttpLoggingInterceptor.Logger { message -> Timber.v(message) }
HttpLoggingInterceptor(logger).apply { level = HttpLoggingInterceptor.Level.BODY }
HttpLoggingInterceptor(logger).apply { level = HttpLoggingInterceptor.Level.BASIC }
}

single {
@ -39,7 +38,7 @@ class NetworkModule : Module {
}

single {
Moshi.Builder().build()
MoshiProvider.providesMoshi()
}

single {

View File

@ -1,20 +1,32 @@
package im.vector.matrix.android.internal.di

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.internal.auth.data.SessionParams
import im.vector.matrix.android.internal.legacy.MXDataHandler
import im.vector.matrix.android.internal.legacy.MXSession
import im.vector.matrix.android.internal.legacy.data.store.MXFileStore
import im.vector.matrix.android.internal.session.DefaultSession
import org.koin.dsl.context.ModuleDefinition
import org.koin.dsl.module.Module
import org.koin.dsl.module.module
import retrofit2.Retrofit

class SessionModule(private val connectionConfig: HomeServerConnectionConfig) : Module {
class SessionModule(private val sessionParams: SessionParams) : Module {

override fun invoke(): ModuleDefinition = module(override = true) {
scope(DefaultSession.SCOPE) {
val retrofitBuilder = get() as Retrofit.Builder
retrofitBuilder
.baseUrl(connectionConfig.hsUri)
.baseUrl(sessionParams.homeServerConnectionConfig?.homeServerUri.toString())
.build()
}

scope(DefaultSession.SCOPE) {
val store = MXFileStore(sessionParams.credentials, false, get())
val dataHandler = MXDataHandler(store, sessionParams.credentials)
MXSession.Builder(sessionParams, dataHandler, get()).build()
}

}.invoke()


}

View File

@ -16,7 +16,11 @@ class SyncModule : Module {
}

scope(DefaultSession.SCOPE) {
Synchronizer(get(), get(), get())
SyncResponseHandler(get(), get())
}

scope(DefaultSession.SCOPE) {
Synchronizer(get(), get(), get(), get())
}

}.invoke()

View File

@ -0,0 +1,523 @@
package im.vector.matrix.android.internal.events.sync

import android.text.TextUtils
import im.vector.matrix.android.api.events.Event
import im.vector.matrix.android.internal.events.sync.data.SyncResponse
import im.vector.matrix.android.internal.legacy.MXDataHandler
import im.vector.matrix.android.internal.legacy.data.Room
import im.vector.matrix.android.internal.legacy.data.store.IMXStore
import im.vector.matrix.android.internal.legacy.data.store.MXMemoryStore
import im.vector.matrix.android.internal.legacy.rest.client.AccountDataRestClient
import im.vector.matrix.android.internal.legacy.rest.model.RoomMember
import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse
import im.vector.matrix.android.internal.legacy.util.JsonUtils
import timber.log.Timber
import java.util.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.List
import kotlin.collections.Map
import kotlin.collections.MutableList
import kotlin.collections.MutableMap
import kotlin.collections.emptyList
import kotlin.collections.isNotEmpty
import kotlin.collections.set

class SyncResponseHandler(private val dataHandler: MXDataHandler,
private val store: IMXStore) {

private val leftRoomsStore = MXMemoryStore()
private var isStartingCryptoWithInitialSync = false
private var areLeftRoomsSynced = false

fun handleResponse(syncResponse: SyncResponse?, fromToken: String?, isCatchingUp: Boolean) {
if (syncResponse == null) {
return
}
Timber.v("Handle sync response")
val isInitialSync = null == fromToken
var isEmptyResponse = true

// Handle the to device events before the room ones
// to ensure to decrypt them properly
if (syncResponse.toDevice?.events != null) {
for (toDeviceEvent in syncResponse.toDevice.events) {
handleToDeviceEvent(toDeviceEvent)
}
}
// Handle account data before the room events
// to be able to update direct chats dictionary during invites handling.
if (syncResponse.accountData != null) {
manageAccountData(syncResponse.accountData, isInitialSync)
}

// sanity check
if (syncResponse.rooms != null) {
// joined rooms events
if (syncResponse.rooms.join.isNotEmpty()) {
val roomIds = syncResponse.rooms.join.keys
// Handle first joined rooms
for (roomId in roomIds) {
if (null != leftRoomsStore.getRoom(roomId)) {
leftRoomsStore.deleteRoom(roomId)
}
// TODO handle joined room
//getRoom(roomId).handleJoinedRoomSync(syncResponse.rooms.join[roomId], isInitialSync)
}
isEmptyResponse = false
}

// invited room management
if (syncResponse.rooms.invite.isNotEmpty()) {
val roomIds = syncResponse.rooms.invite.keys

var updatedDirectChatRoomsDict: MutableMap<String, List<String>>? = null
var hasChanged = false

for (roomId in roomIds) {
if (null != leftRoomsStore.getRoom(roomId)) {
leftRoomsStore.deleteRoom(roomId)
}
val room = getRoom(roomId)
val invitedRoomSync = syncResponse.rooms.invite[roomId]
// TODO handle invited room
//room.handleInvitedRoomSync(invitedRoomSync)

// Handle here the invites to a direct chat.
if (room.isDirectChatInvitation) {
// Retrieve the inviter user id.
var participantUserId: String? = null
for (event in invitedRoomSync?.inviteState?.events ?: emptyList()) {
if (event.sender != null) {
participantUserId = event.sender
break
}
}

if (participantUserId != null) {
// Prepare the updated dictionary.
if (updatedDirectChatRoomsDict == null) updatedDirectChatRoomsDict = if (null != store.directChatRoomsDict) {
// Consider the current dictionary.
HashMap(store.directChatRoomsDict)
} else {
java.util.HashMap()
}

val roomIdsList: MutableList<String> = if (updatedDirectChatRoomsDict.containsKey(participantUserId)) {
ArrayList(updatedDirectChatRoomsDict[participantUserId])
} else {
ArrayList()
}

// Check whether the room was not yet seen as direct chat
if (roomIdsList.indexOf(roomId) < 0) {

roomIdsList.add(roomId) // update room list with the new room
updatedDirectChatRoomsDict[participantUserId] = roomIdsList
hasChanged = true
}
}
}

}

isEmptyResponse = false

if (hasChanged) {
// Update account data to add new direct chat room(s)
/* mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES,
updatedDirectChatRoomsDict, object : ApiCallback<Void> {
override fun onSuccess(info: Void) {
}

override fun onNetworkError(e: Exception) {
// TODO: we should try again.
}

override fun onMatrixError(e: MatrixError) {
}

override fun onUnexpectedError(e: Exception) {
}
})*/
}
}

// left room management
// it should be done at the end but it seems there is a server issue
// when inviting after leaving a room, the room is defined in the both leave & invite rooms list.
if (syncResponse.rooms.leave.isNotEmpty()) {
val roomIds = syncResponse.rooms.leave.keys
for (roomId in roomIds) {
// RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId);

// Presently we remove the existing room from the rooms list.
// FIXME SYNC V2 Archive/Display the left rooms!
// For that create 'handleArchivedRoomSync' method

var membership = RoomMember.MEMBERSHIP_LEAVE
val room = getRoom(roomId)

// Retrieve existing room
// The room will then be able to notify its listeners.
// TODO handle
// room.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)

val member = room.getMember(dataHandler.userId)
if (null != member) {
membership = member.membership
}
if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) {
// ensure that the room data are properly deleted
store.deleteRoom(roomId)
dataHandler.onLeaveRoom(roomId)
} else {
dataHandler.onRoomKick(roomId)
}
// don't add to the left rooms if the user has been kicked / banned
if (areLeftRoomsSynced && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) {
val leftRoom = getRoom(leftRoomsStore, roomId, true)
//Todo handle
//leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)
}
}
isEmptyResponse = false
}
}

// groups
if (null != syncResponse.groups) {
// Handle invited groups
if (null != syncResponse.groups.invite && !syncResponse.groups.invite.isEmpty()) {
// Handle invited groups
for (groupId in syncResponse.groups.invite.keys) {
val invitedGroupSync = syncResponse.groups.invite[groupId]
dataHandler.groupsManager.onNewGroupInvitation(groupId, invitedGroupSync?.profile, invitedGroupSync?.inviter, !isInitialSync)
}
}

// Handle joined groups
if (null != syncResponse.groups.join && !syncResponse.groups.join.isEmpty()) {
for (groupId in syncResponse.groups.join.keys) {
dataHandler.groupsManager.onJoinGroup(groupId, !isInitialSync)
}
}
// Handle left groups
if (null != syncResponse.groups.leave && !syncResponse.groups.leave.isEmpty()) {
// Handle joined groups
for (groupId in syncResponse.groups.leave.keys) {
dataHandler.groupsManager.onLeaveGroup(groupId, !isInitialSync)
}
}
}

// Handle presence of other users
if (syncResponse.presence?.events != null) {
for (presenceEvent in syncResponse.presence.events) {
handlePresenceEvent(presenceEvent)
}
}
dataHandler.crypto?.onSyncCompleted(syncResponse, fromToken, isCatchingUp)
if (!isEmptyResponse) {
store.eventStreamToken = syncResponse.nextBatch
store.commit()
}

if (isInitialSync) {
if (!isCatchingUp) {
dataHandler.startCrypto(true)
} else {
// the events thread sends a dummy initial sync event
// when the application is restarted.
isStartingCryptoWithInitialSync = !isEmptyResponse
}

dataHandler.onInitialSyncComplete(syncResponse?.nextBatch)
} else {

if (!isCatchingUp) {
dataHandler.startCrypto(isStartingCryptoWithInitialSync)
}

dataHandler.onLiveEventsChunkProcessed(fromToken, syncResponse.nextBatch)
dataHandler.callsManager?.checkPendingIncomingCalls()

}
}

private fun manageAccountData(accountData: Map<String, Any>, isInitialSync: Boolean) {
if (accountData.containsKey("events")) {
val events = accountData["events"] as List<Map<String, Any>>
if (!events.isEmpty()) {
// ignored users list
manageIgnoredUsers(events, isInitialSync)
// push rules
managePushRulesUpdate(events)
// direct messages rooms
manageDirectChatRooms(events, isInitialSync)
// URL preview
manageUrlPreview(events)
// User widgets
manageUserWidgets(events)
}
}
}

/**
* Refresh the push rules from the account data events list
*
* @param events the account data events.
*/
private fun managePushRulesUpdate(events: List<Map<String, Any>>) {
for (event in events) {
val type = event["type"] as String

if (TextUtils.equals(type, "m.push_rules")) {
if (event.containsKey("content")) {
val gson = JsonUtils.getGson(false)

// convert the data to PushRulesResponse
// because BingRulesManager supports only PushRulesResponse
val element = gson.toJsonTree(event["content"])
dataHandler.bingRulesManager?.buildRules(gson.fromJson(element, PushRulesResponse::class.java))

// warn the client that the push rules have been updated
dataHandler.onBingRulesUpdate()
}

return
}
}
}

/**
* Check if the ignored users list is updated
*
* @param events the account data events list
*/
private fun manageIgnoredUsers(events: List<Map<String, Any>>, isInitialSync: Boolean) {
val newIgnoredUsers = dataHandler.ignoredUsers(events)

if (null != newIgnoredUsers) {
val curIgnoredUsers = dataHandler.ignoredUserIds
// the both lists are not empty
if (0 != newIgnoredUsers.size || 0 != curIgnoredUsers.size) {
// check if the ignored users list has been updated
if (newIgnoredUsers.size != curIgnoredUsers.size || !newIgnoredUsers.containsAll(curIgnoredUsers)) {
// update the store
store.setIgnoredUserIdsList(newIgnoredUsers)
if (!isInitialSync) {
// warn there is an update
dataHandler.onIgnoredUsersListUpdate()
}
}
}
}
}


/**
* Extract the direct chat rooms list from the dedicated events.
*
* @param events the account data events list.
*/
private fun manageDirectChatRooms(events: List<Map<String, Any>>, isInitialSync: Boolean) {
if (events.isNotEmpty()) {
for (event in events) {
val type = event["type"] as String

if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES)) {
if (event.containsKey("content")) {
val contentDict = event["content"] as Map<String, List<String>>
store.directChatRoomsDict = contentDict
// reset the current list of the direct chat roomIDs
// to update it
if (!isInitialSync) {
// warn there is an update
dataHandler.onDirectMessageChatRoomsListUpdate()
}
}
}
}
}
}

/**
* Manage the URL preview flag
*
* @param events the events list
*/
private fun manageUrlPreview(events: List<Map<String, Any>>) {
if (0 != events.size) {
for (event in events) {
val type = event["type"] as String

if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_PREVIEW_URLS)) {
if (event.containsKey("content")) {
val contentDict = event["content"] as Map<String, Any>
var enable = true
if (contentDict.containsKey(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE)) {
enable = !(contentDict[AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE] as Boolean)
}

store.setURLPreviewEnabled(enable)
}
}
}
}
}

/**
* Manage the user widgets
*
* @param events the events list
*/
private fun manageUserWidgets(events: List<Map<String, Any>>) {
if (0 != events.size) {
for (event in events) {
val type = event["type"] as String

if (TextUtils.equals(type, AccountDataRestClient.ACCOUNT_DATA_TYPE_WIDGETS)) {
if (event.containsKey("content")) {
val contentDict = event["content"] as Map<String, Any>
store.setUserWidgets(contentDict)
}
}
}
}
}

/**
* Handle a presence event.
*
* @param presenceEvent the presence event.
*/
private fun handlePresenceEvent(presenceEvent: Event) {
/* // Presence event
if (EventType.PRESENCE == presenceEvent.type) {
val userPresence = JsonUtils.toUser(presenceEvent.getContent())

// use the sender by default
if (!TextUtils.isEmpty(presenceEvent.getSender())) {
userPresence.user_id = presenceEvent.getSender()
}
var user: User? = store.getUser(userPresence.user_id)

if (user == null) {
user = userPresence
user!!.setDataHandler(dataHandler)
} else {
user.currently_active = userPresence.currently_active
user.presence = userPresence.presence
user.lastActiveAgo = userPresence.lastActiveAgo
}
user.latestPresenceTs = System.currentTimeMillis()
// check if the current user has been updated
if (mCredentials.userId == user.user_id) {
// always use the up-to-date information
getMyUser().displayname = user.displayname
getMyUser().avatar_url = user.avatarUrl

store.setAvatarURL(user.avatarUrl, presenceEvent.getOriginServerTs())
store.setDisplayName(user.displayname, presenceEvent.getOriginServerTs())
}
store.storeUser(user)
onPresenceUpdate(presenceEvent, user)
}*/
}

private fun handleToDeviceEvent(event: Event) {
// Decrypt event if necessary
/*
decryptEvent(event, null)
if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)
&& null != event.getContent()
&& TextUtils.equals(JsonUtils.getMessageMsgType(event.getContent()), "m.bad.encrypted")) {
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : %s", event.getContent())
} else {
//onToDeviceEvent(event)
}
*/
}

/**
* Decrypt an encrypted event
*
* @param event the event to decrypt
* @param timelineId the timeline identifier
* @return true if the event has been decrypted
*/
fun decryptEvent(event: Event?, timelineId: String?): Boolean {
/*
if (null != event && TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) {
if (null != getCrypto()) {
var result: MXEventDecryptionResult? = null
try {
result = getCrypto().decryptEvent(event, timelineId)
} catch (exception: MXDecryptionException) {
event.cryptoError = exception.cryptoError
}
if (null != result) {
event.setClearData(result)
return true
}
} else {
event.cryptoError = MXCryptoError(MXCryptoError.ENCRYPTING_NOT_ENABLED_ERROR_CODE, MXCryptoError.ENCRYPTING_NOT_ENABLED_REASON, null)
}
}
*/
return false
}

/**
* Get the room object for the corresponding room id. Creates and initializes the object if there is none.
*
* @param roomId the room id
* @return the corresponding room
*/
fun getRoom(roomId: String): Room {
return getRoom(roomId, true)
}

/**
* Get the room object for the corresponding room id.
* The left rooms are not included.
*
* @param roomId the room id
* @param create create the room it does not exist.
* @return the corresponding room
*/
fun getRoom(roomId: String, create: Boolean): Room {
return getRoom(store, roomId, create)
}

/**
* Get the room object for the corresponding room id.
* By default, the left rooms are not included.
*
* @param roomId the room id
* @param testLeftRooms true to test if the room is a left room
* @param create create the room it does not exist.
* @return the corresponding room
*/
fun getRoom(roomId: String, testLeftRooms: Boolean, create: Boolean): Room {
var room = store.getRoom(roomId)
if (room == null && testLeftRooms) {
room = leftRoomsStore.getRoom(roomId)
}
if (room == null && create) {
room = getRoom(store, roomId, create)
}
return room
}

fun getRoom(store: IMXStore, roomId: String, create: Boolean): Room {
var room = store.getRoom(roomId)
if (room == null && create) {
room = Room(dataHandler, store, roomId)
store.storeRoom(room)
}
return room
}


}

View File

@ -14,7 +14,8 @@ import kotlinx.coroutines.launch

class Synchronizer(private val syncAPI: SyncAPI,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val jsonMapper: Moshi) {
private val jsonMapper: Moshi,
private val syncResponseHandler: SyncResponseHandler) {

fun synchronize(callback: MatrixCallback<SyncResponse>): Cancelable {
val job = GlobalScope.launch(coroutineDispatchers.main) {
@ -27,8 +28,11 @@ class Synchronizer(private val syncAPI: SyncAPI,
apiCall = syncAPI.sync(params)
moshi = jsonMapper
dispatcher = coroutineDispatchers.io
}.map {
syncResponseHandler.handleResponse(it, null, false)
it
}
syncResponse.either({ callback.onFailure(it) }, { callback.onSuccess(it) })
syncResponse.bimap({ callback.onFailure(it) }, { callback.onSuccess(it) })
}
return CancelableCoroutine(job)
}

View File

@ -1,9 +1,10 @@
package im.vector.matrix.android.internal.events.sync.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class DeviceOneTimeKeysCountSyncResponse(
val signed_curve25519: Int? = null
@Json(name = "signed_curve25519") val signedCurve25519: Int? = null

)

View File

@ -0,0 +1,17 @@
package im.vector.matrix.android.internal.events.sync.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class GroupSyncProfile(
/**
* The name of the group, if any. May be nil.
*/
@Json(name = "name") var name: String? = null,

/**
* The URL for the group's avatar. May be nil.
*/
@Json(name = "avatar_url") var avatarUrl: String? = null
)

View File

@ -0,0 +1,22 @@
package im.vector.matrix.android.internal.events.sync.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class GroupsSyncResponse(
/**
* Joined groups: An array of groups ids.
*/
@Json(name = "join") val join: Map<String, Any> = emptyMap(),

/**
* Invitations. The groups that the user has been invited to: keys are groups ids.
*/
@Json(name = "invite") val invite: Map<String, InvitedGroupSync> = emptyMap(),

/**
* Left groups. An array of groups ids: the groups that the user has left or been banned from.
*/
@Json(name = "leave") val leave: Map<String, Any> = emptyMap()
)

View File

@ -0,0 +1,17 @@
package im.vector.matrix.android.internal.events.sync.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class InvitedGroupSync(
/**
* The identifier of the inviter.
*/
@Json(name = "inviter") val inviter: String? = null,

/**
* The group profile.
*/
@Json(name = "profile") val profile: GroupSyncProfile? = null
)

View File

@ -2,11 +2,11 @@ package im.vector.matrix.android.internal.events.sync.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.legacy.rest.model.group.GroupsSyncResponse

// SyncResponse represents the request response for server sync v2.
@JsonClass(generateAdapter = true)
data class SyncResponse(

/**
* The user private data.
*/
@ -40,6 +40,13 @@ data class SyncResponse(
/**
* One time keys management
*/
@Json(name = "device_one_time_keys_count") val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null
@Json(name = "device_one_time_keys_count") val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null,


/**
* List of groups.
*/
@Json(name = "groups") val groups: GroupsSyncResponse? = null


)

View File

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

package im.vector.matrix.android.internal.legacy;

import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.ssl.Fingerprint;

import java.util.ArrayList;
import java.util.List;

import okhttp3.CipherSuite;
import okhttp3.TlsVersion;

/**
* Represents how to connect to a specific Homeserver, may include credentials to use.
*/
public class HomeServerConnectionConfig {

// the home server URI
private Uri mHsUri;
// the identity server URI
private Uri mIdentityServerUri;
// the anti-virus server URI
private Uri mAntiVirusServerUri;
// allowed fingerprints
private List<Fingerprint> mAllowedFingerprints = new ArrayList<>();
// the credentials
private Credentials mCredentials;
// tell whether we should reject X509 certs that were issued by trusts CAs and only trustcerts with matching fingerprints.
private boolean mPin;
// the accepted TLS versions
private List<TlsVersion> mTlsVersions;
// the accepted TLS cipher suites
private List<CipherSuite> mTlsCipherSuites;
// should accept TLS extensions
private boolean mShouldAcceptTlsExtensions = true;
// allow Http connection
private boolean mAllowHttpExtension;
// Force usage of TLS versions
private boolean mForceUsageTlsVersions;

/**
* Private constructor. Please use the Builder
*/
private HomeServerConnectionConfig() {
// Private constructor
}

/**
* Update the home server URI.
*
* @param uri the new HS uri
*/
public void setHomeserverUri(Uri uri) {
mHsUri = uri;
}

/**
* @return the home server uri
*/
public Uri getHomeserverUri() {
return mHsUri;
}

/**
* @return the identity server uri
*/
public Uri getIdentityServerUri() {
if (null != mIdentityServerUri) {
return mIdentityServerUri;
}
// Else consider the HS uri by default.
return mHsUri;
}

/**
* @return the anti-virus server uri
*/
public Uri getAntiVirusServerUri() {
if (null != mAntiVirusServerUri) {
return mAntiVirusServerUri;
}
// Else consider the HS uri by default.
return mHsUri;
}

/**
* @return the allowed fingerprints.
*/
public List<Fingerprint> getAllowedFingerprints() {
return mAllowedFingerprints;
}

/**
* @return the credentials
*/
public Credentials getCredentials() {
return mCredentials;
}

/**
* Update the credentials.
*
* @param credentials the new credentials
*/
public void setCredentials(Credentials credentials) {
mCredentials = credentials;
}

/**
* @return whether we should reject X509 certs that were issued by trusts CAs and only trust
* certs with matching fingerprints.
*/
public boolean shouldPin() {
return mPin;
}

/**
* TLS versions accepted for TLS connections with the home server.
*/
@Nullable
public List<TlsVersion> getAcceptedTlsVersions() {
return mTlsVersions;
}

/**
* TLS cipher suites accepted for TLS connections with the home server.
*/
@Nullable
public List<CipherSuite> getAcceptedTlsCipherSuites() {
return mTlsCipherSuites;
}

/**
* @return whether we should accept TLS extensions.
*/
public boolean shouldAcceptTlsExtensions() {
return mShouldAcceptTlsExtensions;
}

/**
* @return true if Http connection is allowed (false by default).
*/
public boolean isHttpConnectionAllowed() {
return mAllowHttpExtension;
}

/**
* @return true if the usage of TlsVersions has to be forced
*/
public boolean forceUsageOfTlsVersions() {
return mForceUsageTlsVersions;
}

@Override
public String toString() {
return "HomeserverConnectionConfig{" +
"mHsUri=" + mHsUri +
", mIdentityServerUri=" + mIdentityServerUri +
", mAntiVirusServerUri=" + mAntiVirusServerUri +
", mAllowedFingerprints size=" + mAllowedFingerprints.size() +
", mCredentials=" + mCredentials +
", mPin=" + mPin +
", mShouldAcceptTlsExtensions=" + mShouldAcceptTlsExtensions +
", mTlsVersions=" + (null == mTlsVersions ? "" : mTlsVersions.size()) +
", mTlsCipherSuites=" + (null == mTlsCipherSuites ? "" : mTlsCipherSuites.size()) +
'}';
}

/**
* Convert the object instance into a JSon object
*
* @return the JSon representation
* @throws JSONException the JSON conversion failure reason
*/
public JSONObject toJson() throws JSONException {
JSONObject json = new JSONObject();

json.put("home_server_url", mHsUri.toString());
json.put("identity_server_url", getIdentityServerUri().toString());
if (mAntiVirusServerUri != null) {
json.put("antivirus_server_url", mAntiVirusServerUri.toString());
}

json.put("pin", mPin);

if (mCredentials != null) json.put("credentials", mCredentials.toJson());
if (mAllowedFingerprints != null) {
List<JSONObject> fingerprints = new ArrayList<>(mAllowedFingerprints.size());

for (Fingerprint fingerprint : mAllowedFingerprints) {
fingerprints.add(fingerprint.toJson());
}

json.put("fingerprints", new JSONArray(fingerprints));
}

json.put("tls_extensions", mShouldAcceptTlsExtensions);

if (mTlsVersions != null) {
List<String> tlsVersions = new ArrayList<>(mTlsVersions.size());

for (TlsVersion tlsVersion : mTlsVersions) {
tlsVersions.add(tlsVersion.javaName());
}

json.put("tls_versions", new JSONArray(tlsVersions));
}

json.put("force_usage_of_tls_versions", mForceUsageTlsVersions);

if (mTlsCipherSuites != null) {
List<String> tlsCipherSuites = new ArrayList<>(mTlsCipherSuites.size());

for (CipherSuite tlsCipherSuite : mTlsCipherSuites) {
tlsCipherSuites.add(tlsCipherSuite.javaName());
}

json.put("tls_cipher_suites", new JSONArray(tlsCipherSuites));
}

return json;
}

/**
* Create an object instance from the json object.
*
* @param jsonObject the json object
* @return a HomeServerConnectionConfig instance
* @throws JSONException the conversion failure reason
*/
public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws JSONException {
JSONArray fingerprintArray = jsonObject.optJSONArray("fingerprints");
List<Fingerprint> fingerprints = new ArrayList<>();
if (fingerprintArray != null) {
for (int i = 0; i < fingerprintArray.length(); i++) {
fingerprints.add(Fingerprint.fromJson(fingerprintArray.getJSONObject(i)));
}
}

JSONObject credentialsObj = jsonObject.optJSONObject("credentials");
Credentials creds = credentialsObj != null ? Credentials.fromJson(credentialsObj) : null;

Builder builder = new Builder()
.withHomeServerUri(Uri.parse(jsonObject.getString("home_server_url")))
.withIdentityServerUri(jsonObject.has("identity_server_url") ? Uri.parse(jsonObject.getString("identity_server_url")) : null)
.withCredentials(creds)
.withAllowedFingerPrints(fingerprints)
.withPin(jsonObject.optBoolean("pin", false));

// Set the anti-virus server uri if any
if (jsonObject.has("antivirus_server_url")) {
builder.withAntiVirusServerUri(Uri.parse(jsonObject.getString("antivirus_server_url")));
}

builder.withShouldAcceptTlsExtensions(jsonObject.optBoolean("tls_extensions", true));

// Set the TLS versions if any
if (jsonObject.has("tls_versions")) {
JSONArray tlsVersionsArray = jsonObject.optJSONArray("tls_versions");
if (tlsVersionsArray != null) {
for (int i = 0; i < tlsVersionsArray.length(); i++) {
builder.addAcceptedTlsVersion(TlsVersion.forJavaName(tlsVersionsArray.getString(i)));
}
}
}

builder.forceUsageOfTlsVersions(jsonObject.optBoolean("force_usage_of_tls_versions", false));

// Set the TLS cipher suites if any
if (jsonObject.has("tls_cipher_suites")) {
JSONArray tlsCipherSuitesArray = jsonObject.optJSONArray("tls_cipher_suites");
if (tlsCipherSuitesArray != null) {
for (int i = 0; i < tlsCipherSuitesArray.length(); i++) {
builder.addAcceptedTlsCipherSuite(CipherSuite.forJavaName(tlsCipherSuitesArray.getString(i)));
}
}
}

return builder.build();
}

/**
* Builder
*/
public static class Builder {
private HomeServerConnectionConfig mHomeServerConnectionConfig;

/**
* Builder constructor
*/
public Builder() {
mHomeServerConnectionConfig = new HomeServerConnectionConfig();
}

/**
* @param hsUri The URI to use to connect to the homeserver. Cannot be null
* @return this builder
*/
public Builder withHomeServerUri(final Uri hsUri) {
if (hsUri == null || (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme()))) {
throw new RuntimeException("Invalid home server URI: " + hsUri);
}

// remove trailing /
if (hsUri.toString().endsWith("/")) {
try {
String url = hsUri.toString();
mHomeServerConnectionConfig.mHsUri = Uri.parse(url.substring(0, url.length() - 1));
} catch (Exception e) {
throw new RuntimeException("Invalid home server URI: " + hsUri);
}
} else {
mHomeServerConnectionConfig.mHsUri = hsUri;
}

return this;
}

/**
* @param identityServerUri The URI to use to manage identity. Can be null
* @return this builder
*/
public Builder withIdentityServerUri(@Nullable final Uri identityServerUri) {
if ((null != identityServerUri) && (!"http".equals(identityServerUri.getScheme()) && !"https".equals(identityServerUri.getScheme()))) {
throw new RuntimeException("Invalid identity server URI: " + identityServerUri);
}

// remove trailing /
if ((null != identityServerUri) && identityServerUri.toString().endsWith("/")) {
try {
String url = identityServerUri.toString();
mHomeServerConnectionConfig.mIdentityServerUri = Uri.parse(url.substring(0, url.length() - 1));
} catch (Exception e) {
throw new RuntimeException("Invalid identity server URI: " + identityServerUri);
}
} else {
mHomeServerConnectionConfig.mIdentityServerUri = identityServerUri;
}

return this;
}

/**
* @param credentials The credentials to use, if needed. Can be null.
* @return this builder
*/
public Builder withCredentials(@Nullable Credentials credentials) {
mHomeServerConnectionConfig.mCredentials = credentials;
return this;
}

/**
* @param allowedFingerprints If using SSL, allow server certs that match these fingerprints.
* @return this builder
*/
public Builder withAllowedFingerPrints(@Nullable List<Fingerprint> allowedFingerprints) {
if (allowedFingerprints != null) {
mHomeServerConnectionConfig.mAllowedFingerprints.addAll(allowedFingerprints);
}

return this;
}

/**
* @param pin If true only allow certs matching given fingerprints, otherwise fallback to
* standard X509 checks.
* @return this builder
*/
public Builder withPin(boolean pin) {
mHomeServerConnectionConfig.mPin = pin;

return this;
}

/**
* @param shouldAcceptTlsExtension
* @return this builder
*/
public Builder withShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtension) {
mHomeServerConnectionConfig.mShouldAcceptTlsExtensions = shouldAcceptTlsExtension;

return this;
}

/**
* Add an accepted TLS version for TLS connections with the home server.
*
* @param tlsVersion the tls version to add to the set of TLS versions accepted.
* @return this builder
*/
public Builder addAcceptedTlsVersion(@NonNull TlsVersion tlsVersion) {
if (mHomeServerConnectionConfig.mTlsVersions == null) {
mHomeServerConnectionConfig.mTlsVersions = new ArrayList<>();
}

mHomeServerConnectionConfig.mTlsVersions.add(tlsVersion);

return this;
}

/**
* Force the usage of TlsVersion. This can be usefull for device on Android version < 20
*
* @param forceUsageOfTlsVersions set to true to force the usage of specified TlsVersions (with {@link #addAcceptedTlsVersion(TlsVersion)}
* @return this builder
*/
public Builder forceUsageOfTlsVersions(boolean forceUsageOfTlsVersions) {
mHomeServerConnectionConfig.mForceUsageTlsVersions = forceUsageOfTlsVersions;

return this;
}

/**
* Add a TLS cipher suite to the list of accepted TLS connections with the home server.
*
* @param tlsCipherSuite the tls cipher suite to add.
* @return this builder
*/
public Builder addAcceptedTlsCipherSuite(@NonNull CipherSuite tlsCipherSuite) {
if (mHomeServerConnectionConfig.mTlsCipherSuites == null) {
mHomeServerConnectionConfig.mTlsCipherSuites = new ArrayList<>();
}

mHomeServerConnectionConfig.mTlsCipherSuites.add(tlsCipherSuite);

return this;
}

/**
* Update the anti-virus server URI.
*
* @param antivirusServerUri the new anti-virus uri. Can be null
* @return this builder
*/
public Builder withAntiVirusServerUri(@Nullable Uri antivirusServerUri) {
if ((null != antivirusServerUri) && (!"http".equals(antivirusServerUri.getScheme()) && !"https".equals(antivirusServerUri.getScheme()))) {
throw new RuntimeException("Invalid antivirus server URI: " + antivirusServerUri);
}

mHomeServerConnectionConfig.mAntiVirusServerUri = antivirusServerUri;

return this;
}

/**
* For test only: allow Http connection
*/
@VisibleForTesting
public Builder withAllowHttpConnection() {
mHomeServerConnectionConfig.mAllowHttpExtension = true;
return this;
}

/**
* Convenient method to limit the TLS versions and cipher suites for this Builder
* Ref:
* - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf
* - https://developer.android.com/reference/javax/net/ssl/SSLEngine
*
* @param tlsLimitations true to use Tls limitations
* @param enableCompatibilityMode set to true for Android < 20
* @return this builder
*/
public Builder withTlsLimitations(boolean tlsLimitations, boolean enableCompatibilityMode) {
if (tlsLimitations) {
withShouldAcceptTlsExtensions(false);

// Tls versions
addAcceptedTlsVersion(TlsVersion.TLS_1_2);
addAcceptedTlsVersion(TlsVersion.TLS_1_3);

forceUsageOfTlsVersions(enableCompatibilityMode);

// Cipher suites
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);

if (enableCompatibilityMode) {
// Adopt some preceding cipher suites for Android < 20 to be able to negotiate
// a TLS session.
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
}
}

return this;
}

/**
* @return the {@link HomeServerConnectionConfig}
*/
public HomeServerConnectionConfig build() {
// Check mandatory parameters
if (mHomeServerConnectionConfig.mHsUri == null) {
throw new RuntimeException("Home server URI not set");
}

return mHomeServerConnectionConfig;
}

}
}

View File

@ -25,6 +25,7 @@ import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonElement;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.call.MXCallsManager;
import im.vector.matrix.android.internal.legacy.crypto.MXCrypto;
import im.vector.matrix.android.internal.legacy.crypto.MXCryptoError;
@ -62,13 +63,12 @@ import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule;
import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRuleSet;
import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse;
import im.vector.matrix.android.internal.legacy.rest.model.group.InvitedGroupSync;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.rest.model.sync.InvitedRoomSync;
import im.vector.matrix.android.internal.legacy.rest.model.sync.SyncResponse;
import im.vector.matrix.android.internal.legacy.ssl.UnrecognizedCertificateException;
import im.vector.matrix.android.internal.legacy.util.BingRulesManager;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException;

import java.util.ArrayList;
import java.util.Collection;
@ -173,7 +173,7 @@ public class MXDataHandler {
* Default constructor.
*
* @param store the data storage implementation.
* @param credentials the credentials
* @param credentials the getCredentials
*/
public MXDataHandler(IMXStore store, Credentials credentials) {
mStore = store;
@ -208,8 +208,12 @@ public class MXDataHandler {
mMetricsListener = metricsListener;
}

public GroupsManager getGroupsManager() {
return mGroupsManager;
}

/**
* @return the credentials
* @return the getCredentials
*/
public Credentials getCredentials() {
return mCredentials;
@ -426,7 +430,7 @@ public class MXDataHandler {
// MyUser is initialized as late as possible to have a better chance at having the info in storage,
// which should be the case if this is called after the initial sync
if (mMyUser == null) {
mMyUser = new MyUser(store.getUser(mCredentials.userId));
mMyUser = new MyUser(store.getUser(mCredentials.getUserId()));
mMyUser.setDataHandler(this);

// assume the profile is not yet initialized
@ -441,7 +445,7 @@ public class MXDataHandler {
}

// Handle the case where the user is null by loading the user information from the server
mMyUser.user_id = mCredentials.userId;
mMyUser.user_id = mCredentials.getUserId();
} else if (null != store) {
// assume the profile is not yet initialized
if ((null == store.displayName()) && (null != mMyUser.displayname)) {
@ -634,7 +638,7 @@ public class MXDataHandler {
*/
public String getUserId() {
if (isAlive()) {
return mCredentials.userId;
return mCredentials.getUserId();
} else {
return "dummy";
}
@ -934,7 +938,7 @@ public class MXDataHandler {

RoomSummary summary = mStore.getSummary(event.roomId);
if (null == summary) {
summary = new RoomSummary(null, lastEvent, beforeLiveRoomState, mCredentials.userId);
summary = new RoomSummary(null, lastEvent, beforeLiveRoomState, mCredentials.getUserId());
} else {
summary.setLatestReceivedEvent(lastEvent, beforeLiveRoomState);
}
@ -1069,7 +1073,7 @@ public class MXDataHandler {
* @param events the account data events list.
* @return the ignored users list. null means that there is no defined user ids list.
*/
private List<String> ignoredUsers(List<Map<String, Object>> events) {
public List<String> ignoredUsers(List<Map<String, Object>> events) {
List<String> ignoredUsers = null;

if (0 != events.size()) {
@ -1212,7 +1216,7 @@ public class MXDataHandler {
user.setLatestPresenceTs(System.currentTimeMillis());

// check if the current user has been updated
if (mCredentials.userId.equals(user.user_id)) {
if (mCredentials.getUserId().equals(user.user_id)) {
// always use the up-to-date information
getMyUser().displayname = user.displayname;
getMyUser().avatar_url = user.getAvatarUrl();
@ -1420,7 +1424,7 @@ public class MXDataHandler {

if (hasChanged) {
// Update account data to add new direct chat room(s)
mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES,
mAccountDataRestClient.setAccountData(mCredentials.getUserId(), AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES,
updatedDirectChatRoomsDict, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
@ -1532,10 +1536,6 @@ public class MXDataHandler {
}
}

if (null != mCrypto) {
mCrypto.onSyncCompleted(syncResponse, fromToken, isCatchingUp);
}

IMXStore store = getStore();

if (!isEmptyResponse && (null != store)) {
@ -1890,7 +1890,7 @@ public class MXDataHandler {
/**
* Start the crypto
*/
private void startCrypto(final boolean isInitialSync) {
public void startCrypto(final boolean isInitialSync) {
if ((null != getCrypto()) && !getCrypto().isStarted() && !getCrypto().isStarting()) {
getCrypto().setNetworkConnectivityReceiver(mNetworkConnectivityReceiver);
getCrypto().start(isInitialSync, new ApiCallback<Void>() {

View File

@ -30,8 +30,24 @@ import android.text.TextUtils;

import com.google.gson.JsonObject;

import im.vector.matrix.android.BuildConfig;
import im.vector.matrix.android.R;
import org.matrix.olm.OlmManager;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.call.MXCallsManager;
import im.vector.matrix.android.internal.legacy.crypto.MXCrypto;
import im.vector.matrix.android.internal.legacy.crypto.MXCryptoConfig;
@ -79,7 +95,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.Versions;
import im.vector.matrix.android.internal.legacy.rest.model.bingrules.BingRule;
import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody;
import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterResponse;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlow;
import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationFlowResponse;
import im.vector.matrix.android.internal.legacy.rest.model.message.MediaMessage;
@ -101,21 +116,6 @@ import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.legacy.util.UnsentEventsManager;
import im.vector.matrix.android.internal.legacy.util.VersionsUtil;
import org.matrix.olm.OlmManager;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
* Class that represents one user's session with a particular home server.
@ -192,38 +192,38 @@ public class MXSession {
/**
* Create a basic session for direct API calls.
*
* @param hsConfig the home server connection config
* @param sessionParams the session connection data
*/
private MXSession(HomeServerConnectionConfig hsConfig) {
mCredentials = hsConfig.getCredentials();
mHsConfig = hsConfig;
private MXSession(final SessionParams sessionParams) {
mCredentials = sessionParams.getCredentials();
mHsConfig = sessionParams.getHomeServerConnectionConfig();

mEventsRestClient = new EventsRestClient(hsConfig);
mProfileRestClient = new ProfileRestClient(hsConfig);
mPresenceRestClient = new PresenceRestClient(hsConfig);
mRoomsRestClient = new RoomsRestClient(hsConfig);
mPushRulesRestClient = new PushRulesRestClient(hsConfig);
mPushersRestClient = new PushersRestClient(hsConfig);
mThirdPidRestClient = new ThirdPidRestClient(hsConfig);
mCallRestClient = new CallRestClient(hsConfig);
mAccountDataRestClient = new AccountDataRestClient(hsConfig);
mCryptoRestClient = new CryptoRestClient(hsConfig);
mLoginRestClient = new LoginRestClient(hsConfig);
mGroupsRestClient = new GroupsRestClient(hsConfig);
mMediaScanRestClient = new MediaScanRestClient(hsConfig);
mFilterRestClient = new FilterRestClient(hsConfig);
mEventsRestClient = new EventsRestClient(sessionParams);
mProfileRestClient = new ProfileRestClient(sessionParams);
mPresenceRestClient = new PresenceRestClient(sessionParams);
mRoomsRestClient = new RoomsRestClient(sessionParams);
mPushRulesRestClient = new PushRulesRestClient(sessionParams);
mPushersRestClient = new PushersRestClient(sessionParams);
mThirdPidRestClient = new ThirdPidRestClient(sessionParams);
mCallRestClient = new CallRestClient(sessionParams);
mAccountDataRestClient = new AccountDataRestClient(sessionParams);
mCryptoRestClient = new CryptoRestClient(sessionParams);
mLoginRestClient = new LoginRestClient(sessionParams);
mGroupsRestClient = new GroupsRestClient(sessionParams);
mMediaScanRestClient = new MediaScanRestClient(sessionParams);
mFilterRestClient = new FilterRestClient(sessionParams);
}

/**
* Create a user session with a data handler.
* Private, please use the MxSession.Builder now
*
* @param hsConfig the home server connection config
* @param dataHandler the data handler
* @param appContext the application context
* @param sessionParams the session connection data
* @param dataHandler the data handler
* @param appContext the application context
*/
private MXSession(HomeServerConnectionConfig hsConfig, MXDataHandler dataHandler, Context appContext) {
this(hsConfig);
private MXSession(final SessionParams sessionParams, MXDataHandler dataHandler, Context appContext) {
this(sessionParams);
mDataHandler = dataHandler;

mDataHandler.getStore().addMXStoreListener(new MXStoreListener() {
@ -300,7 +300,7 @@ public class MXSession {

mUnsentEventsManager = new UnsentEventsManager(mNetworkConnectivityReceiver, mDataHandler);

mContentManager = new ContentManager(hsConfig, mUnsentEventsManager);
mContentManager = new ContentManager(mHsConfig, mCredentials, mUnsentEventsManager);

//
mCallsManager = new MXCallsManager(this, mAppContent);
@ -321,8 +321,8 @@ public class MXSession {
mGroupsRestClient.setUnsentEventsManager(mUnsentEventsManager);

// return the default cache manager
mLatestChatMessageCache = new MXLatestChatMessageCache(mCredentials.userId);
mMediasCache = new MXMediasCache(mContentManager, mNetworkConnectivityReceiver, mCredentials.userId, appContext);
mLatestChatMessageCache = new MXLatestChatMessageCache(mCredentials.getUserId());
mMediasCache = new MXMediasCache(mContentManager, mNetworkConnectivityReceiver, mCredentials.getUserId(), appContext);
mDataHandler.setMediasCache(mMediasCache);

mMediaScanRestClient.setMxStore(mDataHandler.getStore());
@ -380,9 +380,9 @@ public class MXSession {
}

/**
* Get the user credentials.
* Get the user getCredentials.
*
* @return the credentials
* @return the getCredentials
*/
public Credentials getCredentials() {
checkIfAlive();
@ -842,7 +842,7 @@ public class MXSession {
mEventsThread.setFailureCallback(mFailureCallback);
}

if (mCredentials.accessToken != null && !mEventsThread.isAlive()) {
if (mCredentials.getAccessToken() != null && !mEventsThread.isAlive()) {
// GA issue
try {
mEventsThread.start();
@ -860,35 +860,6 @@ public class MXSession {
}
}

/**
* Refresh the access token
*/
public void refreshToken() {
checkIfAlive();

mProfileRestClient.refreshTokens(new ApiCallback<Credentials>() {
@Override
public void onSuccess(Credentials info) {
Log.d(LOG_TAG, "refreshToken : succeeds.");
}

@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "refreshToken : onNetworkError " + e.getMessage(), e);
}

@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "refreshToken : onMatrixError " + e.getMessage());
}

@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "refreshToken : onMatrixError " + e.getMessage(), e);
}
});
}

/**
* Update the online status
*
@ -1246,7 +1217,7 @@ public class MXSession {

params.addCryptoAlgorithm(algorithm);
params.setDirectMessage();
params.addParticipantIds(mHsConfig, Arrays.asList(aParticipantUserId));
params.addParticipantIds(mHsConfig, mCredentials, Arrays.asList(aParticipantUserId));

createRoom(params, aCreateRoomCallBack);
}
@ -2436,7 +2407,7 @@ public class MXSession {
DeleteDeviceParams params = new DeleteDeviceParams();
params.auth = new DeleteDeviceAuth();
params.auth.session = registrationFlowResponse.session;
params.auth.user = mCredentials.userId;
params.auth.user = mCredentials.getUserId();
params.auth.password = password;

Log.d(LOG_TAG, "## deleteDevice() : supported stages " + stages);
@ -2512,10 +2483,12 @@ public class MXSession {
* ========================================================================================== */

public static class Builder {
private MXSession mxSession;

public Builder(HomeServerConnectionConfig hsConfig, MXDataHandler dataHandler, Context context) {
mxSession = new MXSession(hsConfig, dataHandler, context);
private MXSession mxSession;
private SessionParams sessionParams;

public Builder(SessionParams sessionParams, MXDataHandler dataHandler, Context context) {
mxSession = new MXSession(sessionParams, dataHandler, context);
}

public Builder withFileEncryption(boolean enableFileEncryption) {
@ -2538,9 +2511,8 @@ public class MXSession {
try {
HomeServerConnectionConfig alteredHsConfig = new HomeServerConnectionConfig.Builder()
.withHomeServerUri(Uri.parse(pushServerUrl))
.withCredentials(mxSession.mHsConfig.getCredentials())
.build();
pushersRestClient = new PushersRestClient(alteredHsConfig);
pushersRestClient = new PushersRestClient(new SessionParams(sessionParams.getCredentials(), alteredHsConfig));
} catch (Exception e) {
Log.e(LOG_TAG, "## withPushServerUrl() failed " + e.getMessage(), e);
}
@ -2562,7 +2534,6 @@ public class MXSession {
*/
public Builder withMetricsListener(@Nullable MetricsListener metricsListener) {
mxSession.mMetricsListener = metricsListener;

return this;
}


View File

@ -36,15 +36,16 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import im.vector.matrix.android.BuildConfig;
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener;
import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver;
import im.vector.matrix.android.internal.legacy.rest.client.MXRestExecutorService;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.ssl.CertUtil;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.legacy.util.PolymorphicRequestBodyConverter;
import im.vector.matrix.android.internal.legacy.util.UnsentEventsManager;
import im.vector.matrix.android.internal.network.ssl.CertUtil;
import okhttp3.Dispatcher;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
@ -53,12 +54,12 @@ import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import timber.log.Timber;

/**
* Class for making Matrix API calls.
*/
public class RestClient<T> {
private static final String LOG_TAG = RestClient.class.getSimpleName();

public static final String URI_API_PREFIX_PATH_MEDIA_R0 = "_matrix/media/r0/";
public static final String URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE = "_matrix/media_proxy/unstable/";
@ -103,38 +104,37 @@ public class RestClient<T> {
// http client
private OkHttpClient mOkHttpClient = new OkHttpClient();

public RestClient(HomeServerConnectionConfig hsConfig, Class<T> type, String uriPrefix, boolean withNullSerialization) {
this(hsConfig, type, uriPrefix, withNullSerialization, EndPointServer.HOME_SERVER);
public RestClient(SessionParams sessionParams, Class<T> type, String uriPrefix, boolean withNullSerialization) {
this(sessionParams, type, uriPrefix, withNullSerialization, EndPointServer.HOME_SERVER);
}

/**
* Public constructor.
*
* @param hsConfig the home server configuration.
* @param sessionParams the session data
* @param type the REST type
* @param uriPrefix the URL request prefix
* @param withNullSerialization true to serialise class member with null value
* @param useIdentityServer true to use the identity server URL as base request
*/
public RestClient(HomeServerConnectionConfig hsConfig, Class<T> type, String uriPrefix, boolean withNullSerialization, boolean useIdentityServer) {
this(hsConfig, type, uriPrefix, withNullSerialization, useIdentityServer ? EndPointServer.IDENTITY_SERVER : EndPointServer.HOME_SERVER);
public RestClient(SessionParams sessionParams, Class<T> type, String uriPrefix, boolean withNullSerialization, boolean useIdentityServer) {
this(sessionParams, type, uriPrefix, withNullSerialization, useIdentityServer ? EndPointServer.IDENTITY_SERVER : EndPointServer.HOME_SERVER);
}

/**
* Public constructor.
*
* @param hsConfig the home server configuration.
* @param sessionParams the session data
* @param type the REST type
* @param uriPrefix the URL request prefix
* @param withNullSerialization true to serialise class member with null value
* @param endPointServer tell which server is used to define the base url
*/
public RestClient(HomeServerConnectionConfig hsConfig, Class<T> type, String uriPrefix, boolean withNullSerialization, EndPointServer endPointServer) {
public RestClient(SessionParams sessionParams, Class<T> type, String uriPrefix, boolean withNullSerialization, EndPointServer endPointServer) {
// The JSON -> object mapper
gson = JsonUtils.getGson(withNullSerialization);

mHsConfig = hsConfig;
mCredentials = hsConfig.getCredentials();
mHsConfig = sessionParams.getHomeServerConnectionConfig();
mCredentials = sessionParams.getCredentials();

Interceptor authentInterceptor = new Interceptor() {

@ -146,12 +146,10 @@ public class RestClient<T> {
// set a custom user agent
newRequestBuilder.addHeader("User-Agent", sUserAgent);
}

// Add the access token to all requests if it is set
if ((mCredentials != null) && (mCredentials.accessToken != null)) {
newRequestBuilder.addHeader("Authorization", "Bearer " + mCredentials.accessToken);
if (mCredentials != null) {
newRequestBuilder.addHeader("Authorization", "Bearer " + mCredentials.getAccessToken());
}

request = newRequestBuilder.build();

return chain.proceed(request);
@ -191,17 +189,15 @@ public class RestClient<T> {
}

try {
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.newPinnedSSLSocketFactory(hsConfig);
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mHsConfig);
okHttpClientBuilder.sslSocketFactory(pair.first, pair.second);
okHttpClientBuilder.hostnameVerifier(CertUtil.newHostnameVerifier(hsConfig));
okHttpClientBuilder.connectionSpecs(CertUtil.newConnectionSpecs(hsConfig));
okHttpClientBuilder.hostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mHsConfig));
okHttpClientBuilder.connectionSpecs(CertUtil.INSTANCE.newConnectionSpecs(mHsConfig));
} catch (Exception e) {
Log.e(LOG_TAG, "## RestClient() setSslSocketFactory failed" + e.getMessage(), e);
Timber.e("## RestClient() setSslSocketFactory failed" + e.getMessage(), e);
}

mOkHttpClient = okHttpClientBuilder.build();
final String endPoint = makeEndpoint(hsConfig, uriPrefix, endPointServer);

final String endPoint = makeEndpoint(mHsConfig, uriPrefix, endPointServer);
// Rest adapter for turning API interfaces into actual REST-calling objects
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(endPoint)
@ -226,9 +222,12 @@ public class RestClient<T> {
break;
case HOME_SERVER:
default:
baseUrl = hsConfig.getHomeserverUri().toString();
baseUrl = hsConfig.getHomeServerUri().toString();

}
if (baseUrl == null) {
throw new IllegalArgumentException("Base url shouldn't be null");
}
baseUrl = sanitizeBaseUrl(baseUrl);
String dynamicPath = sanitizeDynamicPath(uriPrefix);
return baseUrl + dynamicPath;
@ -270,7 +269,7 @@ public class RestClient<T> {
PackageInfo pkgInfo = pm.getPackageInfo(appContext.getApplicationContext().getPackageName(), 0);
appVersion = pkgInfo.versionName;
} catch (Exception e) {
Log.e(LOG_TAG, "## initUserAgent() : failed " + e.getMessage(), e);
Timber.e("## initUserAgent() : failed " + e.getMessage(), e);
}
}

@ -321,12 +320,12 @@ public class RestClient<T> {
.readTimeout((int) (READ_TIMEOUT_MS * factor), TimeUnit.MILLISECONDS)
.writeTimeout((int) (WRITE_TIMEOUT_MS * factor), TimeUnit.MILLISECONDS);

Log.d(LOG_TAG, "## refreshConnectionTimeout() : update setConnectTimeout to " + (CONNECTION_TIMEOUT_MS * factor) + " ms");
Log.d(LOG_TAG, "## refreshConnectionTimeout() : update setReadTimeout to " + (READ_TIMEOUT_MS * factor) + " ms");
Log.d(LOG_TAG, "## refreshConnectionTimeout() : update setWriteTimeout to " + (WRITE_TIMEOUT_MS * factor) + " ms");
Timber.d("## refreshConnectionTimeout() : update setConnectTimeout to " + (CONNECTION_TIMEOUT_MS * factor) + " ms");
Timber.d("## refreshConnectionTimeout() : update setReadTimeout to " + (READ_TIMEOUT_MS * factor) + " ms");
Timber.d("## refreshConnectionTimeout() : update setWriteTimeout to " + (WRITE_TIMEOUT_MS * factor) + " ms");
} else {
builder.connectTimeout(1, TimeUnit.MILLISECONDS);
Log.d(LOG_TAG, "## refreshConnectionTimeout() : update the requests timeout to 1 ms");
Timber.d("## refreshConnectionTimeout() : update the requests timeout to 1 ms");
}

// FIXME It has no effect to the rest client
@ -373,25 +372,25 @@ public class RestClient<T> {
networkConnectivityReceiver.addEventListener(new IMXNetworkEventListener() {
@Override
public void onNetworkConnectionUpdate(boolean isConnected) {
Log.d(LOG_TAG, "## setUnsentEventsManager() : update the requests timeout to " + (isConnected ? CONNECTION_TIMEOUT_MS : 1) + " ms");
Timber.d("## setUnsentEventsManager() : update the requests timeout to " + (isConnected ? CONNECTION_TIMEOUT_MS : 1) + " ms");
refreshConnectionTimeout(networkConnectivityReceiver);
}
});
}

/**
* Get the user's credentials. Typically for saving them somewhere persistent.
* Get the user's getCredentials. Typically for saving them somewhere persistent.
*
* @return the user credentials
* @return the user getCredentials
*/
public Credentials getCredentials() {
return mCredentials;
}

/**
* Provide the user's credentials. To be called after login or registration.
* Provide the user's getCredentials. To be called after login or registration.
*
* @param credentials the user credentials
* @param credentials the user getCredentials
*/
public void setCredentials(Credentials credentials) {
mCredentials = credentials;

View File

@ -26,13 +26,6 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

import im.vector.matrix.android.internal.legacy.MXSession;
import im.vector.matrix.android.internal.legacy.data.Room;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.Event;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@ -40,6 +33,13 @@ import java.util.List;
import java.util.Set;
import java.util.Timer;

import im.vector.matrix.android.internal.legacy.MXSession;
import im.vector.matrix.android.internal.legacy.data.Room;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.Event;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.util.Log;

/**
* This class is the default implementation
*/
@ -657,7 +657,7 @@ public class MXCall implements IMXCall {
hangupContent.add("reason", new JsonPrimitive(reason));
}

Event event = new Event(Event.EVENT_TYPE_CALL_HANGUP, hangupContent, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
Event event = new Event(Event.EVENT_TYPE_CALL_HANGUP, hangupContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId());

// local notification to indicate the end of call
mUIThreadHandler.post(new Runnable() {

View File

@ -631,7 +631,7 @@ public class MXChromeCall extends MXCall {
}

if (addIt) {
Event event = new Event(eventType, content, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
Event event = new Event(eventType, content, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId());

if (null != event) {
// receive an hangup -> close the window asap

View File

@ -374,7 +374,7 @@ public class MXWebRtcCall extends MXCall {
offerContent.addProperty("type", sessionDescription.type.canonicalForm());
inviteContent.add("offer", offerContent);

Event event = new Event(Event.EVENT_TYPE_CALL_INVITE, inviteContent, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
Event event = new Event(Event.EVENT_TYPE_CALL_INVITE, inviteContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId());

mPendingEvents.add(event);

@ -434,7 +434,7 @@ public class MXWebRtcCall extends MXCall {
offerContent.addProperty("type", sessionDescription.type.canonicalForm());
answerContent.add("answer", offerContent);

Event event = new Event(Event.EVENT_TYPE_CALL_ANSWER, answerContent, mSession.getCredentials().userId, mCallSignalingRoom.getRoomId());
Event event = new Event(Event.EVENT_TYPE_CALL_ANSWER, answerContent, mSession.getCredentials().getUserId(), mCallSignalingRoom.getRoomId());
mPendingEvents.add(event);
sendNextEvent();

@ -737,7 +737,7 @@ public class MXWebRtcCall extends MXCall {
}

if (addIt) {
Event event = new Event(Event.EVENT_TYPE_CALL_CANDIDATES, content, mSession.getCredentials().userId,
Event event = new Event(Event.EVENT_TYPE_CALL_CANDIDATES, content, mSession.getCredentials().getUserId(),
mCallSignalingRoom.getRoomId());

mPendingEvents.add(event);

View File

@ -207,17 +207,17 @@ public class MXCrypto {
mRoomEncryptors = new HashMap<>();
mRoomDecryptors = new HashMap<>();

String deviceId = mSession.getCredentials().deviceId;
String deviceId = mSession.getCredentials().getDeviceId();
// deviceId should always be defined
boolean refreshDevicesList = !TextUtils.isEmpty(deviceId);

if (TextUtils.isEmpty(deviceId)) {
// use the stored one
mSession.getCredentials().deviceId = deviceId = mCryptoStore.getDeviceId();
deviceId = mCryptoStore.getDeviceId();
}

if (TextUtils.isEmpty(deviceId)) {
mSession.getCredentials().deviceId = deviceId = UUID.randomUUID().toString();
deviceId = UUID.randomUUID().toString();
Log.d(LOG_TAG, "Warning: No device id in MXCredentials. An id was created. Think of storing it");
mCryptoStore.storeDeviceId(deviceId);
}
@ -230,11 +230,11 @@ public class MXCrypto {
Map<String, String> keys = new HashMap<>();

if (!TextUtils.isEmpty(mOlmDevice.getDeviceEd25519Key())) {
keys.put("ed25519:" + mSession.getCredentials().deviceId, mOlmDevice.getDeviceEd25519Key());
keys.put("ed25519:" + mSession.getCredentials().getDeviceId(), mOlmDevice.getDeviceEd25519Key());
}

if (!TextUtils.isEmpty(mOlmDevice.getDeviceCurve25519Key())) {
keys.put("curve25519:" + mSession.getCredentials().deviceId, mOlmDevice.getDeviceCurve25519Key());
keys.put("curve25519:" + mSession.getCredentials().getDeviceId(), mOlmDevice.getDeviceCurve25519Key());
}

mMyDevice.keys = keys;
@ -441,7 +441,7 @@ public class MXCrypto {
if (!hasBeenReleased()) {
Log.d(LOG_TAG, "###########################################################");
Log.d(LOG_TAG, "uploadDeviceKeys done for " + mSession.getMyUserId());
Log.d(LOG_TAG, " - device id : " + mSession.getCredentials().deviceId);
Log.d(LOG_TAG, " - device id : " + mSession.getCredentials().getDeviceId());
Log.d(LOG_TAG, " - ed25519 : " + mOlmDevice.getDeviceEd25519Key());
Log.d(LOG_TAG, " - curve25519 : " + mOlmDevice.getDeviceCurve25519Key());
Log.d(LOG_TAG, " - oneTimeKeys: " + mLastPublishedOneTimeKeys); // They are
@ -600,17 +600,17 @@ public class MXCrypto {
* @param fromToken the start sync token
* @param isCatchingUp true if there is a catch-up in progress.
*/
public void onSyncCompleted(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) {
public void onSyncCompleted(final im.vector.matrix.android.internal.events.sync.data.SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) {
getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
if (null != syncResponse.deviceLists) {
getDeviceList().handleDeviceListsChanges(syncResponse.deviceLists.changed, syncResponse.deviceLists.left);
if (null != syncResponse.getDeviceLists()) {
getDeviceList().handleDeviceListsChanges(syncResponse.getDeviceLists().getChanged(), syncResponse.getDeviceLists().getLeft());
}

if (null != syncResponse.deviceOneTimeKeysCount) {
int currentCount = (null != syncResponse.deviceOneTimeKeysCount.signed_curve25519) ?
syncResponse.deviceOneTimeKeysCount.signed_curve25519 : 0;
if (null != syncResponse.getDeviceOneTimeKeysCount()) {
int currentCount = (null != syncResponse.getDeviceOneTimeKeysCount().getSignedCurve25519()) ?
syncResponse.getDeviceOneTimeKeysCount().getSignedCurve25519() : 0;
updateOneTimeKeyCount(currentCount);
}

@ -1470,7 +1470,7 @@ public class MXCrypto {
Map<String, Object> payloadJson = new HashMap<>(payloadFields);

payloadJson.put("sender", mSession.getMyUserId());
payloadJson.put("sender_device", mSession.getCredentials().deviceId);
payloadJson.put("sender_device", mSession.getCredentials().getDeviceId());

// Include the Ed25519 key so that the recipient knows what
// device this message came from.

View File

@ -22,6 +22,12 @@ import android.text.TextUtils;

import com.google.gson.JsonElement;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import im.vector.matrix.android.internal.legacy.MXSession;
import im.vector.matrix.android.internal.legacy.crypto.MXCrypto;
import im.vector.matrix.android.internal.legacy.crypto.MXCryptoAlgorithms;
@ -39,12 +45,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MXMegolmEncryption implements IMXEncrypting {
private static final String LOG_TAG = MXMegolmEncryption.class.getSimpleName();

@ -76,7 +76,7 @@ public class MXMegolmEncryption implements IMXEncrypting {
mCrypto = matrixSession.getCrypto();

mRoomId = roomId;
mDeviceId = matrixSession.getCredentials().deviceId;
mDeviceId = matrixSession.getCredentials().getDeviceId();

// Default rotation periods
// TODO: Make it configurable via parameters

View File

@ -18,11 +18,11 @@ package im.vector.matrix.android.internal.legacy.data.cryptostore;

import android.content.Context;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.OutgoingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo;
import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import org.matrix.olm.OlmAccount;
import org.matrix.olm.OlmSession;

@ -35,10 +35,10 @@ import java.util.Set;
*/
public interface IMXCryptoStore {
/**
* Init a crypto store for the passed credentials.
* Init a crypto store for the passed getCredentials.
*
* @param context the application context
* @param credentials the credentials of the account.
* @param credentials the getCredentials of the account.
*/
void initWithCredentials(Context context, Credentials credentials);

@ -55,7 +55,7 @@ public interface IMXCryptoStore {
boolean hasData();

/**
* Delete the crypto store for the passed credentials.
* Delete the crypto store for the passed getCredentials.
*/
void deleteStore();


View File

@ -22,16 +22,6 @@ import android.content.Context;
import android.os.Looper;
import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.OutgoingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo;
import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession;
import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2;
import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.util.CompatUtil;
import im.vector.matrix.android.internal.legacy.util.ContentUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import org.matrix.olm.OlmAccount;
import org.matrix.olm.OlmSession;

@ -51,6 +41,17 @@ import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.crypto.IncomingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.OutgoingRoomKeyRequest;
import im.vector.matrix.android.internal.legacy.crypto.data.MXDeviceInfo;
import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession;
import im.vector.matrix.android.internal.legacy.crypto.data.MXOlmInboundGroupSession2;
import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap;
import im.vector.matrix.android.internal.legacy.util.CompatUtil;
import im.vector.matrix.android.internal.legacy.util.ContentUtils;
import im.vector.matrix.android.internal.legacy.util.Log;

/**
* the crypto data store
*/
@ -91,7 +92,7 @@ public class MXFileCryptoStore implements IMXCryptoStore {
private static final String MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE = "incomingRoomKeyRequests";
private static final String MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE_TMP = "incomingRoomKeyRequests.tmp";

// The credentials used for this store
// The getCredentials used for this store
private Credentials mCredentials;

// Meta data about the store
@ -182,7 +183,7 @@ public class MXFileCryptoStore implements IMXCryptoStore {
public void initWithCredentials(Context context, Credentials credentials) {
mCredentials = credentials;

mStoreFile = new File(new File(context.getApplicationContext().getFilesDir(), MXFILE_CRYPTO_STORE_FOLDER), mCredentials.userId);
mStoreFile = new File(new File(context.getApplicationContext().getFilesDir(), MXFILE_CRYPTO_STORE_FOLDER), mCredentials.getUserId());

mMetaDataFile = new File(mStoreFile, MXFILE_CRYPTO_STORE_METADATA_FILE);
mMetaDataFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_METADATA_FILE_TMP);
@ -217,11 +218,8 @@ public class MXFileCryptoStore implements IMXCryptoStore {
mIncomingRoomKeyRequestsFileTmp = new File(mStoreFile, MXFILE_CRYPTO_STORE_INCOMING_ROOM_KEY_REQUESTS_FILE_TMP);

// Build default metadata
if ((null == mMetaData)
&& (null != credentials.homeServer)
&& (null != credentials.userId)
&& (null != credentials.accessToken)) {
mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.userId, mCredentials.deviceId, MXFILE_CRYPTO_VERSION);
if (mMetaData == null) {
mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.getUserId(), mCredentials.getDeviceId(), MXFILE_CRYPTO_VERSION);
}

mUsersDevicesInfoMap = new MXUsersDevicesMap<>();
@ -243,7 +241,7 @@ public class MXFileCryptoStore implements IMXCryptoStore {

if (null != mMetaData) {
result = TextUtils.isEmpty(mMetaData.mDeviceId)
|| TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId);
|| TextUtils.equals(mCredentials.getDeviceId(), mMetaData.mDeviceId);
}
}

@ -284,11 +282,11 @@ public class MXFileCryptoStore implements IMXCryptoStore {
Log.e(LOG_TAG, "## open() : New MXFileCryptoStore version detected");
resetData();
}
// Check credentials
// The device id may not have been provided in credentials.
// Check getCredentials
// The device id may not have been provided in getCredentials.
// Check it only if provided, else trust the stored one.
else if (!TextUtils.equals(mMetaData.mUserId, mCredentials.userId)
|| ((null != mCredentials.deviceId) && !TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId))) {
else if (!TextUtils.equals(mMetaData.mUserId, mCredentials.getUserId())
|| ((null != mCredentials.getDeviceId()) && !TextUtils.equals(mCredentials.getDeviceId(), mMetaData.mDeviceId))) {
Log.e(LOG_TAG, "## open() : Credentials do not match");
resetData();
}
@ -298,12 +296,9 @@ public class MXFileCryptoStore implements IMXCryptoStore {
preloadCryptoData();
}

// Else, if credentials is valid, create and store it
if ((null == mMetaData)
&& (null != mCredentials.homeServer)
&& (null != mCredentials.userId)
&& (null != mCredentials.accessToken)) {
mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.userId, mCredentials.deviceId, MXFILE_CRYPTO_VERSION);
// Else, if getCredentials is valid, create and store it
if (mMetaData == null){
mMetaData = new MXFileCryptoStoreMetaData2(mCredentials.getUserId(), mCredentials.getDeviceId(), MXFILE_CRYPTO_VERSION);
mIsReady = true;
// flush the metadata
saveMetaData();

View File

@ -23,25 +23,6 @@ import android.os.HandlerThread;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.data.Room;
import im.vector.matrix.android.internal.legacy.data.RoomAccountData;
import im.vector.matrix.android.internal.legacy.data.RoomState;
import im.vector.matrix.android.internal.legacy.data.RoomSummary;
import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.Event;
import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData;
import im.vector.matrix.android.internal.legacy.rest.model.RoomMember;
import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents;
import im.vector.matrix.android.internal.legacy.rest.model.User;
import im.vector.matrix.android.internal.legacy.rest.model.group.Group;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier;
import im.vector.matrix.android.internal.legacy.util.CompatUtil;
import im.vector.matrix.android.internal.legacy.util.ContentUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.legacy.util.MXOsHandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -60,6 +41,25 @@ import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.data.Room;
import im.vector.matrix.android.internal.legacy.data.RoomAccountData;
import im.vector.matrix.android.internal.legacy.data.RoomState;
import im.vector.matrix.android.internal.legacy.data.RoomSummary;
import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.Event;
import im.vector.matrix.android.internal.legacy.rest.model.ReceiptData;
import im.vector.matrix.android.internal.legacy.rest.model.RoomMember;
import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents;
import im.vector.matrix.android.internal.legacy.rest.model.User;
import im.vector.matrix.android.internal.legacy.rest.model.group.Group;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier;
import im.vector.matrix.android.internal.legacy.util.CompatUtil;
import im.vector.matrix.android.internal.legacy.util.ContentUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.legacy.util.MXOsHandler;

/**
* An in-file IMXStore.
*/
@ -217,21 +217,21 @@ public class MXFileStore extends MXMemoryStore {
/**
* Constructor
*
* @param hsConfig the expected credentials
* @param credentials the expected getCredentials
* @param enableFileEncryption set to true to enable file encryption.
* @param context the context.
*/
public MXFileStore(HomeServerConnectionConfig hsConfig, boolean enableFileEncryption, Context context) {
public MXFileStore(Credentials credentials, boolean enableFileEncryption, Context context) {
setContext(context);

mEnableFileEncryption = enableFileEncryption;

mIsReady = false;
mCredentials = hsConfig.getCredentials();
mCredentials = credentials;

mHandlerThread = new HandlerThread("MXFileStoreBackgroundThread_" + mCredentials.userId, Thread.MIN_PRIORITY);
mHandlerThread = new HandlerThread("MXFileStoreBackgroundThread_" + mCredentials.getUserId(), Thread.MIN_PRIORITY);

createDirTree(mCredentials.userId);
createDirTree(mCredentials.getUserId());

// updated data
mRoomsToCommitForMessages = new HashSet<>();
@ -260,8 +260,8 @@ public class MXFileStore extends MXMemoryStore {
mFileStoreHandler = new MXOsHandler(mHandlerThread.getLooper());

mMetadata = new MXFileStoreMetaData();
mMetadata.mUserId = mCredentials.userId;
mMetadata.mAccessToken = mCredentials.accessToken;
mMetadata.mUserId = mCredentials.getUserId();
mMetadata.mAccessToken = mCredentials.getAccessToken();
mMetadata.mVersion = MXFILE_VERSION;
mMetaDataHasChanged = true;
saveMetaData();
@ -360,8 +360,8 @@ public class MXFileStore extends MXMemoryStore {

String errorDescription = null;
boolean succeed = (mMetadata.mVersion == MXFILE_VERSION)
&& TextUtils.equals(mMetadata.mUserId, mCredentials.userId)
&& TextUtils.equals(mMetadata.mAccessToken, mCredentials.accessToken);
&& TextUtils.equals(mMetadata.mUserId, mCredentials.getUserId())
&& TextUtils.equals(mMetadata.mAccessToken, mCredentials.getAccessToken());

if (!succeed) {
errorDescription = "Invalid store content";
@ -437,7 +437,7 @@ public class MXFileStore extends MXMemoryStore {
if (null == room) {
succeed = false;
Log.e(LOG_TAG, "loadSummaries : the room " + roomId + " does not exist");
} else if (null == room.getMember(mCredentials.userId)) {
} else if (null == room.getMember(mCredentials.getUserId())) {
//succeed = false;
Log.e(LOG_TAG, "loadSummaries) : a summary exists for the roomId "
+ roomId + " but the user is not anymore a member");
@ -482,8 +482,8 @@ public class MXFileStore extends MXMemoryStore {
// mMetadata should only be null at file store loading
if (null == mMetadata) {
mMetadata = new MXFileStoreMetaData();
mMetadata.mUserId = mCredentials.userId;
mMetadata.mAccessToken = mCredentials.accessToken;
mMetadata.mUserId = mCredentials.getUserId();
mMetadata.mAccessToken = mCredentials.getAccessToken();
mMetaDataHasChanged = true;
} else {
mMetadata.mEventStreamToken = null;
@ -515,7 +515,7 @@ public class MXFileStore extends MXMemoryStore {

// post processing
Log.d(LOG_TAG, "## open() : post processing.");
dispatchPostProcess(mCredentials.userId);
dispatchPostProcess(mCredentials.getUserId());
mIsPostProcessingDone = true;

synchronized (this) {
@ -525,7 +525,7 @@ public class MXFileStore extends MXMemoryStore {

if (!succeed && !mIsNewStorage) {
Log.e(LOG_TAG, "The store is corrupted.");
dispatchOnStoreCorrupted(mCredentials.userId, errorDescription);
dispatchOnStoreCorrupted(mCredentials.getUserId(), errorDescription);
} else {
// extract the room states
mRoomReceiptsToLoad.addAll(listFiles(mStoreRoomsMessagesReceiptsFolderFile.list()));
@ -535,7 +535,7 @@ public class MXFileStore extends MXMemoryStore {
}

Log.d(LOG_TAG, "The store is opened.");
dispatchOnStoreReady(mCredentials.userId);
dispatchOnStoreReady(mCredentials.getUserId());

// load the following items with delay
// theses items are not required to be ready
@ -567,12 +567,12 @@ public class MXFileStore extends MXMemoryStore {
} else {
if (!mIsPostProcessingDone) {
Log.e(LOG_TAG, "## open() : is ready but the post processing was not yet done.");
dispatchPostProcess(mCredentials.userId);
dispatchPostProcess(mCredentials.getUserId());
mIsPostProcessingDone = true;
} else {
Log.e(LOG_TAG, "## open() when ready : the post processing is already done.");
}
dispatchOnStoreReady(mCredentials.userId);
dispatchOnStoreReady(mCredentials.getUserId());
mPreloadTime = System.currentTimeMillis() - fLoadTimeT0;
if (mMetricsListener != null) {
mMetricsListener.onStorePreloaded(mPreloadTime);
@ -662,7 +662,7 @@ public class MXFileStore extends MXMemoryStore {
try {
ContentUtils.deleteDirectory(mStoreFolderFile);
if (init) {
createDirTree(mCredentials.userId);
createDirTree(mCredentials.getUserId());
}
} catch (Exception e) {
Log.e(LOG_TAG, "deleteAllData failed " + e.getMessage(), e);
@ -790,7 +790,7 @@ public class MXFileStore extends MXMemoryStore {

@Override
public void storeUser(User user) {
if (!TextUtils.equals(mCredentials.userId, user.user_id)) {
if (!TextUtils.equals(mCredentials.getUserId(), user.user_id)) {
mUserIdsToCommit.add(user.user_id);
}
super.storeUser(user);

View File

@ -24,6 +24,7 @@ import android.os.Looper;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.MXDataHandler;
import im.vector.matrix.android.internal.legacy.data.Room;
import im.vector.matrix.android.internal.legacy.data.RoomAccountData;
@ -38,7 +39,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.RoomMember;
import im.vector.matrix.android.internal.legacy.rest.model.TokensChunkEvents;
import im.vector.matrix.android.internal.legacy.rest.model.User;
import im.vector.matrix.android.internal.legacy.rest.model.group.Group;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier;
import im.vector.matrix.android.internal.legacy.util.Log;

@ -149,7 +149,7 @@ public class MXMemoryStore implements IMXStore {
/**
* Default constructor
*
* @param credentials the expected credentials
* @param credentials the expected getCredentials
* @param context the context
*/
public MXMemoryStore(Credentials credentials, Context context) {
@ -245,7 +245,7 @@ public class MXMemoryStore implements IMXStore {
*/
@Override
public void setCorrupted(String reason) {
dispatchOnStoreCorrupted(mCredentials.userId, reason);
dispatchOnStoreCorrupted(mCredentials.getUserId(), reason);
}

/**
@ -607,7 +607,7 @@ public class MXMemoryStore implements IMXStore {
*/
@Override
public int eventsCountAfter(String roomId, String eventId) {
return eventsAfter(roomId, eventId, mCredentials.userId, null).size();
return eventsAfter(roomId, eventId, mCredentials.getUserId(), null).size();
}

@Override
@ -1155,7 +1155,7 @@ public class MXMemoryStore implements IMXStore {

synchronized (mReceiptsByRoomIdLock) {
if (mReceiptsByRoomId.containsKey(roomId)) {
String myUserID = mCredentials.userId;
String myUserID = mCredentials.getUserId();

Map<String, ReceiptData> receiptsByUserId = mReceiptsByRoomId.get(roomId);
// copy the user id list to avoid having update while looping
@ -1237,7 +1237,7 @@ public class MXMemoryStore implements IMXStore {
}

// check if the read receipt is not for an already read message
if (TextUtils.equals(receipt.userId, mCredentials.userId)) {
if (TextUtils.equals(receipt.userId, mCredentials.getUserId())) {
synchronized (mReceiptsByRoomIdLock) {
LinkedHashMap<String, Event> eventsMap = mRoomEvents.get(roomId);

@ -1334,7 +1334,7 @@ public class MXMemoryStore implements IMXStore {
for (int index = 0; index < events.size(); index++) {
Event event = events.get(index);

if (TextUtils.equals(event.getSender(), mCredentials.userId) || TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) {
if (TextUtils.equals(event.getSender(), mCredentials.getUserId()) || TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) {
events.remove(index);
index--;
}
@ -1402,10 +1402,10 @@ public class MXMemoryStore implements IMXStore {
if (mReceiptsByRoomId.containsKey(roomId)) {
Map<String, ReceiptData> receiptsByUserId = mReceiptsByRoomId.get(roomId);

if (receiptsByUserId.containsKey(mCredentials.userId)) {
ReceiptData data = receiptsByUserId.get(mCredentials.userId);
if (receiptsByUserId.containsKey(mCredentials.getUserId())) {
ReceiptData data = receiptsByUserId.get(mCredentials.getUserId());

res = eventsAfter(roomId, data.eventId, mCredentials.userId, types);
res = eventsAfter(roomId, data.eventId, mCredentials.getUserId(), types);
}
}
}
@ -1479,7 +1479,7 @@ public class MXMemoryStore implements IMXStore {
List<IMXStoreListener> listeners = getListeners();

for (IMXStoreListener listener : listeners) {
listener.onStoreOOM(mCredentials.userId, e.getMessage());
listener.onStoreOOM(mCredentials.getUserId(), e.getMessage());
}
}


View File

@ -51,7 +51,7 @@ class TimelineEventSaver {

public void storeEvent(@NonNull final Event event) {
final MXDataHandler dataHandler = mRoom.getDataHandler();
final String myUserId = dataHandler.getCredentials().userId;
final String myUserId = dataHandler.getCredentials().getUserId();

// create dummy read receipt for any incoming event
// to avoid not synchronized read receipt and event

View File

@ -19,6 +19,11 @@ package im.vector.matrix.android.internal.legacy.data.timeline;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nonnull;

import im.vector.matrix.android.internal.legacy.MXDataHandler;
import im.vector.matrix.android.internal.legacy.data.MyUser;
import im.vector.matrix.android.internal.legacy.data.Room;
@ -32,11 +37,6 @@ import im.vector.matrix.android.internal.legacy.util.EventDisplay;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nonnull;

/**
* This class is responsible for handling live event
*/
@ -203,7 +203,7 @@ class TimelineLiveEventHandler {
@NonNull Event event,
final boolean checkRedactedStateEvent) {
boolean shouldBeSaved = false;
String myUserId = dataHandler.getCredentials().userId;
String myUserId = dataHandler.getCredentials().getUserId();

if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) {
if (event.getRedactedEventId() != null) {

View File

@ -32,23 +32,6 @@ import android.widget.ImageView;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaDownloadListener;
import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback;
import im.vector.matrix.android.internal.legacy.rest.client.MediaScanRestClient;
import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanBody;
import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanEncryptedBody;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo;
import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo;
import im.vector.matrix.android.internal.legacy.ssl.CertUtil;
import im.vector.matrix.android.internal.legacy.util.ImageUtils;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import org.matrix.olm.OlmPkEncryption;
import org.matrix.olm.OlmPkMessage;

@ -78,6 +61,24 @@ import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaDownloadListener;
import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback;
import im.vector.matrix.android.internal.legacy.rest.client.MediaScanRestClient;
import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanBody;
import im.vector.matrix.android.internal.legacy.rest.model.EncryptedMediaScanEncryptedBody;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo;
import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedFileInfo;
import im.vector.matrix.android.internal.legacy.util.ImageUtils;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.network.ssl.CertUtil;

/**
* This class manages the media downloading in background.
* <p>
@ -746,9 +747,9 @@ class MXMediaDownloadWorkerTask extends AsyncTask<Void, Void, JsonElement> {
// Add SSL Socket factory.
HttpsURLConnection sslConn = (HttpsURLConnection) connection;
try {
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.newPinnedSSLSocketFactory(mHsConfig);
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mHsConfig);
sslConn.setSSLSocketFactory(pair.first);
sslConn.setHostnameVerifier(CertUtil.newHostnameVerifier(mHsConfig));
sslConn.setHostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mHsConfig));
} catch (Exception e) {
Log.e(LOG_TAG, "doInBackground SSL exception " + e.getMessage(), e);
}

View File

@ -22,15 +22,6 @@ import android.util.Pair;

import org.json.JSONException;
import org.json.JSONObject;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.ContentResponse;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.ssl.CertUtil;
import im.vector.matrix.android.internal.legacy.util.ContentManager;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.io.DataOutputStream;
import java.io.EOFException;
@ -51,6 +42,16 @@ import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.ContentResponse;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.util.ContentManager;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.network.ssl.CertUtil;

/**
* Private AsyncTask used to upload files.
*/
@ -282,7 +283,7 @@ public class MXMediaUploadWorkerTask extends AsyncTask<Void, Void, String> {

String serverResponse = null;

String urlString = mContentManager.getHsConfig().getHomeserverUri().toString() + ContentManager.URI_PREFIX_CONTENT_API + "upload";
String urlString = mContentManager.getHsConfig().getHomeServerUri().toString() + ContentManager.URI_PREFIX_CONTENT_API + "upload";

if (null != mFilename) {
try {
@ -300,7 +301,7 @@ public class MXMediaUploadWorkerTask extends AsyncTask<Void, Void, String> {
if (RestClient.getUserAgent() != null) {
conn.setRequestProperty("User-Agent", RestClient.getUserAgent());
}
conn.setRequestProperty("Authorization", "Bearer " + mContentManager.getHsConfig().getCredentials().accessToken);
conn.setRequestProperty("Authorization", "Bearer " + mContentManager.getCredentials().getAccessToken());
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
@ -310,9 +311,9 @@ public class MXMediaUploadWorkerTask extends AsyncTask<Void, Void, String> {
// Add SSL Socket factory.
HttpsURLConnection sslConn = (HttpsURLConnection) conn;
try {
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.newPinnedSSLSocketFactory(mContentManager.getHsConfig());
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.INSTANCE.newPinnedSSLSocketFactory(mContentManager.getHsConfig());
sslConn.setSSLSocketFactory(pair.first);
sslConn.setHostnameVerifier(CertUtil.newHostnameVerifier(mContentManager.getHsConfig()));
sslConn.setHostnameVerifier(CertUtil.INSTANCE.newHostnameVerifier(mContentManager.getHsConfig()));
} catch (Exception e) {
Log.e(LOG_TAG, "sslConn " + e.getMessage(), e);
}

View File

@ -31,7 +31,18 @@ import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.crypto.MXEncryptedAttachments;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaDownloadListener;
import im.vector.matrix.android.internal.legacy.listeners.IMXMediaUploadListener;
@ -46,17 +57,6 @@ import im.vector.matrix.android.internal.legacy.util.ContentUtils;
import im.vector.matrix.android.internal.legacy.util.Log;
import im.vector.matrix.android.internal.legacy.util.MXOsHandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;

public class MXMediasCache {

private static final String LOG_TAG = MXMediasCache.class.getSimpleName();

View File

@ -16,15 +16,15 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.HashMap;
import java.util.Map;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.AccountDataApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;

import java.util.HashMap;
import java.util.Map;

public class AccountDataRestClient extends RestClient<AccountDataApi> {
/**
* Account data types
@ -43,8 +43,8 @@ public class AccountDataRestClient extends RestClient<AccountDataApi> {
/**
* {@inheritDoc}
*/
public AccountDataRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, AccountDataApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public AccountDataRestClient(SessionParams sessionParams) {
super(sessionParams, AccountDataApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

/**
@ -62,11 +62,11 @@ public class AccountDataRestClient extends RestClient<AccountDataApi> {

mApi.setAccountData(userId, type, params)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
setAccountData(userId, type, params, callback);
}
}));
@Override
public void onRetry() {
setAccountData(userId, type, params, callback);
}
}));
}

/**
@ -82,11 +82,11 @@ public class AccountDataRestClient extends RestClient<AccountDataApi> {

mApi.openIdToken(userId, new HashMap<>())
.enqueue(new RestAdapterCallback<Map<Object, Object>>(description, mUnsentEventsManager, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
openIdToken(userId, callback);
}
}));
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
openIdToken(userId, callback);
}
}));
}
}

View File

@ -17,7 +17,7 @@ package im.vector.matrix.android.internal.legacy.rest.client;

import com.google.gson.JsonObject;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.CallRulesApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -28,8 +28,8 @@ public class CallRestClient extends RestClient<CallRulesApi> {
/**
* {@inheritDoc}
*/
public CallRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, CallRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public CallRestClient(SessionParams sessionParams) {
super(sessionParams, CallRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

public void getTurnServer(final ApiCallback<JsonObject> callback) {

View File

@ -19,7 +19,12 @@ package im.vector.matrix.android.internal.legacy.rest.client;

import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.crypto.data.MXKey;
import im.vector.matrix.android.internal.legacy.crypto.data.MXUsersDevicesMap;
@ -34,12 +39,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteDeviceParam
import im.vector.matrix.android.internal.legacy.rest.model.sync.DevicesListResponse;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import retrofit2.Response;

public class CryptoRestClient extends RestClient<CryptoApi> {
@ -49,8 +48,8 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
/**
* {@inheritDoc}
*/
public CryptoRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, CryptoApi.class, URI_API_PREFIX_PATH_UNSTABLE, false, false);
public CryptoRestClient(SessionParams sessionParams) {
super(sessionParams, CryptoApi.class, URI_API_PREFIX_PATH_UNSTABLE, false, false);
}

/**
@ -82,20 +81,20 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
mApi.uploadKeys(encodedDeviceId, params)
.enqueue(new RestAdapterCallback<KeysUploadResponse>(description, null, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback);
}
}));
@Override
public void onRetry() {
uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback);
}
}));
} else {
mApi.uploadKeys(params)
.enqueue(new RestAdapterCallback<KeysUploadResponse>(description, null, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback);
}
}));
@Override
public void onRetry() {
uploadKeys(deviceKeys, oneTimeKeys, deviceId, callback);
}
}));
}
}

@ -127,11 +126,11 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
mApi.downloadKeysForUsers(parameters)
.enqueue(new RestAdapterCallback<KeysQueryResponse>(description, mUnsentEventsManager, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
downloadKeysForUsers(userIds, token, callback);
}
}));
@Override
public void onRetry() {
downloadKeysForUsers(userIds, token, callback);
}
}));
}

/**
@ -151,40 +150,40 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
mApi.claimOneTimeKeysForUsersDevices(params)
.enqueue(new RestAdapterCallback<KeysClaimResponse>(description, mUnsentEventsManager, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
claimOneTimeKeysForUsersDevices(usersDevicesKeyTypesMap, callback);
}
}) {
@Override
public void success(KeysClaimResponse keysClaimResponse, Response response) {
onEventSent();
@Override
public void onRetry() {
claimOneTimeKeysForUsersDevices(usersDevicesKeyTypesMap, callback);
}
}) {
@Override
public void success(KeysClaimResponse keysClaimResponse, Response response) {
onEventSent();

Map<String, Map<String, MXKey>> map = new HashMap<>();
Map<String, Map<String, MXKey>> map = new HashMap<>();

if (null != keysClaimResponse.oneTimeKeys) {
for (String userId : keysClaimResponse.oneTimeKeys.keySet()) {
Map<String, Map<String, Map<String, Object>>> mapByUserId = keysClaimResponse.oneTimeKeys.get(userId);
if (null != keysClaimResponse.oneTimeKeys) {
for (String userId : keysClaimResponse.oneTimeKeys.keySet()) {
Map<String, Map<String, Map<String, Object>>> mapByUserId = keysClaimResponse.oneTimeKeys.get(userId);

Map<String, MXKey> keysMap = new HashMap<>();
Map<String, MXKey> keysMap = new HashMap<>();

for (String deviceId : mapByUserId.keySet()) {
try {
keysMap.put(deviceId, new MXKey(mapByUserId.get(deviceId)));
} catch (Exception e) {
Log.e(LOG_TAG, "## claimOneTimeKeysForUsersDevices : fail to create a MXKey " + e.getMessage(), e);
for (String deviceId : mapByUserId.keySet()) {
try {
keysMap.put(deviceId, new MXKey(mapByUserId.get(deviceId)));
} catch (Exception e) {
Log.e(LOG_TAG, "## claimOneTimeKeysForUsersDevices : fail to create a MXKey " + e.getMessage(), e);
}
}

if (keysMap.size() != 0) {
map.put(userId, keysMap);
}
}
}

if (keysMap.size() != 0) {
map.put(userId, keysMap);
}
callback.onSuccess(new MXUsersDevicesMap<>(map));
}
}

callback.onSuccess(new MXUsersDevicesMap<>(map));
}
});
});
}

/**
@ -217,11 +216,11 @@ public class CryptoRestClient extends RestClient<CryptoApi> {

mApi.sendToDevice(eventType, transactionId, content)
.enqueue(new RestAdapterCallback<Void>(description, null, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
sendToDevice(eventType, contentMap, callback);
}
}));
@Override
public void onRetry() {
sendToDevice(eventType, contentMap, callback);
}
}));
}

/**
@ -235,11 +234,11 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
mApi.getDevices()
.enqueue(new RestAdapterCallback<DevicesListResponse>(description, mUnsentEventsManager, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
getDevices(callback);
}
}));
@Override
public void onRetry() {
getDevices(callback);
}
}));
}

/**
@ -255,11 +254,11 @@ public class CryptoRestClient extends RestClient<CryptoApi> {

mApi.deleteDevice(deviceId, params)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
deleteDevice(deviceId, params, callback);
}
}));
@Override
public void onRetry() {
deleteDevice(deviceId, params, callback);
}
}));
}

/**
@ -278,11 +277,11 @@ public class CryptoRestClient extends RestClient<CryptoApi> {

mApi.updateDeviceInfo(deviceId, params)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
setDeviceName(deviceId, deviceName, callback);
}
}));
@Override
public void onRetry() {
setDeviceName(deviceId, deviceName, callback);
}
}));
}

/**
@ -299,10 +298,10 @@ public class CryptoRestClient extends RestClient<CryptoApi> {
mApi.getKeyChanges(from, to)
.enqueue(new RestAdapterCallback<KeyChangesResponse>(description, mUnsentEventsManager, callback,
new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
getKeyChanges(from, to, callback);
}
}));
@Override
public void onRetry() {
getKeyChanges(from, to, callback);
}
}));
}
}

View File

@ -19,7 +19,7 @@ package im.vector.matrix.android.internal.legacy.rest.client;

import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.EventsApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -62,8 +62,8 @@ public class EventsRestClient extends RestClient<EventsApi> {
/**
* {@inheritDoc}
*/
public EventsRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, EventsApi.class, "", false);
public EventsRestClient(SessionParams sessionParams) {
super(sessionParams, EventsApi.class, "", false);
}

protected EventsRestClient(EventsApi api) {

View File

@ -16,7 +16,7 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.FilterApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -24,21 +24,21 @@ import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallbac
import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterBody;
import im.vector.matrix.android.internal.legacy.rest.model.filter.FilterResponse;

public class FilterRestClient extends RestClient<FilterApi>{
public class FilterRestClient extends RestClient<FilterApi> {

/**
* {@inheritDoc}
*/
public FilterRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, FilterApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public FilterRestClient(SessionParams sessionParams) {
super(sessionParams, FilterApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

/**
* Uploads a FilterBody to homeserver
*
* @param userId the user id
* @param userId the user id
* @param filterBody FilterBody which should be send to server
* @param callback on success callback containing a String with populated filterId
* @param callback on success callback containing a String with populated filterId
*/
public void uploadFilter(final String userId, final FilterBody filterBody, final ApiCallback<FilterResponse> callback) {
final String description = "uploadFilter userId : " + userId + " filter : " + filterBody;

View File

@ -17,13 +17,18 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.GroupsApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.SimpleApiCallback;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.rest.model.group.AcceptGroupInvitationParams;
import im.vector.matrix.android.internal.legacy.rest.model.group.AddGroupParams;
import im.vector.matrix.android.internal.legacy.rest.model.group.CreateGroupParams;
@ -39,13 +44,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.group.GroupSummary;
import im.vector.matrix.android.internal.legacy.rest.model.group.GroupUsers;
import im.vector.matrix.android.internal.legacy.rest.model.group.LeaveGroupParams;
import im.vector.matrix.android.internal.legacy.rest.model.group.UpdatePubliciseParams;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import retrofit2.Response;

/**
@ -56,8 +54,8 @@ public class GroupsRestClient extends RestClient<GroupsApi> {
/**
* {@inheritDoc}
*/
public GroupsRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, GroupsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public GroupsRestClient(SessionParams sessionParams) {
super(sessionParams, GroupsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

protected GroupsRestClient(GroupsApi api) {

View File

@ -23,23 +23,22 @@ import android.text.TextUtils;

import com.google.gson.JsonObject;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.List;
import java.util.UUID;

import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.LoginApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;
import im.vector.matrix.android.internal.legacy.rest.model.Versions;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlow;
import im.vector.matrix.android.internal.legacy.rest.model.login.LoginFlowResponse;
import im.vector.matrix.android.internal.legacy.rest.model.login.LoginParams;
import im.vector.matrix.android.internal.legacy.rest.model.login.PasswordLoginParams;
import im.vector.matrix.android.internal.legacy.rest.model.login.RegistrationParams;
import im.vector.matrix.android.internal.legacy.rest.model.login.TokenLoginParams;

import java.util.List;
import java.util.UUID;

import retrofit2.Response;

/**
@ -59,10 +58,10 @@ public class LoginRestClient extends RestClient<LoginApi> {
/**
* Public constructor.
*
* @param hsConfig the home server connection config
* @param sessionParams the session connection data
*/
public LoginRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, LoginApi.class, "", false);
public LoginRestClient(SessionParams sessionParams) {
super(sessionParams, LoginApi.class, "", false);
}

/**

View File

@ -18,7 +18,11 @@ package im.vector.matrix.android.internal.legacy.rest.client;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import org.matrix.olm.OlmException;
import org.matrix.olm.OlmPkEncryption;
import org.matrix.olm.OlmPkMessage;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.data.store.IMXStore;
import im.vector.matrix.android.internal.legacy.rest.api.MediaScanApi;
@ -32,10 +36,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.MediaScanPublicKeyRes
import im.vector.matrix.android.internal.legacy.rest.model.MediaScanResult;
import im.vector.matrix.android.internal.legacy.rest.model.crypto.EncryptedBodyFileInfo;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;
import org.matrix.olm.OlmException;
import org.matrix.olm.OlmPkEncryption;
import org.matrix.olm.OlmPkMessage;

import retrofit2.Call;

/**
@ -49,8 +49,8 @@ public class MediaScanRestClient extends RestClient<MediaScanApi> {
/**
* {@inheritDoc}
*/
public MediaScanRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, MediaScanApi.class, RestClient.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE, false, EndPointServer.ANTIVIRUS_SERVER);
public MediaScanRestClient(SessionParams sessionParams) {
super(sessionParams, MediaScanApi.class, RestClient.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE, false, EndPointServer.ANTIVIRUS_SERVER);
}

/**

View File

@ -16,7 +16,7 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.PresenceApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -31,8 +31,8 @@ public class PresenceRestClient extends RestClient<PresenceApi> {
/**
* {@inheritDoc}
*/
public PresenceRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, PresenceApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public PresenceRestClient(SessionParams sessionParams) {
super(sessionParams, PresenceApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

/**

View File

@ -18,7 +18,10 @@ package im.vector.matrix.android.internal.legacy.rest.client;

import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.List;
import java.util.Map;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.ProfileApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -34,18 +37,11 @@ import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberVal
import im.vector.matrix.android.internal.legacy.rest.model.RequestPhoneNumberValidationResponse;
import im.vector.matrix.android.internal.legacy.rest.model.ThreePidCreds;
import im.vector.matrix.android.internal.legacy.rest.model.User;
import im.vector.matrix.android.internal.legacy.rest.model.login.Credentials;
import im.vector.matrix.android.internal.legacy.rest.model.login.TokenRefreshParams;
import im.vector.matrix.android.internal.legacy.rest.model.login.TokenRefreshResponse;
import im.vector.matrix.android.internal.legacy.rest.model.pid.AccountThreePidsResponse;
import im.vector.matrix.android.internal.legacy.rest.model.pid.AddThreePidsParams;
import im.vector.matrix.android.internal.legacy.rest.model.pid.DeleteThreePidParams;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThirdPartyIdentifier;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid;

import java.util.List;
import java.util.Map;

import retrofit2.Response;

/**
@ -57,8 +53,8 @@ public class ProfileRestClient extends RestClient<ProfileApi> {
/**
* {@inheritDoc}
*/
public ProfileRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, ProfileApi.class, "", false);
public ProfileRestClient(SessionParams sessionParams) {
super(sessionParams, ProfileApi.class, "", false);
}

/**
@ -102,7 +98,7 @@ public class ProfileRestClient extends RestClient<ProfileApi> {

// don't retry if the network comes back
// let the user chooses what he want to do
mApi.displayname(mCredentials.userId, user)
mApi.displayname(mCredentials.getUserId(), user)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
@ -150,7 +146,7 @@ public class ProfileRestClient extends RestClient<ProfileApi> {
User user = new User();
user.setAvatarUrl(newUrl);

mApi.avatarUrl(mCredentials.userId, user)
mApi.avatarUrl(mCredentials.getUserId(), user)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
@ -288,31 +284,6 @@ public class ProfileRestClient extends RestClient<ProfileApi> {
}));
}

/**
* Refresh access/refresh tokens, using the current refresh token.
*
* @param callback the callback success and failure callback
*/
public void refreshTokens(final ApiCallback<Credentials> callback) {
final String description = "refreshTokens";

TokenRefreshParams params = new TokenRefreshParams();
params.refresh_token = mCredentials.refreshToken;

mApi.tokenrefresh(params)
.enqueue(new RestAdapterCallback<TokenRefreshResponse>(description, mUnsentEventsManager, callback, null) {
@Override
public void success(TokenRefreshResponse tokenreponse, Response response) {
onEventSent();
mCredentials.refreshToken = tokenreponse.refresh_token;
mCredentials.accessToken = tokenreponse.access_token;
if (null != callback) {
callback.onSuccess(mCredentials);
}
}
});
}

/**
* List all 3PIDs linked to the Matrix user account.
*
@ -447,14 +418,14 @@ public class ProfileRestClient extends RestClient<ProfileApi> {

AddThreePidsParams params = new AddThreePidsParams();
params.three_pid_creds = new ThreePidCreds();

String identityServerHost = mHsConfig.getIdentityServerUri().toString();
if (identityServerHost.startsWith("http://")) {
identityServerHost = identityServerHost.substring("http://".length());
} else if (identityServerHost.startsWith("https://")) {
identityServerHost = identityServerHost.substring("https://".length());
if (identityServerHost != null) {
if (identityServerHost.startsWith("http://")) {
identityServerHost = identityServerHost.substring("http://".length());
} else if (identityServerHost.startsWith("https://")) {
identityServerHost = identityServerHost.substring("https://".length());
}
}

params.three_pid_creds.id_server = identityServerHost;
params.three_pid_creds.sid = pid.sid;
params.three_pid_creds.client_secret = pid.clientSecret;

View File

@ -16,7 +16,7 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.PushRulesApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -29,8 +29,8 @@ public class PushRulesRestClient extends RestClient<PushRulesApi> {
/**
* {@inheritDoc}
*/
public PushRulesRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, PushRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public PushRulesRestClient(SessionParams sessionParams) {
super(sessionParams, PushRulesApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

/**

View File

@ -17,7 +17,9 @@

package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.HashMap;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.data.Pusher;
import im.vector.matrix.android.internal.legacy.rest.api.PushersApi;
@ -25,8 +27,6 @@ import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;
import im.vector.matrix.android.internal.legacy.rest.model.PushersResponse;

import java.util.HashMap;

/**
* REST client for the Pushers API.
*/
@ -36,8 +36,8 @@ public class PushersRestClient extends RestClient<PushersApi> {
private static final String PUSHER_KIND_HTTP = "http";
private static final String DATA_KEY_HTTP_URL = "url";

public PushersRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, PushersApi.class, RestClient.URI_API_PREFIX_PATH_R0, true);
public PushersRestClient(SessionParams sessionParams) {
super(sessionParams, PushersApi.class, RestClient.URI_API_PREFIX_PATH_R0, true);
}

/**

View File

@ -24,7 +24,10 @@ import android.text.TextUtils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.util.HashMap;
import java.util.Map;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.data.RoomState;
import im.vector.matrix.android.internal.legacy.data.timeline.EventTimeline;
@ -52,14 +55,10 @@ import im.vector.matrix.android.internal.legacy.rest.model.filter.RoomEventFilte
import im.vector.matrix.android.internal.legacy.rest.model.message.Message;
import im.vector.matrix.android.internal.legacy.rest.model.sync.RoomResponse;

import java.util.HashMap;
import java.util.Map;

/**
* Class used to make requests to the rooms API.
*/
public class RoomsRestClient extends RestClient<RoomsApi> {
private static final String LOG_TAG = RoomsRestClient.class.getSimpleName();

public static final int DEFAULT_MESSAGES_PAGINATION_LIMIT = 30;

@ -70,8 +69,8 @@ public class RoomsRestClient extends RestClient<RoomsApi> {
/**
* {@inheritDoc}
*/
public RoomsRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, RoomsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
public RoomsRestClient(SessionParams sessionParams) {
super(sessionParams, RoomsApi.class, RestClient.URI_API_PREFIX_PATH_R0, false);
}

/**
@ -857,7 +856,7 @@ public class RoomsRestClient extends RestClient<RoomsApi> {
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("order", order);

mApi.addTag(mCredentials.userId, roomId, tag, hashMap)
mApi.addTag(mCredentials.getUserId(), roomId, tag, hashMap)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
@ -876,7 +875,7 @@ public class RoomsRestClient extends RestClient<RoomsApi> {
public void removeTag(final String roomId, final String tag, final ApiCallback<Void> callback) {
final String description = "removeTag : roomId " + roomId + " - tag " + tag;

mApi.removeTag(mCredentials.userId, roomId, tag)
mApi.removeTag(mCredentials.getUserId(), roomId, tag)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {
@ -898,7 +897,7 @@ public class RoomsRestClient extends RestClient<RoomsApi> {
Map<String, Object> params = new HashMap<>();
params.put(AccountDataRestClient.ACCOUNT_DATA_KEY_URL_PREVIEW_DISABLE, !status);

mApi.updateAccountData(mCredentials.userId, roomId, Event.EVENT_TYPE_URL_PREVIEW, params)
mApi.updateAccountData(mCredentials.getUserId(), roomId, Event.EVENT_TYPE_URL_PREVIEW, params)
.enqueue(new RestAdapterCallback<Void>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() {
@Override
public void onRetry() {

View File

@ -17,7 +17,14 @@
*/
package im.vector.matrix.android.internal.legacy.rest.client;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import im.vector.matrix.android.internal.auth.data.SessionParams;
import im.vector.matrix.android.internal.legacy.RestClient;
import im.vector.matrix.android.internal.legacy.rest.api.ThirdPidApi;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
@ -27,14 +34,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.BulkLookupResponse;
import im.vector.matrix.android.internal.legacy.rest.model.HttpError;
import im.vector.matrix.android.internal.legacy.rest.model.HttpException;
import im.vector.matrix.android.internal.legacy.rest.model.pid.PidResponse;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -46,8 +45,8 @@ public class ThirdPidRestClient extends RestClient<ThirdPidApi> {
/**
* {@inheritDoc}
*/
public ThirdPidRestClient(HomeServerConnectionConfig hsConfig) {
super(hsConfig, ThirdPidApi.class, URI_API_PREFIX_IDENTITY, false, true);
public ThirdPidRestClient(SessionParams sessionParams) {
super(sessionParams, ThirdPidApi.class, URI_API_PREFIX_IDENTITY, false, true);
}

/**

View File

@ -22,19 +22,20 @@ import android.text.TextUtils;

import com.google.gson.annotations.SerializedName;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.MXPatterns;
import im.vector.matrix.android.internal.legacy.data.RoomState;
import im.vector.matrix.android.internal.legacy.rest.model.pid.Invite3Pid;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.MXPatterns;
import im.vector.matrix.android.internal.legacy.data.RoomState;
import im.vector.matrix.android.internal.legacy.rest.model.pid.Invite3Pid;
import im.vector.matrix.android.internal.legacy.rest.model.pid.ThreePid;
import im.vector.matrix.android.internal.legacy.util.JsonUtils;

public class CreateRoomParams {

public static final String PRESET_PRIVATE_CHAT = "private_chat";
@ -225,7 +226,7 @@ public class CreateRoomParams {
*
* @param ids the participant ids to add.
*/
public void addParticipantIds(HomeServerConnectionConfig hsConfig, List<String> ids) {
public void addParticipantIds(HomeServerConnectionConfig homeServerConnectionConfig, Credentials credentials, List<String> ids) {
for (String id : ids) {
if (android.util.Patterns.EMAIL_ADDRESS.matcher(id).matches()) {
if (null == invite3pids) {
@ -233,14 +234,14 @@ public class CreateRoomParams {
}

Invite3Pid pid = new Invite3Pid();
pid.id_server = hsConfig.getIdentityServerUri().getHost();
pid.id_server = homeServerConnectionConfig.getIdentityServerUri().getHost();
pid.medium = ThreePid.MEDIUM_EMAIL;
pid.address = id;

invite3pids.add(pid);
} else if (MXPatterns.isUserId(id)) {
// do not invite oneself
if (!TextUtils.equals(hsConfig.getCredentials().userId, id)) {
if (!TextUtils.equals(credentials.getUserId(), id)) {
if (null == invitedUserIds) {
invitedUserIds = new ArrayList<>();
}

View File

@ -16,7 +16,7 @@
package im.vector.matrix.android.internal.legacy.rest.model;

/**
* 3 pid credentials
* 3 pid getCredentials
*/
public class ThreePidCreds {


View File

@ -21,7 +21,7 @@ import org.json.JSONException;
import org.json.JSONObject;

/**
* The user's credentials.
* The user's getCredentials.
*/
public class Credentials {
public String userId;

View File

@ -23,7 +23,7 @@ import im.vector.matrix.android.internal.legacy.rest.model.ThreePidCreds;
*/
public class AddThreePidsParams {

// the 3rd party id credentials
// the 3rd party id getCredentials
public ThreePidCreds three_pid_creds;

// true when the email has been binded.

View File

@ -1,270 +0,0 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.legacy.ssl;

import android.util.Pair;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.legacy.util.Log;

import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.TlsVersion;

/**
* Various utility classes for dealing with X509Certificates
*/
public class CertUtil {
private static final String LOG_TAG = CertUtil.class.getSimpleName();

/**
* Generates the SHA-256 fingerprint of the given certificate
*
* @param cert the certificate.
* @return the finger print
* @throws CertificateException the certificate exception
*/
public static byte[] generateSha256Fingerprint(X509Certificate cert) throws CertificateException {
return generateFingerprint(cert, "SHA-256");
}

/**
* Generates the SHA-1 fingerprint of the given certificate
*
* @param cert the certificated
* @return the SHA1 fingerprint
* @throws CertificateException the certificate exception
*/
public static byte[] generateSha1Fingerprint(X509Certificate cert) throws CertificateException {
return generateFingerprint(cert, "SHA-1");
}

/**
* Generate the fingerprint for a dedicated type.
*
* @param cert the certificate
* @param type the type
* @return the fingerprint
* @throws CertificateException certificate exception
*/
private static byte[] generateFingerprint(X509Certificate cert, String type) throws CertificateException {
final byte[] fingerprint;
final MessageDigest md;
try {
md = MessageDigest.getInstance(type);
} catch (Exception e) {
// This really *really* shouldn't throw, as java should always have a SHA-256 and SHA-1 impl.
throw new CertificateException(e);
}

fingerprint = md.digest(cert.getEncoded());

return fingerprint;
}

final private static char[] hexArray = "0123456789ABCDEF".toCharArray();

/**
* Convert the fingerprint to an hexa string.
*
* @param fingerprint the fingerprint
* @return the hexa string.
*/
public static String fingerprintToHexString(byte[] fingerprint) {
return fingerprintToHexString(fingerprint, ' ');
}

public static String fingerprintToHexString(byte[] fingerprint, char sep) {
char[] hexChars = new char[fingerprint.length * 3];
for (int j = 0; j < fingerprint.length; j++) {
int v = fingerprint[j] & 0xFF;
hexChars[j * 3] = hexArray[v >>> 4];
hexChars[j * 3 + 1] = hexArray[v & 0x0F];
hexChars[j * 3 + 2] = sep;
}
return new String(hexChars, 0, hexChars.length - 1);
}

/**
* Recursively checks the exception to see if it was caused by an
* UnrecognizedCertificateException
*
* @param e the throwable.
* @return The UnrecognizedCertificateException if exists, else null.
*/
public static UnrecognizedCertificateException getCertificateException(Throwable e) {
int i = 0; // Just in case there is a getCause loop
while (e != null && i < 10) {
if (e instanceof UnrecognizedCertificateException) {
return (UnrecognizedCertificateException) e;
}
e = e.getCause();
i++;
}

return null;
}

/**
* Create a SSLSocket factory for a HS config.
*
* @param hsConfig the HS config.
* @return SSLSocket factory
*/
public static Pair<SSLSocketFactory, X509TrustManager> newPinnedSSLSocketFactory(HomeServerConnectionConfig hsConfig) {
try {
X509TrustManager defaultTrustManager = null;

// If we haven't specified that we wanted to pin the certs, fallback to standard
// X509 checks if fingerprints don't match.
if (!hsConfig.shouldPin()) {
TrustManagerFactory tf = null;

// get the PKIX instance
try {
tf = TrustManagerFactory.getInstance("PKIX");
} catch (Exception e) {
Log.e(LOG_TAG, "## newPinnedSSLSocketFactory() : TrustManagerFactory.getInstance failed " + e.getMessage(), e);
}

// it doesn't exist, use the default one.
if (null == tf) {
try {
tf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
} catch (Exception e) {
Log.e(LOG_TAG, "## addRule : onBingRuleUpdateFailure failed " + e.getMessage(), e);
}
}

tf.init((KeyStore) null);
TrustManager[] trustManagers = tf.getTrustManagers();

for (int i = 0; i < trustManagers.length; i++) {
if (trustManagers[i] instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) trustManagers[i];
break;
}
}
}

TrustManager[] trustPinned = new TrustManager[]{
new PinnedTrustManager(hsConfig.getAllowedFingerprints(), defaultTrustManager)
};

SSLSocketFactory sslSocketFactory;

if (hsConfig.forceUsageOfTlsVersions() && hsConfig.getAcceptedTlsVersions() != null) {
// Force usage of accepted Tls Versions for Android < 20
sslSocketFactory = new TLSSocketFactory(trustPinned, hsConfig.getAcceptedTlsVersions());
} else {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustPinned, new java.security.SecureRandom());
sslSocketFactory = sslContext.getSocketFactory();
}

return new Pair<>(sslSocketFactory, defaultTrustManager);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* Create a Host name verifier for a hs config.
*
* @param hsConfig the hs config.
* @return a new HostnameVerifier.
*/
public static HostnameVerifier newHostnameVerifier(HomeServerConnectionConfig hsConfig) {
final HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
final List<Fingerprint> trusted_fingerprints = hsConfig.getAllowedFingerprints();

return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
if (defaultVerifier.verify(hostname, session)) return true;
if (trusted_fingerprints == null || trusted_fingerprints.size() == 0) return false;

// If remote cert matches an allowed fingerprint, just accept it.
try {
for (Certificate cert : session.getPeerCertificates()) {
for (Fingerprint allowedFingerprint : trusted_fingerprints) {
if (allowedFingerprint != null && cert instanceof X509Certificate && allowedFingerprint.matchesCert((X509Certificate) cert)) {
return true;
}
}
}
} catch (SSLPeerUnverifiedException e) {
return false;
} catch (CertificateException e) {
return false;
}

return false;
}
};
}

/**
* Create a list of accepted TLS specifications for a hs config.
*
* @param hsConfig the hs config.
* @return a list of accepted TLS specifications.
*/
public static List<ConnectionSpec> newConnectionSpecs(HomeServerConnectionConfig hsConfig) {
final ConnectionSpec.Builder builder = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS);

final List<TlsVersion> tlsVersions = hsConfig.getAcceptedTlsVersions();
if (null != tlsVersions) {
builder.tlsVersions(tlsVersions.toArray(new TlsVersion[0]));
}

final List<CipherSuite> tlsCipherSuites = hsConfig.getAcceptedTlsCipherSuites();
if (null != tlsCipherSuites) {
builder.cipherSuites(tlsCipherSuites.toArray(new CipherSuite[0]));
}

builder.supportsTlsExtensions(hsConfig.shouldAcceptTlsExtensions());

List<ConnectionSpec> list = new ArrayList<>();

list.add(builder.build());

if (hsConfig.isHttpConnectionAllowed()) {
list.add(ConnectionSpec.CLEARTEXT);
}

return list;
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.legacy.ssl;

import android.util.Base64;

import org.json.JSONException;
import org.json.JSONObject;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;

/**
* Represents a X509 Certificate fingerprint.
*/
public class Fingerprint {
public enum HashType {SHA1, SHA256}

private final byte[] mBytes;
private final HashType mHashType;
private String mDisplayableHexRepr;

public Fingerprint(byte[] bytes, HashType hashType) {
mBytes = bytes;
mHashType = hashType;
mDisplayableHexRepr = null;
}

public static Fingerprint newSha256Fingerprint(X509Certificate cert) throws CertificateException {
return new Fingerprint(
CertUtil.generateSha256Fingerprint(cert),
HashType.SHA256
);
}

public static Fingerprint newSha1Fingerprint(X509Certificate cert) throws CertificateException {
return new Fingerprint(
CertUtil.generateSha1Fingerprint(cert),
HashType.SHA1
);
}

public HashType getType() {
return mHashType;
}

public byte[] getBytes() {
return mBytes;
}

public String getBytesAsHexString() {
if (mDisplayableHexRepr == null) {
mDisplayableHexRepr = CertUtil.fingerprintToHexString(mBytes);
}

return mDisplayableHexRepr;
}

public JSONObject toJson() throws JSONException {
JSONObject obj = new JSONObject();
obj.put("bytes", Base64.encodeToString(getBytes(), Base64.DEFAULT));
obj.put("hash_type", mHashType.toString());
return obj;
}

public static Fingerprint fromJson(JSONObject obj) throws JSONException {
String hashTypeStr = obj.getString("hash_type");
byte[] fingerprintBytes = Base64.decode(obj.getString("bytes"), Base64.DEFAULT);

final HashType hashType;
if ("SHA256".equalsIgnoreCase(hashTypeStr)) {
hashType = HashType.SHA256;
} else if ("SHA1".equalsIgnoreCase(hashTypeStr)) {
hashType = HashType.SHA1;
} else {
throw new JSONException("Unrecognized hash type: " + hashTypeStr);
}

return new Fingerprint(fingerprintBytes, hashType);
}

public boolean matchesCert(X509Certificate cert) throws CertificateException {
Fingerprint o = null;
switch (mHashType) {
case SHA256:
o = Fingerprint.newSha256Fingerprint(cert);
break;
case SHA1:
o = Fingerprint.newSha1Fingerprint(cert);
break;
}

return equals(o);
}

public String toString() {
return String.format("Fingerprint{type: '%s', fingeprint: '%s'}", mHashType.toString(), getBytesAsHexString());
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Fingerprint that = (Fingerprint) o;

if (!Arrays.equals(mBytes, that.mBytes)) return false;
return mHashType == that.mHashType;

}

@Override
public int hashCode() {
int result = mBytes != null ? Arrays.hashCode(mBytes) : 0;
result = 31 * result + (mHashType != null ? mHashType.hashCode() : 0);
return result;
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.legacy.ssl;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.X509TrustManager;

/**
* Implements a TrustManager that checks Certificates against an explicit list of known
* fingerprints.
*/
public class PinnedTrustManager implements X509TrustManager {
private final List<Fingerprint> mFingerprints;
private final X509TrustManager mDefaultTrustManager;

/**
* @param fingerprints An array of SHA256 cert fingerprints
* @param defaultTrustManager Optional trust manager to fall back on if cert does not match
* any of the fingerprints. Can be null.
*/
public PinnedTrustManager(List<Fingerprint> fingerprints, X509TrustManager defaultTrustManager) {
mFingerprints = fingerprints;
mDefaultTrustManager = defaultTrustManager;
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String s) throws CertificateException {
try {
if (mDefaultTrustManager != null) {
mDefaultTrustManager.checkClientTrusted(
chain, s
);
return;
}
} catch (CertificateException e) {
// If there is an exception we fall back to checking fingerprints
if (mFingerprints == null || mFingerprints.size() == 0) {
throw new UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.getCause());
}
}
checkTrusted("client", chain);
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String s) throws CertificateException {
try {
if (mDefaultTrustManager != null) {
mDefaultTrustManager.checkServerTrusted(
chain, s
);
return;
}
} catch (CertificateException e) {
// If there is an exception we fall back to checking fingerprints
if (mFingerprints == null || mFingerprints.size() == 0) {
throw new UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.getCause());
}
}
checkTrusted("server", chain);
}

private void checkTrusted(String type, X509Certificate[] chain) throws CertificateException {
X509Certificate cert = chain[0];

boolean found = false;
if (mFingerprints != null) {
for (Fingerprint allowedFingerprint : mFingerprints) {
if (allowedFingerprint != null && allowedFingerprint.matchesCert(cert)) {
found = true;
break;
}
}
}

if (!found) {
throw new UnrecognizedCertificateException(cert, Fingerprint.newSha256Fingerprint(cert), null);
}
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

View File

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

package im.vector.matrix.android.internal.legacy.ssl;

import im.vector.matrix.android.internal.legacy.util.Log;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import okhttp3.TlsVersion;

/**
* Force the usage of Tls versions on every created socket
* Inspired from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
*/
/*package*/ class TLSSocketFactory extends SSLSocketFactory {
private static final String LOG_TAG = TLSSocketFactory.class.getSimpleName();

private SSLSocketFactory internalSSLSocketFactory;

private String[] enabledProtocols;

/**
* Constructor
*
* @param trustPinned
* @param acceptedTlsVersions
* @throws KeyManagementException
* @throws NoSuchAlgorithmException
*/
/*package*/ TLSSocketFactory(TrustManager[] trustPinned, List<TlsVersion> acceptedTlsVersions) throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustPinned, new SecureRandom());
internalSSLSocketFactory = context.getSocketFactory();

enabledProtocols = new String[acceptedTlsVersions.size()];
int i = 0;
for (TlsVersion tlsVersion : acceptedTlsVersions) {
enabledProtocols[i] = tlsVersion.javaName();
i++;
}
}

@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}

@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}

private Socket enableTLSOnSocket(Socket socket) {
if (socket != null && (socket instanceof SSLSocket)) {
SSLSocket sslSocket = (SSLSocket) socket;

List<String> supportedProtocols = Arrays.asList(sslSocket.getSupportedProtocols());
List<String> filteredEnabledProtocols = new ArrayList<>();

for (String protocol : enabledProtocols) {
if (supportedProtocols.contains(protocol)) {
filteredEnabledProtocols.add(protocol);
}
}

if (!filteredEnabledProtocols.isEmpty()) {
try {
sslSocket.setEnabledProtocols(filteredEnabledProtocols.toArray(new String[filteredEnabledProtocols.size()]));
} catch (Exception e) {
Log.e(LOG_TAG, "Exception: ", e);
}
}
}
return socket;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.legacy.ssl;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
* Thrown when we are given a certificate that does match the certificate we were told to
* expect.
*/
public class UnrecognizedCertificateException extends CertificateException {
private final X509Certificate mCert;
private final Fingerprint mFingerprint;

public UnrecognizedCertificateException(X509Certificate cert, Fingerprint fingerprint, Throwable cause) {
super("Unrecognized certificate with unknown fingerprint: " + cert.getSubjectDN(), cause);
mCert = cert;
mFingerprint = fingerprint;
}

public X509Certificate getCertificate() {
return mCert;
}

public Fingerprint getFingerprint() {
return mFingerprint;
}
}

View File

@ -146,7 +146,7 @@ public class BingRulesManager {
public BingRulesManager(MXSession session, NetworkConnectivityReceiver networkConnectivityReceiver) {
mSession = session;
mApiClient = session.getBingRulesApiClient();
mMyUserId = session.getCredentials().userId;
mMyUserId = session.getCredentials().getUserId();
mDataHandler = session.getDataHandler();

mNetworkListener = new IMXNetworkEventListener() {

View File

@ -19,7 +19,8 @@ package im.vector.matrix.android.internal.legacy.util;

import android.support.annotation.Nullable;

import im.vector.matrix.android.internal.legacy.HomeServerConnectionConfig;
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig;
import im.vector.matrix.android.internal.auth.data.Credentials;
import im.vector.matrix.android.internal.legacy.RestClient;

/**
@ -39,6 +40,7 @@ public class ContentManager {

// HS config
private final HomeServerConnectionConfig mHsConfig;
private final Credentials mCredentials;

// the unsent events Manager
private final UnsentEventsManager mUnsentEventsManager;
@ -53,8 +55,9 @@ public class ContentManager {
* @param hsConfig the HomeserverConnectionConfig to use
* @param unsentEventsManager the unsent events manager
*/
public ContentManager(HomeServerConnectionConfig hsConfig, UnsentEventsManager unsentEventsManager) {
public ContentManager(HomeServerConnectionConfig hsConfig, Credentials credentials, UnsentEventsManager unsentEventsManager) {
mHsConfig = hsConfig;
mCredentials = credentials;
mUnsentEventsManager = unsentEventsManager;
// The AV scanner is disabled by default
configureAntiVirusScanner(false);
@ -73,7 +76,7 @@ public class ContentManager {
if (isEnabled) {
mDownloadUrlPrefix = mHsConfig.getAntiVirusServerUri().toString() + "/" + RestClient.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE;
} else {
mDownloadUrlPrefix = mHsConfig.getHomeserverUri().toString() + URI_PREFIX_CONTENT_API;
mDownloadUrlPrefix = mHsConfig.getHomeServerUri().toString() + URI_PREFIX_CONTENT_API;
}
}

@ -88,6 +91,13 @@ public class ContentManager {
return mHsConfig;
}

/**
* @return the getCredentials.
*/
public Credentials getCredentials() {
return mCredentials;
}

/**
* @return the unsent events manager
*/
@ -210,7 +220,7 @@ public class ContentManager {
// Caution: identicon has no thumbnail path.
if (mediaServerAndId.startsWith(MATRIX_CONTENT_IDENTICON_PREFIX)) {
// identicon url still go to the media repo since they dont need virus scanning
url = mHsConfig.getHomeserverUri().toString() + URI_PREFIX_CONTENT_API;
url = mHsConfig.getHomeServerUri().toString() + URI_PREFIX_CONTENT_API;
} else {
// Use the current download url prefix to take into account a potential antivirus scanner
url = mDownloadUrlPrefix + "thumbnail/";

View File

@ -97,7 +97,7 @@ public class EventUtils {

Room room = session.getDataHandler().getRoom(event.roomId);
return RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE.equals(room.getVisibility())
&& !TextUtils.equals(event.getSender(), session.getCredentials().userId);
&& !TextUtils.equals(event.getSender(), session.getCredentials().getUserId());
}

/**

View File

@ -26,6 +26,12 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import im.vector.matrix.android.internal.legacy.rest.json.BooleanDeserializer;
import im.vector.matrix.android.internal.legacy.rest.json.ConditionDeserializer;
import im.vector.matrix.android.internal.legacy.rest.json.MatrixFieldNamingStrategy;
@ -59,11 +65,6 @@ import im.vector.matrix.android.internal.legacy.rest.model.message.StickerMessag
import im.vector.matrix.android.internal.legacy.rest.model.message.VideoMessage;
import im.vector.matrix.android.internal.legacy.rest.model.pid.RoomThirdPartyInvite;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.TreeSet;

/**
* Static methods for converting json into objects.
*/
@ -527,6 +528,16 @@ public class JsonUtils {
return new JsonObject();
}

public static JsonObject toJson(Map<String, Object> data) {
try {
return (JsonObject) gson.toJsonTree(data);
} catch (Exception e) {
Log.e(LOG_TAG, "## toJson failed " + e.getMessage(), e);
}

return new JsonObject();
}

/**
* Convert an Message instance into a Json object.
*

View File

@ -20,15 +20,6 @@ package im.vector.matrix.android.internal.legacy.util;
import android.content.Context;
import android.text.TextUtils;

import im.vector.matrix.android.internal.legacy.MXDataHandler;
import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener;
import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.legacy.ssl.CertUtil;
import im.vector.matrix.android.internal.legacy.ssl.UnrecognizedCertificateException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@ -38,6 +29,14 @@ import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import im.vector.matrix.android.internal.legacy.MXDataHandler;
import im.vector.matrix.android.internal.legacy.listeners.IMXNetworkEventListener;
import im.vector.matrix.android.internal.legacy.network.NetworkConnectivityReceiver;
import im.vector.matrix.android.internal.legacy.rest.callback.ApiCallback;
import im.vector.matrix.android.internal.legacy.rest.callback.RestAdapterCallback;
import im.vector.matrix.android.internal.legacy.rest.model.MatrixError;
import im.vector.matrix.android.internal.network.ssl.CertUtil;
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException;
import retrofit2.Response;

/**
@ -405,8 +404,7 @@ public class UnsentEventsManager {
}

if (null != exception) {
UnrecognizedCertificateException unrecCertEx = CertUtil.getCertificateException(exception);

UnrecognizedCertificateException unrecCertEx = CertUtil.INSTANCE.getCertificateException(exception);
if (null != unrecCertEx) {
Log.e(LOG_TAG, "## onEventSendingFailed() : SSL issue detected");
mDataHandler.onSSLCertificateError(unrecCertEx);

View File

@ -1,18 +1,18 @@
package im.vector.matrix.android.internal.network

import im.vector.matrix.android.api.auth.CredentialsStore
import im.vector.matrix.android.api.auth.SessionParamsStore
import okhttp3.Interceptor
import okhttp3.Response

class AccessTokenInterceptor(private val credentialsStore: CredentialsStore) : Interceptor {
class AccessTokenInterceptor(private val sessionParamsStore: SessionParamsStore) : Interceptor {

override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val newRequestBuilder = request.newBuilder()
// Add the access token to all requests if it is set
val credentials = credentialsStore.get()
credentials?.let {
newRequestBuilder.addHeader("Authorization", "Bearer " + it.accessToken)
val sessionParams = sessionParamsStore.get()
sessionParams?.let {
newRequestBuilder.addHeader("Authorization", "Bearer " + it.credentials.accessToken)
}
request = newRequestBuilder.build()
return chain.proceed(request)

View File

@ -1,9 +1,9 @@
package im.vector.matrix.android.internal.network

import arrow.core.Either
import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.internal.util.Either
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.withContext
@ -21,7 +21,7 @@ class Request<DATA> {

suspend fun execute(): Either<Failure, DATA?> = withContext(dispatcher) {
return@withContext try {

val response = apiCall.await()
if (response.isSuccessful) {
val result = response.body()

View File

@ -0,0 +1,247 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.network.ssl

import android.util.Pair
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import okhttp3.ConnectionSpec
import timber.log.Timber
import java.security.KeyStore
import java.security.MessageDigest
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.*
import javax.net.ssl.*
import kotlin.experimental.and

/**
* Various utility classes for dealing with X509Certificates
*/
object CertUtil {

private val hexArray = "0123456789ABCDEF".toCharArray()

/**
* Generates the SHA-256 fingerprint of the given certificate
*
* @param cert the certificate.
* @return the finger print
* @throws CertificateException the certificate exception
*/
@Throws(CertificateException::class)
fun generateSha256Fingerprint(cert: X509Certificate): ByteArray {
return generateFingerprint(cert, "SHA-256")
}

/**
* Generates the SHA-1 fingerprint of the given certificate
*
* @param cert the certificated
* @return the SHA1 fingerprint
* @throws CertificateException the certificate exception
*/
@Throws(CertificateException::class)
fun generateSha1Fingerprint(cert: X509Certificate): ByteArray {
return generateFingerprint(cert, "SHA-1")
}

/**
* Generate the fingerprint for a dedicated type.
*
* @param cert the certificate
* @param type the type
* @return the fingerprint
* @throws CertificateException certificate exception
*/
@Throws(CertificateException::class)
private fun generateFingerprint(cert: X509Certificate, type: String): ByteArray {
val fingerprint: ByteArray
val md: MessageDigest
try {
md = MessageDigest.getInstance(type)
} catch (e: Exception) {
// This really *really* shouldn't throw, as java should always have a SHA-256 and SHA-1 impl.
throw CertificateException(e)
}

fingerprint = md.digest(cert.encoded)

return fingerprint
}

/**
* Convert the fingerprint to an hexa string.
*
* @param fingerprint the fingerprint
* @return the hexa string.
*/
@JvmOverloads
fun fingerprintToHexString(fingerprint: ByteArray, sep: Char = ' '): String {
val hexChars = CharArray(fingerprint.size * 3)
for (j in fingerprint.indices) {
val v = (fingerprint[j] and 0xFF.toByte()).toInt()
hexChars[j * 3] = hexArray[v.ushr(4)]
hexChars[j * 3 + 1] = hexArray[v and 0x0F]
hexChars[j * 3 + 2] = sep
}
return String(hexChars, 0, hexChars.size - 1)
}

/**
* Recursively checks the exception to see if it was caused by an
* UnrecognizedCertificateException
*
* @param e the throwable.
* @return The UnrecognizedCertificateException if exists, else null.
*/
fun getCertificateException(e: Throwable?): UnrecognizedCertificateException? {
var e = e
var i = 0 // Just in case there is a getCause loop
while (e != null && i < 10) {
if (e is UnrecognizedCertificateException) {
return e
}
e = e.cause
i++
}

return null
}

/**
* Create a SSLSocket factory for a HS config.
*
* @param hsConfig the HS config.
* @return SSLSocket factory
*/
fun newPinnedSSLSocketFactory(hsConfig: HomeServerConnectionConfig): Pair<SSLSocketFactory, X509TrustManager> {
try {
var defaultTrustManager: X509TrustManager? = null

// If we haven't specified that we wanted to shouldPin the certs, fallback to standard
// X509 checks if fingerprints don't match.
if (!hsConfig.shouldPin) {
var tf: TrustManagerFactory? = null

// get the PKIX instance
try {
tf = TrustManagerFactory.getInstance("PKIX")
} catch (e: Exception) {
Timber.e("## newPinnedSSLSocketFactory() : TrustManagerFactory.getInstance failed " + e.message, e)
}

// it doesn't exist, use the default one.
if (null == tf) {
try {
tf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
} catch (e: Exception) {
Timber.e("## addRule : onBingRuleUpdateFailure failed " + e.message, e)
}

}

tf!!.init(null as KeyStore?)
val trustManagers = tf.trustManagers

for (i in trustManagers.indices) {
if (trustManagers[i] is X509TrustManager) {
defaultTrustManager = trustManagers[i] as X509TrustManager
break
}
}
}

val trustPinned = arrayOf<TrustManager>(PinnedTrustManager(hsConfig.allowedFingerprints, defaultTrustManager))

val sslSocketFactory: SSLSocketFactory

if (hsConfig.forceUsageTlsVersions && hsConfig.tlsVersions != null) {
// Force usage of accepted Tls Versions for Android < 20
sslSocketFactory = TLSSocketFactory(trustPinned, hsConfig.tlsVersions)
} else {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustPinned, java.security.SecureRandom())
sslSocketFactory = sslContext.socketFactory
}

return Pair<SSLSocketFactory, X509TrustManager>(sslSocketFactory, defaultTrustManager)
} catch (e: Exception) {
throw RuntimeException(e)
}

}

/**
* Create a Host name verifier for a hs config.
*
* @param hsConfig the hs config.
* @return a new HostnameVerifier.
*/
fun newHostnameVerifier(hsConfig: HomeServerConnectionConfig): HostnameVerifier {
val defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier()
val trustedFingerprints = hsConfig.allowedFingerprints

return HostnameVerifier { hostname, session ->
if (defaultVerifier.verify(hostname, session)) return@HostnameVerifier true
if (trustedFingerprints == null || trustedFingerprints.size == 0) return@HostnameVerifier false

// If remote cert matches an allowed fingerprint, just accept it.
try {
for (cert in session.peerCertificates) {
for (allowedFingerprint in trustedFingerprints) {
if (allowedFingerprint != null && cert is X509Certificate && allowedFingerprint.matchesCert(cert)) {
return@HostnameVerifier true
}
}
}
} catch (e: SSLPeerUnverifiedException) {
return@HostnameVerifier false
} catch (e: CertificateException) {
return@HostnameVerifier false
}

false
}
}

/**
* Create a list of accepted TLS specifications for a hs config.
*
* @param hsConfig the hs config.
* @return a list of accepted TLS specifications.
*/
fun newConnectionSpecs(hsConfig: HomeServerConnectionConfig): List<ConnectionSpec> {
val builder = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
val tlsVersions = hsConfig.tlsVersions
if (null != tlsVersions) {
builder.tlsVersions(*tlsVersions.toTypedArray())
}

val tlsCipherSuites = hsConfig.tlsCipherSuites
if (null != tlsCipherSuites) {
builder.cipherSuites(*tlsCipherSuites.toTypedArray())
}

builder.supportsTlsExtensions(hsConfig.shouldAcceptTlsExtensions)
val list = ArrayList<ConnectionSpec>()
list.add(builder.build())
if (hsConfig.allowHttpExtension) {
list.add(ConnectionSpec.CLEARTEXT)
}
return list
}
}

View File

@ -0,0 +1,68 @@
package im.vector.matrix.android.internal.network.ssl

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import java.security.cert.CertificateException
import java.security.cert.X509Certificate

@JsonClass(generateAdapter = true)
data class Fingerprint(
val mBytes: ByteArray,
val mHashType: HashType
) {

val displayableHexRepr: String by lazy {
CertUtil.fingerprintToHexString(mBytes)
}

@Throws(CertificateException::class)
fun matchesCert(cert: X509Certificate): Boolean {
var o: Fingerprint? = when (mHashType) {
Fingerprint.HashType.SHA256 -> Fingerprint.newSha256Fingerprint(cert)
Fingerprint.HashType.SHA1 -> Fingerprint.newSha1Fingerprint(cert)
}
return equals(o)
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as Fingerprint
if (!mBytes.contentEquals(other.mBytes)) return false
if (mHashType != other.mHashType) return false

return true
}

override fun hashCode(): Int {
var result = mBytes.contentHashCode()
result = 31 * result + mHashType.hashCode()
return result
}

companion object {

@Throws(CertificateException::class)
fun newSha256Fingerprint(cert: X509Certificate): Fingerprint {
return Fingerprint(
CertUtil.generateSha256Fingerprint(cert),
HashType.SHA256
)
}

@Throws(CertificateException::class)
fun newSha1Fingerprint(cert: X509Certificate): Fingerprint {
return Fingerprint(
CertUtil.generateSha1Fingerprint(cert),
HashType.SHA1
)
}
}

enum class HashType {
@Json(name = "sha-1") SHA1,
@Json(name = "sha-256")SHA256
}

}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.network.ssl

import java.security.cert.CertificateException
import java.security.cert.X509Certificate

import javax.net.ssl.X509TrustManager

/**
* Implements a TrustManager that checks Certificates against an explicit list of known
* fingerprints.
*/

/**
* @param fingerprints An array of SHA256 cert fingerprints
* @param defaultTrustManager Optional trust manager to fall back on if cert does not match
* any of the fingerprints. Can be null.
*/
class PinnedTrustManager(private val mFingerprints: List<Fingerprint>?,
private val mDefaultTrustManager: X509TrustManager?) : X509TrustManager {

@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate>, s: String) {
try {
if (mDefaultTrustManager != null) {
mDefaultTrustManager.checkClientTrusted(
chain, s
)
return
}
} catch (e: CertificateException) {
// If there is an exception we fall back to checking fingerprints
if (mFingerprints == null || mFingerprints.isEmpty()) {
throw UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.cause)
}
}

checkTrusted("client", chain)
}

@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate>, s: String) {
try {
if (mDefaultTrustManager != null) {
mDefaultTrustManager.checkServerTrusted(
chain, s
)
return
}
} catch (e: CertificateException) {
// If there is an exception we fall back to checking fingerprints
if (mFingerprints == null || mFingerprints.isEmpty()) {
throw UnrecognizedCertificateException(chain[0], Fingerprint.newSha256Fingerprint(chain[0]), e.cause)
}
}

checkTrusted("server", chain)
}

@Throws(CertificateException::class)
private fun checkTrusted(type: String, chain: Array<X509Certificate>) {
val cert = chain[0]

var found = false
if (mFingerprints != null) {
for (allowedFingerprint in mFingerprints) {
if (allowedFingerprint.matchesCert(cert)) {
found = true
break
}
}
}

if (!found) {
throw UnrecognizedCertificateException(cert, Fingerprint.newSha256Fingerprint(cert), null)
}
}

override fun getAcceptedIssuers(): Array<X509Certificate> {
return emptyArray()
}
}

View File

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

package im.vector.matrix.android.internal.network.ssl

import im.vector.matrix.android.internal.legacy.util.Log
import okhttp3.TlsVersion
import java.io.IOException
import java.net.InetAddress
import java.net.Socket
import java.net.UnknownHostException
import java.security.KeyManagementException
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.util.*
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager

/**
* Force the usage of Tls versions on every created socket
* Inspired from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
*/

internal class TLSSocketFactory


/**
* Constructor
*
* @param trustPinned
* @param acceptedTlsVersions
* @throws KeyManagementException
* @throws NoSuchAlgorithmException
*/
@Throws(KeyManagementException::class, NoSuchAlgorithmException::class)
constructor(trustPinned: Array<TrustManager>, acceptedTlsVersions: List<TlsVersion>) : SSLSocketFactory() {

private val internalSSLSocketFactory: SSLSocketFactory
private val enabledProtocols: Array<String>

init {
val context = SSLContext.getInstance("TLS")
context.init(null, trustPinned, SecureRandom())
internalSSLSocketFactory = context.socketFactory
enabledProtocols = Array(acceptedTlsVersions.size) {
acceptedTlsVersions[it].javaName()
}
}

override fun getDefaultCipherSuites(): Array<String> {
return internalSSLSocketFactory.defaultCipherSuites
}

override fun getSupportedCipherSuites(): Array<String> {
return internalSSLSocketFactory.supportedCipherSuites
}

@Throws(IOException::class)
override fun createSocket(): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket())
}

@Throws(IOException::class)
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose))
}

@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(host: String, port: Int): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
}

@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort))
}

@Throws(IOException::class)
override fun createSocket(host: InetAddress, port: Int): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
}

@Throws(IOException::class)
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket? {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))
}

private fun enableTLSOnSocket(socket: Socket?): Socket? {
if (socket != null && socket is SSLSocket) {
val sslSocket = socket as SSLSocket?

val supportedProtocols = Arrays.asList(*sslSocket!!.supportedProtocols)
val filteredEnabledProtocols = ArrayList<String>()

for (protocol in enabledProtocols) {
if (supportedProtocols.contains(protocol)) {
filteredEnabledProtocols.add(protocol)
}
}

if (!filteredEnabledProtocols.isEmpty()) {
try {
sslSocket.enabledProtocols = filteredEnabledProtocols.toTypedArray()
} catch (e: Exception) {
Log.e(LOG_TAG, "Exception: ", e)
}

}
}
return socket
}

companion object {
private val LOG_TAG = TLSSocketFactory::class.java.simpleName
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.network.ssl

import java.security.cert.CertificateException
import java.security.cert.X509Certificate

/**
* Thrown when we are given a certificate that does match the certificate we were told to
* expect.
*/
data class UnrecognizedCertificateException(
val certificate: X509Certificate,
val fingerprint: Fingerprint,
override val cause: Throwable?
) : CertificateException("Unrecognized certificate with unknown fingerprint: " + certificate.subjectDN, cause)

View File

@ -1,7 +1,7 @@
package im.vector.matrix.android.internal.session

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.auth.data.SessionParams
import im.vector.matrix.android.internal.di.SessionModule
import im.vector.matrix.android.internal.events.sync.SyncModule
import im.vector.matrix.android.internal.events.sync.Synchronizer
@ -11,13 +11,13 @@ import org.koin.standalone.StandAloneContext
import org.koin.standalone.getKoin
import org.koin.standalone.inject

class DefaultSession(homeServerConnectionConfig: HomeServerConnectionConfig) : Session, KoinComponent {
class DefaultSession(sessionParams: SessionParams) : Session, KoinComponent {

private val synchronizer by inject<Synchronizer>()
private val scope: Scope

init {
val sessionModule = SessionModule(homeServerConnectionConfig)
val sessionModule = SessionModule(sessionParams)
val syncModule = SyncModule()
StandAloneContext.loadKoinModules(listOf(sessionModule, syncModule))
scope = getKoin().createScope(SCOPE)

View File

@ -1,35 +0,0 @@
package im.vector.matrix.android.internal.util

sealed class Either<out L, out R> {
/** * Represents the left side of [Either] class which by convention is a "Failure". */
data class Left<out L>(val a: L) : Either<L, Nothing>()

/** * Represents the right side of [Either] class which by convention is a "Success". */
data class Right<out R>(val b: R) : Either<Nothing, R>()

val isRight get() = this is Right<R>
val isLeft get() = this is Left<L>

fun <L> left(a: L) = Left(a)
fun <R> right(b: R) = Right(b)

fun either(fnL: (L) -> Any, fnR: (R) -> Any): Any =
when (this) {
is Left -> fnL(a)
is Right -> fnR(b)
}
}

// Credits to Alex Hart -> https://proandroiddev.com/kotlins-nothing-type-946de7d464fb
// Composes 2 functions
fun <A, B, C> ((A) -> B).c(f: (B) -> C): (A) -> C = {
f(this(it))
}

fun <T, L, R> Either<L, R>.flatMap(fn: (R) -> Either<L, T>): Either<L, T> =
when (this) {
is Either.Left -> Either.Left(a)
is Either.Right -> fn(b)
}

fun <T, L, R> Either<L, R>.map(fn: (R) -> (T)): Either<L, T> = this.flatMap(fn.c(::right))