Skip to content

Commit

Permalink
Merge branch 'release/0.91.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Jul 6, 2020
2 parents 7b075f1 + 1e6d98a commit 51abdb6
Show file tree
Hide file tree
Showing 71 changed files with 471 additions and 436 deletions.
21 changes: 21 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
Changes in Riot.imX 0.91.4 (2020-XX-XX)
===================================================

Features ✨:
- Re-activate Wellknown support with updated UI (#1614)

Improvements 🙌:
- Upload device keys only once to the homeserver and fix crash when no network (#1629)

Bugfix 🐛:
- Fix crash when coming from a notification (#1601)
- Fix Exception when importing keys (#1576)
- File isn't downloaded when another file with the same name already exists (#1578)
- saved images don't show up in gallery (#1324)
- Fix reply fallback leaking sender locale (#429)

Build 🧱:
- Fix lint false-positive about WorkManager (#1012)
- Upgrade build-tools from 3.5.3 to 3.6.6
- Upgrade gradle from 5.4.1 to 5.6.4

Changes in Riot.imX 0.91.3 (2020-07-01)
===================================================

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.google.gms:google-services:4.3.2'
classpath "com.airbnb.okreplay:gradle-plugin:1.5.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Sep 27 10:10:35 CEST 2019
#Thu Jul 02 12:33:07 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
16 changes: 16 additions & 0 deletions matrix-sdk-android/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,19 @@

### Webrtc
-keep class org.webrtc.** { *; }

### Serializable persisted classes
# https://www.guardsquare.com/en/products/proguard/manual/examples#serializable
-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
6 changes: 0 additions & 6 deletions matrix-sdk-android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="im.vector.matrix.android">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Expand All @@ -8,11 +7,6 @@

<application android:networkSecurityConfig="@xml/network_security_config">

<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
<!--
The SDK offers a secured File provider to access downloaded files.
Access to these file will be given via the FileService, with a temporary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.auth.login
import dagger.Lazy
import im.vector.matrix.android.api.auth.data.Credentials
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.internal.auth.AuthAPI
import im.vector.matrix.android.internal.auth.SessionCreator
Expand All @@ -27,6 +28,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
import im.vector.matrix.android.internal.task.Task
import okhttp3.OkHttpClient
import javax.inject.Inject
Expand All @@ -49,13 +51,28 @@ internal class DefaultDirectLoginTask @Inject constructor(

override suspend fun execute(params: DirectLoginTask.Params): Session {
val client = buildClient(params.homeServerConnectionConfig)
val authAPI = retrofitFactory.create(client, params.homeServerConnectionConfig.homeServerUri.toString())
val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString()

val authAPI = retrofitFactory.create(client, homeServerUrl)
.create(AuthAPI::class.java)

val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)

val credentials = executeRequest<Credentials>(null) {
apiCall = authAPI.login(loginParams)
val credentials = try {
executeRequest<Credentials>(null) {
apiCall = authAPI.login(loginParams)
}
} catch (throwable: Throwable) {
when (throwable) {
is UnrecognizedCertificateException -> {
throw Failure.UnrecognizedCertificateFailure(
homeServerUrl,
throwable.fingerprint
)
}
else ->
throw throwable
}
}

return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ import im.vector.matrix.android.internal.crypto.model.event.RoomKeyWithHeldConte
import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.model.toRest
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
Expand Down Expand Up @@ -98,6 +97,7 @@ import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.task.launchToCallback
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.fetchCopied
Expand Down Expand Up @@ -340,11 +340,14 @@ internal class DefaultCryptoService @Inject constructor(
}

fun ensureDevice() {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
// Open the store
cryptoStore.open()
// TODO why do that everytime? we should mark that it was done
uploadDeviceKeys()
// this can throw if no network
tryThis {
uploadDeviceKeys()
}

oneTimeKeysUploader.maybeUploadOneTimeKeys()
// this can throw if no backup
tryThis {
Expand Down Expand Up @@ -389,7 +392,7 @@ internal class DefaultCryptoService @Inject constructor(
// } else {

// Why would we do that? it will be called at end of syn
incomingGossipingRequestManager.processReceivedGossipingRequests()
incomingGossipingRequestManager.processReceivedGossipingRequests()
// }
}.fold(
{
Expand Down Expand Up @@ -888,7 +891,7 @@ internal class DefaultCryptoService @Inject constructor(
*/
private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean {
return when (secretName) {
MASTER_KEY_SSSS_NAME -> {
MASTER_KEY_SSSS_NAME -> {
crossSigningService.onSecretMSKGossip(secretValue)
true
}
Expand Down Expand Up @@ -980,7 +983,11 @@ internal class DefaultCryptoService @Inject constructor(
/**
* Upload my user's device keys.
*/
private suspend fun uploadDeviceKeys(): KeysUploadResponse {
private suspend fun uploadDeviceKeys() {
if (cryptoStore.getDeviceKeysUploaded()) {
Timber.d("Keys already uploaded, nothing to do")
return
}
// Prepare the device keys data to send
// Sign it
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
Expand All @@ -991,7 +998,9 @@ internal class DefaultCryptoService @Inject constructor(
)

val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null)
return uploadKeysTask.execute(uploadDeviceKeysParams)
uploadKeysTask.execute(uploadDeviceKeysParams)

cryptoStore.setDeviceKeysUploaded(true)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,7 @@ internal interface IMXCryptoStore {
fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest?
fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
fun getGossipingEventsTrail(): List<Event>

fun setDeviceKeysUploaded(uploaded: Boolean)
fun getDeviceKeysUploaded(): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,18 @@ internal class RealmCryptoStore @Inject constructor(
} ?: false
}

override fun setDeviceKeysUploaded(uploaded: Boolean) {
doRealmTransaction(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer = uploaded
}
}

override fun getDeviceKeysUploaded(): Boolean {
return doWithRealm(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
} ?: false
}

override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>) {
doRealmTransaction(realmConfiguration) {
// Reset all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
// 0, 1, 2: legacy Riot-Android
// 3: migrate to RiotX schema
// 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
const val CRYPTO_STORE_SCHEMA_VERSION = 10L
const val CRYPTO_STORE_SCHEMA_VERSION = 11L
}

override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
Expand All @@ -70,6 +70,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
if (oldVersion <= 7) migrateTo8(realm)
if (oldVersion <= 8) migrateTo9(realm)
if (oldVersion <= 9) migrateTo10(realm)
if (oldVersion <= 10) migrateTo11(realm)
}

private fun migrateTo1Legacy(realm: DynamicRealm) {
Expand Down Expand Up @@ -176,13 +177,14 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
}
}

// Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper2
// Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper
realm.schema.get("OlmInboundGroupSessionEntity")
?.transform { obj ->
try {
val oldSerializedData = obj.getString("olmInboundGroupSessionData")
deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
val newOlmInboundGroupSessionWrapper2 = OlmInboundGroupSessionWrapper2()
val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
.apply {
olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
roomId = mxOlmInboundGroupSession2.mRoomId
Expand All @@ -191,7 +193,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
}

obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper2))
obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
}
} catch (e: Exception) {
Timber.e(e, "Error")
Expand Down Expand Up @@ -445,4 +447,11 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
.addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java)
.setNullable(SharedSessionEntityFields.CHAIN_INDEX, true)
}

// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
private fun migrateTo11(realm: DynamicRealm) {
Timber.d("Step 10 -> 11")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ internal open class CryptoMetadataEntity(
// The keys backup version currently used. Null means no backup.
var backupVersion: String? = null,

// The device keys has been sent to the homeserver
var deviceKeysSentToServer: Boolean = false,

var xSignMasterPrivateKey: String? = null,
var xSignUserPrivateKey: String? = null,
var xSignSelfSignedPrivateKey: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ internal class LocalEchoEventFactory @Inject constructor(
val body = bodyForReply(originalEvent.getLastMessageContent(), originalEvent.root.getClearContent().toModel())
val replyFormatted = REPLY_PATTERN.format(
permalink,
stringProvider.getString(R.string.message_reply_to_prefix),
userLink,
originalEvent.senderInfo.disambiguatedDisplayName,
body.takeFormatted(),
Expand Down Expand Up @@ -372,7 +371,6 @@ internal class LocalEchoEventFactory @Inject constructor(
val body = bodyForReply(eventReplied.getLastMessageContent(), eventReplied.root.getClearContent().toModel())
val replyFormatted = REPLY_PATTERN.format(
permalink,
stringProvider.getString(R.string.message_reply_to_prefix),
userLink,
userId,
body.takeFormatted(),
Expand Down Expand Up @@ -434,10 +432,10 @@ internal class LocalEchoEventFactory @Inject constructor(
TextContent(content.body, formattedText)
}
}
MessageType.MSGTYPE_FILE -> return TextContent(stringProvider.getString(R.string.reply_to_a_file))
MessageType.MSGTYPE_AUDIO -> return TextContent(stringProvider.getString(R.string.reply_to_an_audio_file))
MessageType.MSGTYPE_IMAGE -> return TextContent(stringProvider.getString(R.string.reply_to_an_image))
MessageType.MSGTYPE_VIDEO -> return TextContent(stringProvider.getString(R.string.reply_to_a_video))
MessageType.MSGTYPE_FILE -> return TextContent("sent a file.")
MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.")
MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.")
MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.")
else -> return TextContent(content?.body ?: "")
}
}
Expand Down Expand Up @@ -489,6 +487,6 @@ internal class LocalEchoEventFactory @Inject constructor(
// </blockquote>
// </mx-reply>
// No whitespace because currently breaks temporary formatted text to Span
const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">%s</a><a href="%s">%s</a><br />%s</blockquote></mx-reply>%s"""
const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">In reply to</a> <a href="%s">%s</a><br />%s</blockquote></mx-reply>%s"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI
import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI
import im.vector.matrix.android.internal.task.Task
Expand Down Expand Up @@ -106,6 +107,12 @@ internal class DefaultGetWellknownTask @Inject constructor(
}
} catch (throwable: Throwable) {
when (throwable) {
is UnrecognizedCertificateException -> {
throw Failure.UnrecognizedCertificateFailure(
"https://$domain",
throwable.fingerprint
)
}
is Failure.NetworkConnection -> {
WellknownResult.Ignore
}
Expand Down
6 changes: 0 additions & 6 deletions matrix-sdk-android/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,6 @@
<string name="summary_user_sent_sticker">أرسل ⁨%1$s⁩ ملصقا.</string>

<string name="notice_avatar_changed_too">(تغيّرت الصورة أيضا)</string>
<string name="message_reply_to_prefix">ردا على</string>

<string name="reply_to_an_image">أرسل صورة.</string>
<string name="reply_to_a_video">أرسل فديوهًا.</string>
<string name="reply_to_an_audio_file">أرسل ملف صوت.</string>
<string name="reply_to_a_file">أرسل ملفًا.</string>

<string name="room_displayname_invite_from">دعوة من ⁨%s⁩</string>
<string name="room_displayname_empty_room">غرفة فارغة</string>
Expand Down
7 changes: 0 additions & 7 deletions matrix-sdk-android/src/main/res/values-az/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
<string name="notice_crypto_unable_to_decrypt">** Şifrəni aça bilmir: %s **</string>
<string name="notice_crypto_error_unkwown_inbound_session_id">Göndərənin cihazı bu mesaj üçün açarları bizə göndərməyib.</string>

<string name="message_reply_to_prefix">Cavab olaraq</string>

<string name="could_not_redact">Redaktə etmək olmur</string>
<string name="unable_to_send_message">Mesaj göndərmək olmur</string>

Expand All @@ -69,11 +67,6 @@
<string name="medium_email">Elektron poçt ünvanı</string>
<string name="medium_phone_number">Telefon nömrəsi</string>

<string name="reply_to_an_image">şəkil göndərdi.</string>
<string name="reply_to_a_video">video göndərdi.</string>
<string name="reply_to_an_audio_file">səs faylı göndərdi.</string>
<string name="reply_to_a_file">fayl göndərdi.</string>

<string name="room_displayname_invite_from">%s-dən dəvət</string>
<string name="room_displayname_room_invite">Otağa dəvət</string>

Expand Down
Loading

0 comments on commit 51abdb6

Please sign in to comment.