Merge branch 'vector-im:develop' into develop

This commit is contained in:
hanthor 2022-05-06 14:57:11 -04:00 committed by GitHub
commit e1960e9593
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
278 changed files with 2721 additions and 1636 deletions

1
changelog.d/5151.misc Normal file
View file

@ -0,0 +1 @@
Improve threads rendering in the main timeline

1
changelog.d/5953.misc Normal file
View file

@ -0,0 +1 @@
Reformatted project code

View file

@ -192,7 +192,7 @@ dependencies {
implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.47'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.48'
testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.7.3'

View file

@ -37,7 +37,10 @@ class PermalinkParserTest {
Assert.assertTrue("Should be parsed as email invite but was ${parsedLink::class.java}", parsedLink is PermalinkData.RoomEmailInviteLink)
parsedLink as PermalinkData.RoomEmailInviteLink
Assert.assertEquals("!MRBNLPtFnMAazZVPMO:matrix.org", parsedLink.roomId)
Assert.assertEquals("XmOwRZnSFabCRhTywFbJWKXWVNPysOpXIbroMGaUymqkJSvHeVKRsjHajwjCYdBsvGSvHauxbKfJmOxtXldtyLnyBMLKpBQCMzyYggrdapbVIceWZBtmslOQrXLABRoe", parsedLink.token)
Assert.assertEquals(
"XmOwRZnSFabCRhTywFbJWKXWVNPysOpXIbroMGaUymqkJSvHeVKRsjHajwjCYdBsvGSvHauxbKfJmOxtXldtyLnyBMLKpBQCMzyYggrdapbVIceWZBtmslOQrXLABRoe",
parsedLink.token
)
Assert.assertEquals("vector.im", parsedLink.identityServer)
Assert.assertEquals("Team2", parsedLink.roomName)
Assert.assertEquals("hiphop5", parsedLink.inviterName)
@ -45,7 +48,8 @@ class PermalinkParserTest {
@Test
fun testParseLinkWIthEvent() {
val rawInvite = "https://matrix.to/#/!OGEhHVWSdvArJzumhm:matrix.org/\$xuvJUVDJnwEeVjPx029rAOZ50difpmU_5gZk_T0jGfc?via=matrix.org&via=libera.chat&via=matrix.example.io"
val rawInvite =
"https://matrix.to/#/!OGEhHVWSdvArJzumhm:matrix.org/\$xuvJUVDJnwEeVjPx029rAOZ50difpmU_5gZk_T0jGfc?via=matrix.org&via=libera.chat&via=matrix.example.io"
val parsedLink = PermalinkParser.parse(rawInvite)
Assert.assertTrue("Should be parsed as room link", parsedLink is PermalinkData.RoomLink)

View file

@ -21,5 +21,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import java.util.concurrent.Executors
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main,
Executors.newSingleThreadExecutor().asCoroutineDispatcher())
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(
Main, Main, Main, Main,
Executors.newSingleThreadExecutor().asCoroutineDispatcher()
)

View file

@ -67,9 +67,11 @@ class DeactivateAccountTest : InstrumentedTest {
val throwable = commonTestHelper.logAccountWithError(session.myUserId, TestConstants.PASSWORD)
// Test the error
assertTrue(throwable is Failure.ServerError &&
throwable.error.code == MatrixError.M_USER_DEACTIVATED &&
throwable.error.message == "This account has been deactivated")
assertTrue(
throwable is Failure.ServerError &&
throwable.error.code == MatrixError.M_USER_DEACTIVATED &&
throwable.error.message == "This account has been deactivated"
)
// Try to create an account with the deactivate account user id, it will fail (M_USER_IN_USE)
val hs = commonTestHelper.createHomeServerConfig()
@ -95,8 +97,10 @@ class DeactivateAccountTest : InstrumentedTest {
// Test the error
accountCreationError.let {
assertTrue(it is Failure.ServerError &&
it.error.code == MatrixError.M_USER_IN_USE)
assertTrue(
it is Failure.ServerError &&
it.error.code == MatrixError.M_USER_IN_USE
)
}
// No need to close the session, it has been deactivated

View file

@ -291,7 +291,8 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
)
)
}
}, it)
}, it
)
}
}
@ -308,7 +309,8 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
requestID,
roomId,
bob.myUserId,
bob.sessionParams.credentials.deviceId!!)
bob.sessionParams.credentials.deviceId!!
)
// we should reach SHOW SAS on both
var alicePovTx: OutgoingSasVerificationTransaction? = null

View file

@ -29,15 +29,17 @@ import org.matrix.android.sdk.internal.raw.RawModule
import org.matrix.android.sdk.internal.settings.SettingsModule
import org.matrix.android.sdk.internal.util.system.SystemModule
@Component(modules = [
TestModule::class,
MatrixModule::class,
NetworkModule::class,
AuthModule::class,
RawModule::class,
SettingsModule::class,
SystemModule::class
])
@Component(
modules = [
TestModule::class,
MatrixModule::class,
NetworkModule::class,
AuthModule::class,
RawModule::class,
SettingsModule::class,
SystemModule::class
]
)
@MatrixScope
internal interface TestMatrixComponent : MatrixComponent {

View file

@ -76,9 +76,11 @@ class CryptoStoreTest : InstrumentedTest {
}
val olmSession1 = OlmSession().apply {
initOutboundSession(olmAccount1,
initOutboundSession(
olmAccount1,
olmAccount1.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
olmAccount1.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
olmAccount1.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first()
)
}
val sessionId1 = olmSession1.sessionIdentifier()
@ -93,9 +95,11 @@ class CryptoStoreTest : InstrumentedTest {
}
val olmSession2 = OlmSession().apply {
initOutboundSession(olmAccount2,
initOutboundSession(
olmAccount2,
olmAccount2.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
olmAccount2.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
olmAccount2.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first()
)
}
val sessionId2 = olmSession2.sessionIdentifier()

View file

@ -299,11 +299,13 @@ class E2eeSanityTests : InstrumentedTest {
}
val importedResult = testHelper.doSync<ImportRoomKeysResult> {
keysBackupService.restoreKeyBackupWithPassword(keyVersionResult!!,
keysBackupService.restoreKeyBackupWithPassword(
keyVersionResult!!,
keyBackupPassword,
null,
null,
null, it)
null, it
)
}
assertEquals(3, importedResult.totalNumberOfKeys)

View file

@ -93,9 +93,11 @@ class ExportEncryptionTest {
fail("## checkExportDecrypt1() failed : " + e.message)
}
assertEquals("## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -111,9 +113,11 @@ class ExportEncryptionTest {
fail("## checkExportDecrypt2() failed : " + e.message)
}
assertEquals("## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -129,9 +133,11 @@ class ExportEncryptionTest {
fail("## checkExportDecrypt3() failed : " + e.message)
}
assertEquals("## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -147,9 +153,11 @@ class ExportEncryptionTest {
fail("## checkExportEncrypt1() failed : " + e.message)
}
assertEquals("## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -165,9 +173,11 @@ class ExportEncryptionTest {
fail("## checkExportEncrypt2() failed : " + e.message)
}
assertEquals("## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -183,9 +193,11 @@ class ExportEncryptionTest {
fail("## checkExportEncrypt3() failed : " + e.message)
}
assertEquals("## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
@Test
@ -201,8 +213,10 @@ class ExportEncryptionTest {
fail("## checkExportEncrypt4() failed : " + e.message)
}
assertEquals("## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
assertEquals(
"## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
decodedString
)
}
}

View file

@ -171,7 +171,10 @@ class UnwedgingTest : InstrumentedTest {
// Let us wedge the session now. Set crypto state like after the first message
Timber.i("## CRYPTO | testUnwedging: wedge the session now. Set crypto state like after the first message")
aliceCryptoStore.storeSession(OlmSessionWrapper(deserializeFromRealm<OlmSession>(oldSession)!!), bobSession.cryptoService().getMyDevice().identityKey()!!)
aliceCryptoStore.storeSession(
OlmSessionWrapper(deserializeFromRealm<OlmSession>(oldSession)!!),
bobSession.cryptoService().getMyDevice().identityKey()!!
)
olmDevice.clearOlmSessionCache()
Thread.sleep(6_000)
@ -218,7 +221,8 @@ class UnwedgingTest : InstrumentedTest {
)
)
}
}, it)
}, it
)
}
// Wait until we received back the key

View file

@ -126,8 +126,16 @@ class XSigningTest : InstrumentedTest {
assertNull("Alice should not see bob User key", bobKeysFromAlicePOV.userKey())
assertNotNull("Alice can see bob SelfSigned key", bobKeysFromAlicePOV.selfSigningKey())
assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.masterKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey)
assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.selfSigningKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.selfSigningKey()?.unpaddedBase64PublicKey)
assertEquals(
"Bob keys from alice pov should match",
bobKeysFromAlicePOV.masterKey()?.unpaddedBase64PublicKey,
bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey
)
assertEquals(
"Bob keys from alice pov should match",
bobKeysFromAlicePOV.selfSigningKey()?.unpaddedBase64PublicKey,
bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.selfSigningKey()?.unpaddedBase64PublicKey
)
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())

View file

@ -145,7 +145,10 @@ class KeyShareTests : InstrumentedTest {
Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
Log.v("TEST", "=========================")
it.forEach { keyRequest ->
Log.v("TEST", "[ts${keyRequest.localCreationTimestamp}] requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId} is ${keyRequest.state}")
Log.v(
"TEST",
"[ts${keyRequest.localCreationTimestamp}] requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId} is ${keyRequest.state}"
)
}
Log.v("TEST", "=========================")
}
@ -164,8 +167,10 @@ class KeyShareTests : InstrumentedTest {
}
// Mark the device as trusted
aliceSession.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId,
aliceSession2.sessionParams.deviceId ?: "")
aliceSession.cryptoService().setDeviceVerification(
DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId,
aliceSession2.sessionParams.deviceId ?: ""
)
// Re request
aliceSession2.cryptoService().reRequestRoomKeyForEvent(receivedEvent.root)
@ -223,7 +228,8 @@ class KeyShareTests : InstrumentedTest {
)
)
}
}, it)
}, it
)
}
// Also bootstrap keybackup on first session
@ -282,8 +288,10 @@ class KeyShareTests : InstrumentedTest {
})
val txId = "m.testVerif12"
aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.deviceId
?: "", txId)
aliceVerificationService2.beginKeyVerification(
VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.deviceId
?: "", txId
)
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
@ -337,7 +345,8 @@ class KeyShareTests : InstrumentedTest {
)
)
}
}, it)
}, it
)
}
// Create an encrypted room and send a couple of messages
@ -371,7 +380,8 @@ class KeyShareTests : InstrumentedTest {
)
)
}
}, it)
}, it
)
}
// Let alice invite bob

View file

@ -147,13 +147,15 @@ class WithHeldTests : InstrumentedTest {
val aliceInterceptor = testHelper.getTestInterceptor(aliceSession)
// Simulate no OTK
aliceInterceptor!!.addRule(MockOkHttpInterceptor.SimpleRule(
"/keys/claim",
200,
"""
aliceInterceptor!!.addRule(
MockOkHttpInterceptor.SimpleRule(
"/keys/claim",
200,
"""
{ "one_time_keys" : {} }
"""
))
)
)
Log.d("#TEST", "Recovery :${aliceSession.sessionParams.credentials.accessToken}")
val roomAlicePov = aliceSession.getRoom(testData.roomId)!!
@ -184,7 +186,10 @@ class WithHeldTests : InstrumentedTest {
// Ensure that alice has marked the session to be shared with bob
val sessionId = eventBobPOV!!.root.content.toModel<EncryptedEventContent>()!!.sessionId!!
val chainIndex = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(bobSession.myUserId, bobSession.sessionParams.credentials.deviceId)
val chainIndex = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(
bobSession.myUserId,
bobSession.sessionParams.credentials.deviceId
)
Assert.assertEquals("Alice should have marked bob's device for this session", 0, chainIndex)
// Add a new device for bob
@ -202,7 +207,10 @@ class WithHeldTests : InstrumentedTest {
}
}
val chainIndex2 = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(bobSecondSession.myUserId, bobSecondSession.sessionParams.credentials.deviceId)
val chainIndex2 = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(
bobSecondSession.myUserId,
bobSecondSession.sessionParams.credentials.deviceId
)
Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2)

View file

@ -54,9 +54,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
generatePrivateKeyResult.iterations
)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@ -102,9 +104,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad password
val retrievedPrivateKey = retrievePrivateKeyWithPassword(BAD_PASSWORD,
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
BAD_PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
generatePrivateKeyResult.iterations
)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@ -122,9 +126,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
PASSWORD,
generatePrivateKeyResult.salt,
500_001)
500_001
)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@ -142,9 +148,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
val retrievedPrivateKey = retrievePrivateKeyWithPassword(
PASSWORD,
BAD_SALT,
generatePrivateKeyResult.iterations)
generatePrivateKeyResult.iterations
)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@ -168,7 +176,8 @@ class KeysBackupPasswordTest : InstrumentedTest {
116.toByte(), 224.toByte(), 229.toByte(), 224.toByte(), 9.toByte(), 3.toByte(), 178.toByte(), 162.toByte(),
120.toByte(), 23.toByte(), 108.toByte(), 218.toByte(), 22.toByte(), 61.toByte(), 241.toByte(), 200.toByte(),
235.toByte(), 173.toByte(), 236.toByte(), 100.toByte(), 115.toByte(), 247.toByte(), 33.toByte(), 132.toByte(),
195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte())
195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte()
)
assertArrayEquals(privateKeyBytes, retrievedPrivateKey)
}

View file

@ -272,10 +272,12 @@ class KeysBackupTest : InstrumentedTest {
assertNotNull(decryption)
// - Check decryptKeyBackupData() returns stg
val sessionData = keysBackup
.decryptKeyBackupData(keyBackupData,
.decryptKeyBackupData(
keyBackupData,
session.olmInboundGroupSession!!.sessionIdentifier(),
cryptoTestData.roomId,
decryption!!)
decryption!!
)
assertNotNull(sessionData)
// - Compare the decrypted megolm key with the original one
keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
@ -297,7 +299,8 @@ class KeysBackupTest : InstrumentedTest {
// - Restore the e2e backup from the homeserver
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
@ -680,7 +683,8 @@ class KeysBackupTest : InstrumentedTest {
val steps = ArrayList<StepProgressListener.Step>()
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password,
null,
null,
@ -771,7 +775,8 @@ class KeysBackupTest : InstrumentedTest {
// - Restore the e2e backup with the recovery key.
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
@ -1055,7 +1060,11 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup2.isEnabled)
// - Validate the old device from the new one
aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession2.myUserId, oldDeviceId)
aliceSession2.cryptoService().setDeviceVerification(
DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
aliceSession2.myUserId,
oldDeviceId
)
// -> Backup should automatically enable on the new device
val latch4 = CountDownLatch(1)

View file

@ -88,10 +88,12 @@ internal class KeysBackupTestHelper(
stateObserver.stopAndCheckStates(null)
return KeysBackupScenarioData(cryptoTestData,
return KeysBackupScenarioData(
cryptoTestData,
aliceKeys,
prepareKeysBackupDataResult,
aliceSession2)
aliceSession2
)
}
fun prepareAndCreateKeysBackupData(keysBackup: KeysBackupService,

View file

@ -207,14 +207,16 @@ class QuadSTests : InstrumentedTest {
// Assert that can decrypt with both keys
testHelper.runBlockingTest {
aliceSession.sharedSecretStorageService().getSecret("my.secret",
aliceSession.sharedSecretStorageService().getSecret(
"my.secret",
keyId1,
RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)!!
)
}
testHelper.runBlockingTest {
aliceSession.sharedSecretStorageService().getSecret("my.secret",
aliceSession.sharedSecretStorageService().getSecret(
"my.secret",
keyId2,
RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!!
)
@ -245,13 +247,15 @@ class QuadSTests : InstrumentedTest {
testHelper.runBlockingTest {
try {
aliceSession.sharedSecretStorageService().getSecret("my.secret",
aliceSession.sharedSecretStorageService().getSecret(
"my.secret",
keyId1,
RawBytesKeySpec.fromPassphrase(
"A bad passphrase",
key1Info.content?.passphrase?.salt ?: "",
key1Info.content?.passphrase?.iterations ?: 0,
null)
null
)
)
} catch (throwable: Throwable) {
assert(throwable is SharedSecretStorageError.BadMac)
@ -260,13 +264,15 @@ class QuadSTests : InstrumentedTest {
// Now try with correct key
testHelper.runBlockingTest {
aliceSession.sharedSecretStorageService().getSecret("my.secret",
aliceSession.sharedSecretStorageService().getSecret(
"my.secret",
keyId1,
RawBytesKeySpec.fromPassphrase(
passphrase,
key1Info.content?.passphrase?.salt ?: "",
key1Info.content?.passphrase?.iterations ?: 0,
null)
null
)
)
}
@ -321,7 +327,8 @@ class QuadSTests : InstrumentedTest {
keyId,
passphrase,
emptyKeySigner,
null)
null
)
}
assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")

View file

@ -75,10 +75,12 @@ class SASTest : InstrumentedTest {
}
bobVerificationService.addListener(bobListener)
val txID = aliceVerificationService.beginKeyVerification(VerificationMethod.SAS,
val txID = aliceVerificationService.beginKeyVerification(
VerificationMethod.SAS,
bobSession.myUserId,
bobSession.cryptoService().getMyDevice().deviceId,
null)
null
)
assertNotNull("Alice should have a started transaction", txID)
val aliceKeyTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID!!)
@ -467,8 +469,10 @@ class SASTest : InstrumentedTest {
val aliceTx = aliceVerificationService.getExistingTransaction(bobUserId, verificationSAS!!) as SASDefaultVerificationTransaction
val bobTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SASDefaultVerificationTransaction
assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
assertEquals(
"Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
bobTx.getShortCodeRepresentation(SasMode.DECIMAL)
)
cryptoTestData.cleanUp(testHelper)
}
@ -544,7 +548,8 @@ class SASTest : InstrumentedTest {
// Assert that devices are verified
val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? =
bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
@ -611,14 +616,16 @@ class SASTest : InstrumentedTest {
requestID!!,
cryptoTestData.roomId,
bobSession.myUserId,
bobSession.sessionParams.deviceId!!)
bobSession.sessionParams.deviceId!!
)
bobVerificationService.beginKeyVerificationInDMs(
VerificationMethod.SAS,
requestID!!,
cryptoTestData.roomId,
aliceSession.myUserId,
aliceSession.sessionParams.deviceId!!)
aliceSession.sessionParams.deviceId!!
)
// we should reach SHOW SAS on both
var alicePovTx: SasVerificationTransaction?

View file

@ -37,7 +37,8 @@ class QrCodeTest : InstrumentedTest {
sharedSecret = "MTIzNDU2Nzg"
)
private val value1 = "MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val value1 =
"MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val qrCode2 = QrCodeData.SelfVerifyingMasterKeyTrusted(
transactionId = "MaTransaction",
@ -46,7 +47,8 @@ class QrCodeTest : InstrumentedTest {
sharedSecret = "MTIzNDU2Nzg"
)
private val value2 = "MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val value2 =
"MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
private val qrCode3 = QrCodeData.SelfVerifyingMasterKeyNotTrusted(
transactionId = "MaTransaction",
@ -55,7 +57,8 @@ class QrCodeTest : InstrumentedTest {
sharedSecret = "MTIzNDU2Nzg"
)
private val value3 = "MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008B\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
private val value3 =
"MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008B\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
private val sharedSecretByteArray = "12345678".toByteArray(Charsets.ISO_8859_1)

View file

@ -175,7 +175,8 @@ class VerificationTest : InstrumentedTest {
)
)
}
}, callback)
}, callback
)
}
testHelper.doSync<Unit> { callback ->
@ -191,7 +192,8 @@ class VerificationTest : InstrumentedTest {
)
)
}
}, callback)
}, callback
)
}
val aliceVerificationService = aliceSession.cryptoService().verificationService()

View file

@ -71,10 +71,12 @@ class MarkdownParserTest : InstrumentedTest {
testIdentity("")
testIdentity("a")
testIdentity("1")
testIdentity("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et " +
"dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" +
"modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pari" +
"atur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
testIdentity(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et " +
"dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" +
"modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pari" +
"atur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
)
}
@Test
@ -294,16 +296,20 @@ class MarkdownParserTest : InstrumentedTest {
"$markdownPattern$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>"
)
}
// Test twice the same tag
"$markdownPattern$name$markdownPattern and $markdownPattern$name bis$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>"
)
}
val textBefore = "a"
@ -313,48 +319,60 @@ class MarkdownParserTest : InstrumentedTest {
"$textBefore$markdownPattern$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>"
)
}
// With text before and space
"$textBefore $markdownPattern$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>"
)
}
// With sticked text after
"$markdownPattern$name$markdownPattern$textAfter"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter"
)
}
// With space and text after
"$markdownPattern$name$markdownPattern $textAfter"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter"
)
}
// With sticked text before and text after
"$textBefore$markdownPattern$name$markdownPattern$textAfter"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter")
.expect(
expectedText = it,
expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter"
)
}
// With text before and after, with spaces
"$textBefore $markdownPattern$name$markdownPattern $textAfter"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter")
.expect(
expectedText = it,
expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter"
)
}
}
@ -366,16 +384,20 @@ class MarkdownParserTest : InstrumentedTest {
"$markdownPattern$name\n$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name$softBreak$name</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name$softBreak$name</$htmlExpectedTag>"
)
}
// With new line between two blocks
"$markdownPattern$name$markdownPattern\n$markdownPattern$name$markdownPattern"
.let {
markdownParser.parse(it)
.expect(expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><br /><$htmlExpectedTag>$name</$htmlExpectedTag>")
.expect(
expectedText = it,
expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><br /><$htmlExpectedTag>$name</$htmlExpectedTag>"
)
}
}

View file

@ -39,27 +39,35 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
"""{"a":["c":"b","d":"e"]}""",
"""{"a":["d":"b","c":"e"]}"""
).forEach {
assertEquals(it,
JsonCanonicalizer.canonicalize(it))
assertEquals(
it,
JsonCanonicalizer.canonicalize(it)
)
}
}
@Test
fun reorderTest() {
assertEquals("""{"a":true,"b":false}""",
JsonCanonicalizer.canonicalize("""{"b":false,"a":true}"""))
assertEquals(
"""{"a":true,"b":false}""",
JsonCanonicalizer.canonicalize("""{"b":false,"a":true}""")
)
}
@Test
fun realSampleTest() {
assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}"""))
assertEquals(
"""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}""")
)
}
@Test
fun doubleQuoteTest() {
assertEquals("{\"a\":\"\\\"\"}",
JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}"))
assertEquals(
"{\"a\":\"\\\"\"}",
JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}")
)
}
/* ==========================================================================================
@ -68,38 +76,52 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
@Test
fun matrixOrg001Test() {
assertEquals("""{}""",
JsonCanonicalizer.canonicalize("""{}"""))
assertEquals(
"""{}""",
JsonCanonicalizer.canonicalize("""{}""")
)
}
@Test
fun matrixOrg002Test() {
assertEquals("""{"one":1,"two":"Two"}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"one":1,"two":"Two"}""",
JsonCanonicalizer.canonicalize(
"""{
"one": 1,
"two": "Two"
}"""))
}"""
)
)
}
@Test
fun matrixOrg003Test() {
assertEquals("""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize(
"""{
"b": "2",
"a": "1"
}"""))
}"""
)
)
}
@Test
fun matrixOrg004Test() {
assertEquals("""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}"""))
assertEquals(
"""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}""")
)
}
@Test
fun matrixOrg005Test() {
assertEquals("""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
JsonCanonicalizer.canonicalize(
"""{
"auth": {
"success": true,
"mxid": "@john.doe:example.com",
@ -117,37 +139,53 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
]
}
}
}"""))
}"""
)
)
}
@Test
fun matrixOrg006Test() {
assertEquals("""{"a":"日本語"}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"a":"日本語"}""",
JsonCanonicalizer.canonicalize(
"""{
"a": "日本語"
}"""))
}"""
)
)
}
@Test
fun matrixOrg007Test() {
assertEquals("""{"日":1,"本":2}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"日":1,"本":2}""",
JsonCanonicalizer.canonicalize(
"""{
"": 2,
"": 1
}"""))
}"""
)
)
}
@Test
fun matrixOrg008Test() {
assertEquals("""{"a":"日"}""",
JsonCanonicalizer.canonicalize("{\"a\": \"\u65E5\"}"))
assertEquals(
"""{"a":"日"}""",
JsonCanonicalizer.canonicalize("{\"a\": \"\u65E5\"}")
)
}
@Test
fun matrixOrg009Test() {
assertEquals("""{"a":null}""",
JsonCanonicalizer.canonicalize("""{
assertEquals(
"""{"a":null}""",
JsonCanonicalizer.canonicalize(
"""{
"a": null
}"""))
}"""
)
)
}
}

View file

@ -26,9 +26,18 @@ class StringOrderTest {
@Test
fun testbasing() {
assertEquals("a", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("a", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
assertEquals("element", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("element", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
assertEquals("matrix", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("matrix", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
assertEquals(
"a",
StringOrderUtils.baseToString(StringOrderUtils.stringToBase("a", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
)
assertEquals(
"element",
StringOrderUtils.baseToString(StringOrderUtils.stringToBase("element", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
)
assertEquals(
"matrix",
StringOrderUtils.baseToString(StringOrderUtils.stringToBase("matrix", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
)
}
@Test

View file

@ -59,7 +59,8 @@ class ThreadMessagingTest : InstrumentedTest {
val sentMessages = commonTestHelper.sendTextMessage(
room = aliceRoom,
message = textMessage,
nbOfMessages = 1)
nbOfMessages = 1
)
val initMessage = sentMessages.first()
@ -73,7 +74,8 @@ class ThreadMessagingTest : InstrumentedTest {
room = aliceRoom,
message = "Reply In the above thread",
numberOfMessages = 1,
rootThreadEventId = initMessage.root.eventId.orEmpty())
rootThreadEventId = initMessage.root.eventId.orEmpty()
)
val replyInThread = repliesInThread.first()
replyInThread.root.isThread().shouldBeTrue()
@ -116,7 +118,8 @@ class ThreadMessagingTest : InstrumentedTest {
val sentMessages = commonTestHelper.sendTextMessage(
room = aliceRoom,
message = textMessage,
nbOfMessages = 1)
nbOfMessages = 1
)
val initMessage = sentMessages.first()
@ -134,7 +137,8 @@ class ThreadMessagingTest : InstrumentedTest {
room = bobRoom,
message = "Reply In the above thread",
numberOfMessages = 1,
rootThreadEventId = initMessage.root.eventId.orEmpty())
rootThreadEventId = initMessage.root.eventId.orEmpty()
)
val replyInThread = repliesInThread.first()
replyInThread.root.isThread().shouldBeTrue()
@ -190,7 +194,8 @@ class ThreadMessagingTest : InstrumentedTest {
val sentMessages = commonTestHelper.sendTextMessage(
room = aliceRoom,
message = textMessage,
nbOfMessages = 5)
nbOfMessages = 5
)
sentMessages.forEach {
it.root.isThread().shouldBeFalse()
@ -206,7 +211,8 @@ class ThreadMessagingTest : InstrumentedTest {
room = aliceRoom,
message = "Reply In the above thread",
numberOfMessages = 40,
rootThreadEventId = selectedInitMessage.root.eventId.orEmpty())
rootThreadEventId = selectedInitMessage.root.eventId.orEmpty()
)
repliesInThread.forEach {
it.root.isThread().shouldBeTrue()
@ -253,7 +259,8 @@ class ThreadMessagingTest : InstrumentedTest {
val sentMessages = commonTestHelper.sendTextMessage(
room = aliceRoom,
message = textMessage,
nbOfMessages = 5)
nbOfMessages = 5
)
sentMessages.forEach {
it.root.isThread().shouldBeFalse()
@ -270,7 +277,8 @@ class ThreadMessagingTest : InstrumentedTest {
room = aliceRoom,
message = "Alice reply In the above second thread message",
numberOfMessages = 35,
rootThreadEventId = secondMessage.root.eventId.orEmpty())
rootThreadEventId = secondMessage.root.eventId.orEmpty()
)
// Let's reply in timeline to that message from another user
val bobSession = cryptoTestData.secondSession!!
@ -282,14 +290,16 @@ class ThreadMessagingTest : InstrumentedTest {
room = bobRoom,
message = "Bob reply In the above first thread message",
numberOfMessages = 42,
rootThreadEventId = firstMessage.root.eventId.orEmpty())
rootThreadEventId = firstMessage.root.eventId.orEmpty()
)
// Bob will also reply in second thread 5 times
val bobThreadRepliesInSecondMessage = commonTestHelper.replyInThreadMessage(
room = bobRoom,
message = "Another Bob reply In the above second thread message",
numberOfMessages = 20,
rootThreadEventId = secondMessage.root.eventId.orEmpty())
rootThreadEventId = secondMessage.root.eventId.orEmpty()
)
aliceThreadRepliesInSecondMessage.forEach {
it.root.isThread().shouldBeTrue()

View file

@ -68,7 +68,8 @@ internal class ChunkEntityTest : InstrumentedTest {
roomId = ROOM_ID,
eventEntity = fakeEvent,
direction = PaginationDirection.FORWARDS,
roomMemberContentsByUser = emptyMap())
roomMemberContentsByUser = emptyMap()
)
chunk.timelineEvents.size shouldBeEqualTo 1
}
}
@ -84,12 +85,14 @@ internal class ChunkEntityTest : InstrumentedTest {
roomId = ROOM_ID,
eventEntity = fakeEvent,
direction = PaginationDirection.FORWARDS,
roomMemberContentsByUser = emptyMap())
roomMemberContentsByUser = emptyMap()
)
chunk.addTimelineEvent(
roomId = ROOM_ID,
eventEntity = fakeEvent,
direction = PaginationDirection.FORWARDS,
roomMemberContentsByUser = emptyMap())
roomMemberContentsByUser = emptyMap()
)
chunk.timelineEvents.size shouldBeEqualTo 1
}
}
@ -162,7 +165,8 @@ internal class ChunkEntityTest : InstrumentedTest {
roomId = roomId,
eventEntity = fakeEvent,
direction = direction,
roomMemberContentsByUser = emptyMap())
roomMemberContentsByUser = emptyMap()
)
}
}

View file

@ -71,7 +71,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
val sentMessages = commonTestHelper.sendTextMessage(
roomFromAlicePOV,
message,
numberOfMessagesToSend)
numberOfMessagesToSend
)
// Alice clear the cache and restart the sync
commonTestHelper.clearCacheAndSync(aliceSession)

View file

@ -94,7 +94,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
val firstMessageFromAliceId = commonTestHelper.sendTextMessage(
roomFromAlicePOV,
firstMessage,
30)
30
)
.last()
.eventId
@ -130,7 +131,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
commonTestHelper.sendTextMessage(
roomFromAlicePOV,
secondMessage,
30)
30
)
// Bob start to sync
bobSession.startSync(true)

View file

@ -64,7 +64,8 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
commonTestHelper.sendTextMessage(
roomFromAlicePOV,
message,
numberOfMessagesToSent)
numberOfMessagesToSent
)
val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30))
bobTimeline.start()

View file

@ -85,7 +85,8 @@ class SearchMessagesTest : InstrumentedTest {
commonTestHelper.sendTextMessage(
roomFromAlicePOV,
MESSAGE,
2)
2
)
val data = commonTestHelper.runBlockingTest {
block.invoke(cryptoTestData)

View file

@ -177,21 +177,27 @@ class SpaceHierarchyTest : InstrumentedTest {
val commonTestHelper = CommonTestHelper(context())
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
val spaceAInfo = createPublicSpace(
session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
)
)
/* val spaceBInfo = */ createPublicSpace(session, "SpaceB", listOf(
/* val spaceBInfo = */ createPublicSpace(
session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
)
)
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
val spaceCInfo = createPublicSpace(
session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
)
)
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@ -254,15 +260,19 @@ class SpaceHierarchyTest : InstrumentedTest {
val commonTestHelper = CommonTestHelper(context())
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
val spaceAInfo = createPublicSpace(
session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
)
)
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
val spaceCInfo = createPublicSpace(
session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
)
)
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@ -296,16 +306,20 @@ class SpaceHierarchyTest : InstrumentedTest {
val commonTestHelper = CommonTestHelper(context())
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
val spaceAInfo = createPublicSpace(
session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
)
)
val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
val spaceBInfo = createPublicSpace(
session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
)
)
// add B as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@ -315,10 +329,12 @@ class SpaceHierarchyTest : InstrumentedTest {
session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
}
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
val spaceCInfo = createPublicSpace(
session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
)
)
commonTestHelper.waitWithLatch { latch ->
@ -446,21 +462,27 @@ class SpaceHierarchyTest : InstrumentedTest {
val commonTestHelper = CommonTestHelper(context())
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
/* val spaceAInfo = */ createPublicSpace(session, "SpaceA", listOf(
/* val spaceAInfo = */ createPublicSpace(
session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
)
)
val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
val spaceBInfo = createPublicSpace(
session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
)
)
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
val spaceCInfo = createPublicSpace(
session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
)
)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
@ -494,10 +516,12 @@ class SpaceHierarchyTest : InstrumentedTest {
val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
val spaceAInfo = createPrivateSpace(aliceSession, "Private Space A", listOf(
val spaceAInfo = createPrivateSpace(
aliceSession, "Private Space A", listOf(
Triple("General", true /*suggested*/, true/*canonical*/),
Triple("Random", true, true)
))
)
)
commonTestHelper.runBlockingTest {
aliceSession.getRoom(spaceAInfo.spaceId)!!.membershipService().invite(bobSession.myUserId, null)

View file

@ -28,8 +28,12 @@ internal class MathsHtmlNodeRenderer(private val context: HtmlNodeRendererContex
val display = node.javaClass == DisplayMaths::class.java
val contents = node.firstChild // should be the only child
val latex = (contents as Text).literal
val attributes = context.extendAttributes(node, if (display) "div" else "span", Collections.singletonMap("data-mx-maths",
latex))
val attributes = context.extendAttributes(
node, if (display) "div" else "span", Collections.singletonMap(
"data-mx-maths",
latex
)
)
html.tag(if (display) "div" else "span", attributes)
html.tag("code")
context.render(contents)

View file

@ -132,9 +132,11 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
instance = Matrix(appContext, matrixConfiguration)
} else {
throw IllegalStateException("Matrix is not initialized properly." +
" If you want to manage your own Matrix instance use Matrix.createInstance" +
" otherwise you should call Matrix.initialize or let your application implement MatrixConfiguration.Provider.")
throw IllegalStateException(
"Matrix is not initialized properly." +
" If you want to manage your own Matrix instance use Matrix.createInstance" +
" otherwise you should call Matrix.initialize or let your application implement MatrixConfiguration.Provider."
)
}
}
return instance

View file

@ -1,127 +1,129 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.auth
import org.matrix.android.sdk.api.auth.data.LocalizedFlowDataLoginTerms
import org.matrix.android.sdk.api.auth.registration.TermPolicies
/**
* This method extract the policies from the login terms parameter, regarding the user language.
* For each policy, if user language is not found, the default language is used and if not found, the first url and name are used (not predictable)
*
* Example of Data:
* <pre>
* "m.login.terms": {
* "policies": {
* "privacy_policy": {
* "version": "1.0",
* "en": {
* "url": "http:\/\/matrix.org\/_matrix\/consent?v=1.0",
* "name": "Terms and Conditions"
* }
* }
* }
* }
*</pre>
*
* @param userLanguage the user language
* @param defaultLanguage the default language to use if the user language is not found for a policy in registrationFlowResponse
*/
fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> {
val result = ArrayList<LocalizedFlowDataLoginTerms>()
val policies = get("policies")
if (policies is Map<*, *>) {
policies.keys.forEach { policyName ->
val localizedFlowDataLoginTermsPolicyName = policyName as String
var localizedFlowDataLoginTermsVersion: String? = null
var localizedFlowDataLoginTermsLocalizedUrl: String? = null
var localizedFlowDataLoginTermsLocalizedName: String? = null
val policy = policies[policyName]
// Enter this policy
if (policy is Map<*, *>) {
// Version
localizedFlowDataLoginTermsVersion = policy["version"] as String?
var userLanguageUrlAndName: UrlAndName? = null
var defaultLanguageUrlAndName: UrlAndName? = null
var firstUrlAndName: UrlAndName? = null
// Search for language
policy.keys.forEach { policyKey ->
when (policyKey) {
"version" -> Unit // Ignore
userLanguage -> {
// We found the data for the user language
userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
defaultLanguage -> {
// We found default language
defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
else -> {
if (firstUrlAndName == null) {
// Get at least some data
firstUrlAndName = extractUrlAndName(policy[policyKey])
}
}
}
}
// Copy found language data by priority
when {
userLanguageUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
}
defaultLanguageUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
}
firstUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
}
}
}
result.add(LocalizedFlowDataLoginTerms(
policyName = localizedFlowDataLoginTermsPolicyName,
version = localizedFlowDataLoginTermsVersion,
localizedUrl = localizedFlowDataLoginTermsLocalizedUrl,
localizedName = localizedFlowDataLoginTermsLocalizedName
))
}
}
return result
}
private fun extractUrlAndName(policyData: Any?): UrlAndName? {
if (policyData is Map<*, *>) {
val url = policyData["url"] as String?
val name = policyData["name"] as String?
if (url != null && name != null) {
return UrlAndName(url, name)
}
}
return null
}
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.auth
import org.matrix.android.sdk.api.auth.data.LocalizedFlowDataLoginTerms
import org.matrix.android.sdk.api.auth.registration.TermPolicies
/**
* This method extract the policies from the login terms parameter, regarding the user language.
* For each policy, if user language is not found, the default language is used and if not found, the first url and name are used (not predictable)
*
* Example of Data:
* <pre>
* "m.login.terms": {
* "policies": {
* "privacy_policy": {
* "version": "1.0",
* "en": {
* "url": "http:\/\/matrix.org\/_matrix\/consent?v=1.0",
* "name": "Terms and Conditions"
* }
* }
* }
* }
*</pre>
*
* @param userLanguage the user language
* @param defaultLanguage the default language to use if the user language is not found for a policy in registrationFlowResponse
*/
fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> {
val result = ArrayList<LocalizedFlowDataLoginTerms>()
val policies = get("policies")
if (policies is Map<*, *>) {
policies.keys.forEach { policyName ->
val localizedFlowDataLoginTermsPolicyName = policyName as String
var localizedFlowDataLoginTermsVersion: String? = null
var localizedFlowDataLoginTermsLocalizedUrl: String? = null
var localizedFlowDataLoginTermsLocalizedName: String? = null
val policy = policies[policyName]
// Enter this policy
if (policy is Map<*, *>) {
// Version
localizedFlowDataLoginTermsVersion = policy["version"] as String?
var userLanguageUrlAndName: UrlAndName? = null
var defaultLanguageUrlAndName: UrlAndName? = null
var firstUrlAndName: UrlAndName? = null
// Search for language
policy.keys.forEach { policyKey ->
when (policyKey) {
"version" -> Unit // Ignore
userLanguage -> {
// We found the data for the user language
userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
defaultLanguage -> {
// We found default language
defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
}
else -> {
if (firstUrlAndName == null) {
// Get at least some data
firstUrlAndName = extractUrlAndName(policy[policyKey])
}
}
}
}
// Copy found language data by priority
when {
userLanguageUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
}
defaultLanguageUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
}
firstUrlAndName != null -> {
localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
}
}
}
result.add(
LocalizedFlowDataLoginTerms(
policyName = localizedFlowDataLoginTermsPolicyName,
version = localizedFlowDataLoginTermsVersion,
localizedUrl = localizedFlowDataLoginTermsLocalizedUrl,
localizedName = localizedFlowDataLoginTermsLocalizedName
)
)
}
}
return result
}
private fun extractUrlAndName(policyData: Any?): UrlAndName? {
if (policyData is Map<*, *>) {
val url = policyData["url"] as String?
val name = policyData["name"] as String?
if (url != null && name != null) {
return UrlAndName(url, name)
}
}
return null
}

View file

@ -88,8 +88,10 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult {
val isMandatory = flows?.all { type in it.stages.orEmpty() } == true
val stage = when (type) {
LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha(isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String)
?: "")
LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha(
isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String)
?: ""
)
LoginFlowTypes.DUMMY -> Stage.Dummy(isMandatory)
LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap<String, String>())
LoginFlowTypes.EMAIL_IDENTITY -> Stage.Email(isMandatory)

View file

@ -93,7 +93,8 @@ data class CryptoCrossSigningKey(
userId = userId,
usages = listOf(usage.value),
keys = mapOf("ed25519:$b64key" to b64key),
signatures = signMap)
signatures = signMap
)
}
}
}

View file

@ -68,7 +68,8 @@ interface FileService {
mxcUrl = messageContent.getFileUrl(),
fileName = messageContent.getFileName(),
mimeType = messageContent.mimeType,
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt())
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt()
)
/**
* Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION

View file

@ -379,9 +379,11 @@ internal class DefaultAuthenticationService @Inject constructor(
throw MatrixIdFailure.InvalidMatrixId
}
return getWellknownTask.execute(GetWellknownTask.Params(
domain = matrixId.getDomain(),
homeServerConnectionConfig = homeServerConnectionConfig)
return getWellknownTask.execute(
GetWellknownTask.Params(
domain = matrixId.getDomain(),
homeServerConnectionConfig = homeServerConnectionConfig
)
)
}
@ -390,13 +392,15 @@ internal class DefaultAuthenticationService @Inject constructor(
password: String,
initialDeviceName: String,
deviceId: String?): Session {
return directLoginTask.execute(DirectLoginTask.Params(
homeServerConnectionConfig = homeServerConnectionConfig,
userId = matrixId,
password = password,
deviceName = initialDeviceName,
deviceId = deviceId
))
return directLoginTask.execute(
DirectLoginTask.Params(
homeServerConnectionConfig = homeServerConnectionConfig,
userId = matrixId,
password = password,
deviceName = initialDeviceName,
deviceId = deviceId
)
)
}
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {

View file

@ -21,9 +21,11 @@ import io.realm.annotations.RealmModule
/**
* Realm module for authentication classes
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
SessionParamsEntity::class,
PendingSessionEntity::class
])
]
)
internal class AuthRealmModule

View file

@ -44,7 +44,8 @@ internal class PendingSessionMapper @Inject constructor(moshi: Moshi) {
resetPasswordData = resetPasswordData,
currentSession = entity.currentSession,
isRegistrationStarted = entity.isRegistrationStarted,
currentThreePidData = threePidData)
currentThreePidData = threePidData
)
}
fun map(sessionData: PendingSessionData?): PendingSessionEntity? {

View file

@ -54,6 +54,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
sessionParams.userId,
credentialsJson,
homeServerConnectionConfigJson,
sessionParams.isTokenValid)
sessionParams.isTokenValid
)
}
}

View file

@ -120,21 +120,25 @@ internal class DefaultRegistrationWizard(
RegisterAddThreePidTask.Params(
threePid,
pendingSessionData.clientSecret,
pendingSessionData.sendAttempt))
pendingSessionData.sendAttempt
)
)
pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1)
.also { pendingSessionStore.savePendingSessionData(it) }
val params = RegistrationParams(
auth = if (threePid is RegisterThreePid.Email) {
AuthParams.createForEmailIdentity(safeSession,
AuthParams.createForEmailIdentity(
safeSession,
ThreePidCredentials(
clientSecret = pendingSessionData.clientSecret,
sid = response.sid
)
)
} else {
AuthParams.createForMsisdnIdentity(safeSession,
AuthParams.createForMsisdnIdentity(
safeSession,
ThreePidCredentials(
clientSecret = pendingSessionData.clientSecret,
sid = response.sid

View file

@ -712,8 +712,10 @@ internal class DefaultCryptoService @Inject constructor(
}.foldToCallback(callback)
} else {
val algorithm = getEncryptionAlgorithm(roomId)
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
val reason = String.format(
MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON
)
Timber.tag(loggerTag.value).e("encryptEventContent() : failed $reason")
callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
}

View file

@ -137,10 +137,14 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
olmDevice.verifySignature(fingerprint, oneTimeKey.signalableJSONDictionary(), signature)
isVerified = true
} catch (e: Exception) {
Timber.tag(loggerTag.value).d(e, "verifyKeyAndStartSession() : Verify error for otk: ${oneTimeKey.signalableJSONDictionary()}," +
" signature:$signature fingerprint:$fingerprint")
Timber.tag(loggerTag.value).e("verifyKeyAndStartSession() : Verify error for ${deviceInfo.userId}|${deviceInfo.deviceId} " +
" - signable json ${oneTimeKey.signalableJSONDictionary()}")
Timber.tag(loggerTag.value).d(
e, "verifyKeyAndStartSession() : Verify error for otk: ${oneTimeKey.signalableJSONDictionary()}," +
" signature:$signature fingerprint:$fingerprint"
)
Timber.tag(loggerTag.value).e(
"verifyKeyAndStartSession() : Verify error for ${deviceInfo.userId}|${deviceInfo.deviceId} " +
" - signable json ${oneTimeKey.signalableJSONDictionary()}"
)
errorMessage = e.message
}

View file

@ -96,11 +96,13 @@ internal class MXMegolmDecryption(private val userId: String,
}
return runCatching {
olmDevice.decryptGroupMessage(encryptedEventContent.ciphertext,
olmDevice.decryptGroupMessage(
encryptedEventContent.ciphertext,
event.roomId,
timeline,
encryptedEventContent.sessionId,
encryptedEventContent.senderKey)
encryptedEventContent.senderKey
)
}
.fold(
{ olmDecryptionResult ->
@ -132,9 +134,11 @@ internal class MXMegolmDecryption(private val userId: String,
requestKeysForEvent(event, true)
}
// Encapsulate as withHeld exception
throw MXCryptoError.Base(MXCryptoError.ErrorType.KEYS_WITHHELD,
throw MXCryptoError.Base(
MXCryptoError.ErrorType.KEYS_WITHHELD,
withHeldInfo.code?.value ?: "",
withHeldInfo.reason)
withHeldInfo.reason
)
}
if (requestKeysOnFail) {
@ -144,7 +148,8 @@ internal class MXMegolmDecryption(private val userId: String,
throw MXCryptoError.Base(
MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX,
"UNKNOWN_MESSAGE_INDEX",
null)
null
)
}
val reason = String.format(MXCryptoError.OLM_REASON, throwable.olmException.message)
@ -153,7 +158,8 @@ internal class MXMegolmDecryption(private val userId: String,
throw MXCryptoError.Base(
MXCryptoError.ErrorType.OLM,
reason,
detailedReason)
detailedReason
)
}
if (throwable is MXCryptoError.Base) {
if (
@ -166,9 +172,11 @@ internal class MXMegolmDecryption(private val userId: String,
requestKeysForEvent(event, true)
}
// Encapsulate as withHeld exception
throw MXCryptoError.Base(MXCryptoError.ErrorType.KEYS_WITHHELD,
throw MXCryptoError.Base(
MXCryptoError.ErrorType.KEYS_WITHHELD,
withHeldInfo.code?.value ?: "",
withHeldInfo.reason)
withHeldInfo.reason
)
} else {
// This is un-used in Matrix Android SDK2, not sure if needed
// addEventToPendingList(event, timeline)
@ -298,13 +306,15 @@ internal class MXMegolmDecryption(private val userId: String,
}
Timber.tag(loggerTag.value).i("onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId,
val added = olmDevice.addInboundGroupSession(
roomKeyContent.sessionId,
roomKeyContent.sessionKey,
roomKeyContent.roomId,
senderKey,
forwardingCurve25519KeyChain,
keysClaimed,
exportFormat)
exportFormat
)
if (added) {
defaultKeysBackupService.maybeBackupKeys()

View file

@ -56,6 +56,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor(
sendToDeviceTask,
coroutineDispatchers,
cryptoCoroutineScope,
eventsManager)
eventsManager
)
}
}

View file

@ -337,8 +337,9 @@ internal class MXMegolmEncryption(
sessionId: String,
senderKey: String?,
code: WithHeldCode) {
Timber.tag(loggerTag.value).d("notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" +
" ${targets.joinToString { "${it.userId}|${it.deviceId}" }}"
Timber.tag(loggerTag.value).d(
"notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" +
" ${targets.joinToString { "${it.userId}|${it.deviceId}" }}"
)
val withHeldContent = RoomKeyWithHeldContent(
roomId = roomId,

View file

@ -36,6 +36,7 @@ internal class SharedWithHelper(
userId = deviceInfo.userId,
deviceId = deviceInfo.deviceId,
deviceIdentityKey = deviceInfo.identityKey() ?: "",
chainIndex = chainIndex)
chainIndex = chainIndex
)
}
}

View file

@ -45,20 +45,26 @@ internal class MXOlmDecryption(
override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
val olmEventContent = event.content.toModel<OlmEventContent>() ?: run {
Timber.tag(loggerTag.value).e("## decryptEvent() : bad event format")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_EVENT_FORMAT,
MXCryptoError.BAD_EVENT_FORMAT_TEXT_REASON)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.BAD_EVENT_FORMAT,
MXCryptoError.BAD_EVENT_FORMAT_TEXT_REASON
)
}
val cipherText = olmEventContent.ciphertext ?: run {
Timber.tag(loggerTag.value).e("## decryptEvent() : missing cipher text")
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_CIPHER_TEXT,
MXCryptoError.MISSING_CIPHER_TEXT_REASON)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.MISSING_CIPHER_TEXT,
MXCryptoError.MISSING_CIPHER_TEXT_REASON
)
}
val senderKey = olmEventContent.senderKey ?: run {
Timber.tag(loggerTag.value).e("## decryptEvent() : missing sender key")
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY,
MXCryptoError.MISSING_SENDER_KEY_TEXT_REASON)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.MISSING_SENDER_KEY,
MXCryptoError.MISSING_SENDER_KEY_TEXT_REASON
)
}
val messageAny = cipherText[olmDevice.deviceCurve25519Key] ?: run {
@ -98,52 +104,70 @@ internal class MXOlmDecryption(
}
if (olmPayloadContent.recipient != userId) {
Timber.tag(loggerTag.value).e("## decryptEvent() : Event ${event.eventId}:" +
" Intended recipient ${olmPayloadContent.recipient} does not match our id $userId")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT,
String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient))
Timber.tag(loggerTag.value).e(
"## decryptEvent() : Event ${event.eventId}:" +
" Intended recipient ${olmPayloadContent.recipient} does not match our id $userId"
)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.BAD_RECIPIENT,
String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient)
)
}
val recipientKeys = olmPayloadContent.recipientKeys ?: run {
Timber.tag(loggerTag.value).e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" +
" property; cannot prevent unknown-key attack")
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY,
String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys"))
Timber.tag(loggerTag.value).e(
"## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" +
" property; cannot prevent unknown-key attack"
)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.MISSING_PROPERTY,
String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys")
)
}
val ed25519 = recipientKeys["ed25519"]
if (ed25519 != olmDevice.deviceEd25519Key) {
Timber.tag(loggerTag.value).e("## decryptEvent() : Event ${event.eventId}: Intended recipient ed25519 key $ed25519 did not match ours")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT_KEY,
MXCryptoError.BAD_RECIPIENT_KEY_REASON)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.BAD_RECIPIENT_KEY,
MXCryptoError.BAD_RECIPIENT_KEY_REASON
)
}
if (olmPayloadContent.sender.isNullOrBlank()) {
Timber.tag(loggerTag.value)
.e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'sender' property; cannot prevent unknown-key attack")
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY,
String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender"))
throw MXCryptoError.Base(
MXCryptoError.ErrorType.MISSING_PROPERTY,
String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender")
)
}
if (olmPayloadContent.sender != event.senderId) {
Timber.tag(loggerTag.value)
.e("Event ${event.eventId}: sender ${olmPayloadContent.sender} does not match reported sender ${event.senderId}")
throw MXCryptoError.Base(MXCryptoError.ErrorType.FORWARDED_MESSAGE,
String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender))
throw MXCryptoError.Base(
MXCryptoError.ErrorType.FORWARDED_MESSAGE,
String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)
)
}
if (olmPayloadContent.roomId != event.roomId) {
Timber.tag(loggerTag.value)
.e("## decryptEvent() : Event ${event.eventId}: room ${olmPayloadContent.roomId} does not match reported room ${event.roomId}")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ROOM,
String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId))
throw MXCryptoError.Base(
MXCryptoError.ErrorType.BAD_ROOM,
String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId)
)
}
val keys = olmPayloadContent.keys ?: run {
Timber.tag(loggerTag.value).e("## decryptEvent failed : null keys")
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT,
MXCryptoError.MISSING_CIPHER_TEXT_REASON)
throw MXCryptoError.Base(
MXCryptoError.ErrorType.UNABLE_TO_DECRYPT,
MXCryptoError.MISSING_CIPHER_TEXT_REASON
)
}
return MXEventDecryptionResult(

View file

@ -26,6 +26,7 @@ internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice:
fun create(): MXOlmDecryption {
return MXOlmDecryption(
olmDevice,
userId)
userId
)
}
}

View file

@ -38,6 +38,7 @@ internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice:
cryptoStore,
messageEncrypter,
deviceListManager,
ensureOlmSessionsForUsersAction)
ensureOlmSessionsForUsersAction
)
}
}

View file

@ -566,8 +566,10 @@ internal class DefaultCrossSigningService @Inject constructor(
}
// Sign the other MasterKey with our UserSigning key
val newSignature = JsonCanonicalizer.getCanonicalJson(Map::class.java,
otherMasterKeys.signalableJSONDictionary()).let { userPkSigning?.sign(it) }
val newSignature = JsonCanonicalizer.getCanonicalJson(
Map::class.java,
otherMasterKeys.signalableJSONDictionary()
).let { userPkSigning?.sign(it) }
if (newSignature == null) {
// race??
@ -684,7 +686,8 @@ internal class DefaultCrossSigningService @Inject constructor(
val otherSSKSignature = otherDevice.signatures?.get(otherUserId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
?: return legacyFallbackTrust(
locallyTrusted,
DeviceTrustResult.MissingDeviceSignature(otherDeviceId, otherKeys.selfSigningKey()
DeviceTrustResult.MissingDeviceSignature(
otherDeviceId, otherKeys.selfSigningKey()
?.unpaddedBase64PublicKey
?: ""
)
@ -733,7 +736,8 @@ internal class DefaultCrossSigningService @Inject constructor(
val otherSSKSignature = otherDevice.signatures?.get(otherKeys.userId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
?: return legacyFallbackTrust(
locallyTrusted,
DeviceTrustResult.MissingDeviceSignature(otherDevice.deviceId, otherKeys.selfSigningKey()
DeviceTrustResult.MissingDeviceSignature(
otherDevice.deviceId, otherKeys.selfSigningKey()
?.unpaddedBase64PublicKey
?: ""
)

View file

@ -516,7 +516,8 @@ internal class DefaultKeysBackupService @Inject constructor(
UpdateKeysBackupVersionBody(
algorithm = keysBackupVersion.algorithm,
authData = newMegolmBackupAuthDataWithNewSignature.toJsonDict(),
version = keysBackupVersion.version)
version = keysBackupVersion.version
)
}
// And send it to the homeserver
@ -719,14 +720,18 @@ internal class DefaultKeysBackupService @Inject constructor(
}
}
}
Timber.v("restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
" of $sessionsFromHsCount from the backup store on the homeserver")
Timber.v(
"restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
" of $sessionsFromHsCount from the backup store on the homeserver"
)
// Do not trigger a backup for them if they come from the backup version we are using
val backUp = keysVersionResult.version != keysBackupVersion?.version
if (backUp) {
Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up" +
" to backup version: ${keysBackupVersion?.version}")
Timber.v(
"restoreKeysWithRecoveryKey: Those keys will be backed up" +
" to backup version: ${keysBackupVersion?.version}"
)
}
// Import them into the crypto store
@ -801,11 +806,15 @@ internal class DefaultKeysBackupService @Inject constructor(
// Get key for the room and for the session
val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version))
// Convert to KeysBackupData
KeysBackupData(mutableMapOf(
roomId to RoomKeysBackupData(mutableMapOf(
sessionId to data
))
))
KeysBackupData(
mutableMapOf(
roomId to RoomKeysBackupData(
mutableMapOf(
sessionId to data
)
)
)
)
} else if (roomId != null) {
// Get all keys for the room
val data = getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version))
@ -1326,7 +1335,8 @@ internal class DefaultKeysBackupService @Inject constructor(
"sender_key" to sessionData.senderKey,
"sender_claimed_keys" to sessionData.senderClaimedKeys,
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
"session_key" to sessionData.sessionKey)
"session_key" to sessionData.sessionKey
)
val json = MoshiProvider.providesMoshi()
.adapter(Map::class.java)
@ -1354,7 +1364,8 @@ internal class DefaultKeysBackupService @Inject constructor(
sessionData = mapOf(
"ciphertext" to encryptedSessionBackupData.mCipherText,
"mac" to encryptedSessionBackupData.mMac,
"ephemeral" to encryptedSessionBackupData.mEphemeralKey)
"ephemeral" to encryptedSessionBackupData.mEphemeralKey
)
)
}

View file

@ -40,7 +40,8 @@ internal class DefaultDeleteRoomSessionDataTask @Inject constructor(
roomKeysApi.deleteRoomSessionData(
params.roomId,
params.sessionId,
params.version)
params.version
)
}
}
}

View file

@ -38,7 +38,8 @@ internal class DefaultDeleteRoomSessionsDataTask @Inject constructor(
return executeRequest(globalErrorReceiver) {
roomKeysApi.deleteRoomSessionsData(
params.roomId,
params.version)
params.version
)
}
}
}

View file

@ -41,7 +41,8 @@ internal class DefaultGetRoomSessionDataTask @Inject constructor(
roomKeysApi.getRoomSessionData(
params.roomId,
params.sessionId,
params.version)
params.version
)
}
}
}

View file

@ -39,7 +39,8 @@ internal class DefaultGetRoomSessionsDataTask @Inject constructor(
return executeRequest(globalErrorReceiver) {
roomKeysApi.getRoomSessionsData(
params.roomId,
params.version)
params.version
)
}
}
}

View file

@ -44,7 +44,8 @@ internal class DefaultStoreRoomSessionDataTask @Inject constructor(
params.roomId,
params.sessionId,
params.version,
params.keyBackupData)
params.keyBackupData
)
}
}
}

View file

@ -42,7 +42,8 @@ internal class DefaultStoreRoomSessionsDataTask @Inject constructor(
roomKeysApi.storeRoomSessionsData(
params.roomId,
params.version,
params.roomKeysBackupData)
params.roomKeysBackupData
)
}
}
}

View file

@ -40,7 +40,8 @@ internal class DefaultStoreSessionsDataTask @Inject constructor(
return executeRequest(globalErrorReceiver) {
roomKeysApi.storeSessionsData(
params.version,
params.keysBackupData)
params.keysBackupData
)
}
}
}

View file

@ -213,7 +213,8 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
secretKey.privateKey,
ByteArray(32) { 0.toByte() },
secretName.toByteArray(),
64)
64
)
// The first 32 bytes are used as the AES key, and the next 32 bytes are used as the MAC key
val aesKey = pseudoRandomKey.copyOfRange(0, 32)
@ -255,7 +256,8 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
secretKey.privateKey,
ByteArray(32) { 0.toByte() },
secretName.toByteArray(),
64)
64
)
// The first 32 bytes are used as the AES key, and the next 32 bytes are used as the MAC key
val aesKey = pseudoRandomKey.copyOfRange(0, 32)

View file

@ -38,7 +38,8 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti
/**
* Realm module for Crypto store classes
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
CryptoMetadataEntity::class,
CryptoRoomEntity::class,
@ -57,5 +58,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti
WithHeldSessionEntity::class,
SharedSessionEntity::class,
OutboundGroupSessionInfoEntity::class
])
]
)
internal class RealmCryptoStoreModule

View file

@ -27,11 +27,13 @@ import javax.inject.Inject
internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
private val signaturesAdapter = moshi.adapter<Map<String, Map<String, String>>>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
private val signaturesAdapter = moshi.adapter<Map<String, Map<String, String>>>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)
)
fun update(keyInfo: KeyInfoEntity, cryptoCrossSigningKey: CryptoCrossSigningKey) {
// update signatures?

View file

@ -72,16 +72,20 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
))
val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
val listMigrationAdapter = moshi.adapter<List<String>>(
Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
)
)
val mapMigrationAdapter = moshi.adapter<JsonDict>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)
)
realm.schema.get("DeviceInfoEntity")
?.addField(DeviceInfoEntityFields.USER_ID, String::class.java)

View file

@ -27,21 +27,27 @@ import timber.log.Timber
internal object CryptoMapper {
private val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
private val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
))
private val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
private val mapOfStringMigrationAdapter = moshi.adapter<Map<String, Map<String, String>>>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
private val listMigrationAdapter = moshi.adapter<List<String>>(
Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
)
)
private val mapMigrationAdapter = moshi.adapter<JsonDict>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)
)
private val mapOfStringMigrationAdapter = moshi.adapter<Map<String, Map<String, String>>>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)
)
internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity {
return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId))
@ -91,11 +97,13 @@ internal object CryptoMapper {
},
keys = deviceInfoEntity.keysMapJson?.let {
try {
moshi.adapter<Map<String, String>>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)).fromJson(it)
moshi.adapter<Map<String, String>>(
Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
)
).fromJson(it)
} catch (failure: Throwable) {
Timber.e(failure)
null

View file

@ -73,11 +73,13 @@ internal class DefaultSendEventTask @Inject constructor(
@Throws
private suspend fun handleEncryption(params: SendEventTask.Params): Event {
if (params.encrypt && !params.event.isEncrypted()) {
return encryptEventTask.execute(EncryptEventTask.Params(
params.event.roomId ?: "",
params.event,
listOf("m.relates_to")
))
return encryptEventTask.execute(
EncryptEventTask.Params(
params.event.roomId ?: "",
params.event,
listOf("m.relates_to")
)
)
}
return params.event
}

View file

@ -64,11 +64,13 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
private suspend fun handleEncryption(params: SendVerificationMessageTask.Params): Event {
if (cryptoSessionInfoProvider.isRoomEncrypted(params.event.roomId ?: "")) {
try {
return encryptEventTask.execute(EncryptEventTask.Params(
params.event.roomId ?: "",
params.event,
listOf("m.relates_to")
))
return encryptEventTask.execute(
EncryptEventTask.Params(
params.event.roomId ?: "",
params.event,
listOf("m.relates_to")
)
)
} catch (throwable: Throwable) {
// We said it's ok to send verification request in clear
}

View file

@ -53,7 +53,8 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
transactionId,
otherUserID,
null,
isIncoming = true),
isIncoming = true
),
IncomingSasVerificationTransaction {
override val uxState: IncomingSasVerificationTransaction.UxState

View file

@ -50,7 +50,8 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
transactionId,
otherUserId,
otherDeviceId,
isIncoming = false),
isIncoming = false
),
OutgoingSasVerificationTransaction {
override val uxState: OutgoingSasVerificationTransaction.UxState

View file

@ -105,8 +105,10 @@ internal abstract class DefaultVerificationTransaction(
private fun setDeviceVerified(userId: String, deviceId: String) {
// TODO should not override cross sign status
setDeviceVerificationAction.handle(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
setDeviceVerificationAction.handle(
DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
userId,
deviceId)
deviceId
)
}
}

View file

@ -58,7 +58,8 @@ internal abstract class SASDefaultVerificationTransaction(
transactionId,
otherUserId,
otherDeviceId,
isIncoming),
isIncoming
),
SasVerificationTransaction {
companion object {
@ -297,9 +298,11 @@ internal abstract class SASDefaultVerificationTransaction(
return
}
trust(otherMasterKeyIsVerified,
trust(
otherMasterKeyIsVerified,
verifiedDevices,
eventuallyMarkMyMasterKeyAsTrusted = otherMasterKey?.trustLevel?.isVerified() == false)
eventuallyMarkMyMasterKeyAsTrusted = otherMasterKey?.trustLevel?.isVerified() == false
)
}
override fun cancel() {

View file

@ -54,7 +54,8 @@ internal class DefaultQrCodeVerificationTransaction(
transactionId,
otherUserId,
otherDeviceId,
isIncoming),
isIncoming
),
QrCodeVerificationTransaction {
override val qrCodeText: String?

View file

@ -56,7 +56,8 @@ internal sealed class QrCodeData(
transactionId,
userMasterCrossSigningPublicKey,
otherUserMasterCrossSigningPublicKey,
sharedSecret)
sharedSecret
)
/**
* self-verifying in which the current device does trust the master key
@ -77,7 +78,8 @@ internal sealed class QrCodeData(
transactionId,
userMasterCrossSigningPublicKey,
otherDeviceKey,
sharedSecret)
sharedSecret
)
/**
* self-verifying in which the current device does not yet trust the master key
@ -98,5 +100,6 @@ internal sealed class QrCodeData(
transactionId,
deviceKey,
userMasterCrossSigningPublicKey,
sharedSecret)
sharedSecret
)
}

View file

@ -207,8 +207,10 @@ internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: Stri
?.eventId
?.let { editedEventId ->
TimelineEventEntity.where(realm, roomId, eventId = editedEventId).findFirst()?.let { editedEvent ->
it.root.threadDetails = it.root.threadDetails?.copy(lastRootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary()
?: "(edited)")
it.root.threadDetails = it.root.threadDetails?.copy(
lastRootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary()
?: "(edited)"
)
it
} ?: it
} ?: it
@ -341,7 +343,8 @@ internal fun updateNotificationsNew(roomId: String, realm: Realm, currentUserId:
realm = realm,
roomId = roomId,
rootThreadEventId = eventId,
senderId = currentUserId)
senderId = currentUserId
)
val rootThreadEventEntity = EventEntity.where(realm, eventId).findFirst()
if (isUserParticipating) {

View file

@ -24,7 +24,8 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
/**
* Realm module for Session
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
ChunkEntity::class,
EventEntity::class,
@ -71,5 +72,6 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
SpaceParentSummaryEntity::class,
UserPresenceEntity::class,
ThreadSummaryEntity::class
])
]
)
internal class SessionRealmModule

View file

@ -43,15 +43,17 @@ import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
import org.matrix.olm.OlmManager
import java.io.File
@Component(modules = [
MatrixModule::class,
NetworkModule::class,
AuthModule::class,
RawModule::class,
SettingsModule::class,
SystemModule::class,
NoOpTestModule::class
])
@Component(
modules = [
MatrixModule::class,
NetworkModule::class,
AuthModule::class,
RawModule::class,
SettingsModule::class,
SystemModule::class,
NoOpTestModule::class
]
)
@MatrixScope
internal interface MatrixComponent {

View file

@ -36,7 +36,8 @@ internal object MatrixModule {
@Provides
@MatrixScope
fun providesMatrixCoroutineDispatchers(): MatrixCoroutineDispatchers {
return MatrixCoroutineDispatchers(io = Dispatchers.IO,
return MatrixCoroutineDispatchers(
io = Dispatchers.IO,
computation = Dispatchers.Default,
main = Dispatchers.Main,
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),

View file

@ -46,17 +46,18 @@ internal object MoshiProvider {
.add(TlsVersionMoshiAdapter())
// Use addLast here so we can inject a SplitLazyRoomSyncJsonAdapter later to override the default parsing.
.addLast(DefaultLazyRoomSyncEphemeralJsonAdapter())
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
.registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
.registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
.registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
.registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
.registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
.registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
.registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
.registerSubtype(MessageVerificationRequestContent::class.java, MessageType.MSGTYPE_VERIFICATION_REQUEST)
.registerSubtype(MessagePollResponseContent::class.java, MessageType.MSGTYPE_POLL_RESPONSE)
.add(
RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
.registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
.registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
.registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
.registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
.registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
.registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
.registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
.registerSubtype(MessageVerificationRequestContent::class.java, MessageType.MSGTYPE_VERIFICATION_REQUEST)
.registerSubtype(MessagePollResponseContent::class.java, MessageType.MSGTYPE_POLL_RESPONSE)
)
.add(SerializeNulls.JSON_ADAPTER_FACTORY)
.build()

View file

@ -84,9 +84,11 @@ internal class WorkManagerProvider @Inject constructor(
if (workInfo?.state?.isFinished == true) {
checkWorkerLiveState.removeObserver(this)
if (workInfo.state == WorkInfo.State.FAILED) {
throw RuntimeException("MatrixWorkerFactory is not being set on your worker configuration.\n" +
"Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +
"You can grab the instance through the Matrix class.")
throw RuntimeException(
"MatrixWorkerFactory is not being set on your worker configuration.\n" +
"Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +
"You can grab the instance through the Matrix class."
)
}
}
}

View file

@ -76,10 +76,12 @@ class WellKnown {
if (apiUrl != null &&
apiUrl.startsWith("https://") &&
uiUrl!!.startsWith("https://")) {
managers.add(WellKnownManagerConfig(
apiUrl = apiUrl,
uiUrl = uiUrl
))
managers.add(
WellKnownManagerConfig(
apiUrl = apiUrl,
uiUrl = uiUrl
)
)
}
}
}

View file

@ -63,8 +63,10 @@ internal class RuntimeJsonAdapterFactory<T>(
}
val fallbackAdapter = moshi.adapter<Any>(fallbackType)
val objectJsonAdapter = moshi.adapter(Any::class.java)
return RuntimeJsonAdapter(labelKey, labelToAdapter, typeToLabel,
objectJsonAdapter, fallbackAdapter).nullSafe()
return RuntimeJsonAdapter(
labelKey, labelToAdapter, typeToLabel,
objectJsonAdapter, fallbackAdapter
).nullSafe()
}
@Suppress("UNCHECKED_CAST")
@ -77,8 +79,10 @@ internal class RuntimeJsonAdapterFactory<T>(
override fun fromJson(reader: JsonReader): Any? {
val peekedToken = reader.peek()
if (peekedToken != JsonReader.Token.BEGIN_OBJECT) {
throw JsonDataException("Expected BEGIN_OBJECT but was " + peekedToken +
" at path " + reader.path)
throw JsonDataException(
"Expected BEGIN_OBJECT but was " + peekedToken +
" at path " + reader.path
)
}
val jsonValue = reader.readJsonValue()
val jsonObject = jsonValue as Map<String, Any>?
@ -91,13 +95,15 @@ internal class RuntimeJsonAdapterFactory<T>(
override fun toJson(writer: JsonWriter, value: Any?) {
val type: Class<*> = value!!.javaClass
val label = typeToLabel[type]
?: throw IllegalArgumentException("Expected one of " +
typeToLabel.keys +
" but found " +
value +
", a " +
value.javaClass +
". Register this subtype.")
?: throw IllegalArgumentException(
"Expected one of " +
typeToLabel.keys +
" but found " +
value +
", a " +
value.javaClass +
". Register this subtype."
)
val adapter = labelToAdapter[label]!!
val jsonValue = adapter.toJsonValue(value) as Map<String, Any>?
val valueWithLabel: MutableMap<String, Any> = LinkedHashMap(1 + jsonValue!!.size)

View file

@ -35,8 +35,10 @@ internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): Re
arrayOf(
RoomSummaryEntityFields.IS_FAVOURITE,
RoomSummaryEntityFields.IS_LOW_PRIORITY,
RoomSummaryEntityFields.LAST_ACTIVITY_TIME),
arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING))
RoomSummaryEntityFields.LAST_ACTIVITY_TIME
),
arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING)
)
}
RoomSortOrder.NONE -> {
}

View file

@ -23,9 +23,11 @@ import org.matrix.android.sdk.internal.database.model.RawCacheEntity
/**
* Realm module for global classes
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
RawCacheEntity::class,
KnownServerUrlEntity::class
])
]
)
internal class GlobalRealmModule

View file

@ -68,7 +68,8 @@ import org.matrix.android.sdk.internal.session.widgets.WidgetModule
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.util.system.SystemModule
@Component(dependencies = [MatrixComponent::class],
@Component(
dependencies = [MatrixComponent::class],
modules = [
SessionModule::class,
RoomModule::class,

View file

@ -289,12 +289,14 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
val uploadThumbnailResult = dealWithThumbnail(params)
handleSuccess(params,
handleSuccess(
params,
contentUploadResponse.contentUri,
uploadedFileEncryptedFileInfo,
uploadThumbnailResult?.uploadedThumbnailUrl,
uploadThumbnailResult?.uploadedThumbnailEncryptedFileInfo,
newAttachmentAttributes)
newAttachmentAttributes
)
} catch (t: Throwable) {
Timber.e(t, "## ERROR ${t.localizedMessage}")
handleFailure(params, t)

View file

@ -21,9 +21,11 @@ import io.realm.annotations.RealmModule
/**
* Realm module for content scanner classes
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
ContentScannerInfoEntity::class,
ContentScanResultEntity::class
])
]
)
internal class ContentScannerRealmModule

View file

@ -94,10 +94,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
}.getOrNull()
val wellknownResult = runCatching {
getWellknownTask.execute(GetWellknownTask.Params(
domain = userId.getDomain(),
homeServerConnectionConfig = homeServerConnectionConfig
))
getWellknownTask.execute(
GetWellknownTask.Params(
domain = userId.getDomain(),
homeServerConnectionConfig = homeServerConnectionConfig
)
)
}.getOrNull()
insertInDb(capabilities, mediaConfig, versions, wellknownResult)

View file

@ -218,9 +218,11 @@ internal class DefaultIdentityService @Inject constructor(
listeners.toList().forEach { tryOrNull { it.onIdentityServerChange() } }
}
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.IdentityParams(
identityContent = IdentityServerContent(baseUrl = url)
))
updateUserAccountDataTask.execute(
UpdateUserAccountDataTask.IdentityParams(
identityContent = IdentityServerContent(baseUrl = url)
)
)
}
override fun getUserConsent(): Boolean {
@ -297,11 +299,13 @@ internal class DefaultIdentityService @Inject constructor(
}
override suspend fun sign3pidInvitation(identiyServer: String, token: String, secret: String): SignInvitationResult {
return sign3pidInvitationTask.execute(Sign3pidInvitationTask.Params(
url = identiyServer,
token = token,
privateKey = secret
))
return sign3pidInvitationTask.execute(
Sign3pidInvitationTask.Params(
url = identiyServer,
token = token,
privateKey = secret
)
)
}
override fun addListener(listener: IdentityServiceListener) {

View file

@ -83,11 +83,13 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
return try {
LookUpData(hashedAddresses,
executeRequest(null) {
identityAPI.lookup(IdentityLookUpParams(
hashedAddresses,
IdentityHashDetailResponse.ALGORITHM_SHA256,
hashDetailResponse.pepper
))
identityAPI.lookup(
IdentityLookUpParams(
hashedAddresses,
IdentityHashDetailResponse.ALGORITHM_SHA256,
hashDetailResponse.pepper
)
)
})
} catch (failure: Throwable) {
// Catch invalid hash pepper and retry
@ -117,8 +119,10 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
return withOlmUtility { olmUtility ->
threePids.map { threePid ->
base64ToBase64Url(
olmUtility.sha256(threePid.value.lowercase(Locale.ROOT) +
" " + threePid.toMedium() + " " + pepper)
olmUtility.sha256(
threePid.value.lowercase(Locale.ROOT) +
" " + threePid.toMedium() + " " + pepper
)
)
}
}

View file

@ -57,18 +57,22 @@ internal class DefaultIdentityRequestTokenForBindingTask @Inject constructor(
val tokenResponse = executeRequest(null) {
when (params.threePid) {
is ThreePid.Email -> identityAPI.requestTokenToBindEmail(IdentityRequestTokenForEmailBody(
clientSecret = clientSecret,
sendAttempt = sendAttempt,
email = params.threePid.email
))
is ThreePid.Email -> identityAPI.requestTokenToBindEmail(
IdentityRequestTokenForEmailBody(
clientSecret = clientSecret,
sendAttempt = sendAttempt,
email = params.threePid.email
)
)
is ThreePid.Msisdn -> {
identityAPI.requestTokenToBindMsisdn(IdentityRequestTokenForMsisdnBody(
clientSecret = clientSecret,
sendAttempt = sendAttempt,
phoneNumber = params.threePid.msisdn,
countryCode = params.threePid.getCountryCode()
))
identityAPI.requestTokenToBindMsisdn(
IdentityRequestTokenForMsisdnBody(
clientSecret = clientSecret,
sendAttempt = sendAttempt,
phoneNumber = params.threePid.msisdn,
countryCode = params.threePid.getCountryCode()
)
)
}
}
}

View file

@ -50,7 +50,8 @@ internal class DefaultIdentitySubmitTokenForBindingTask @Inject constructor(
clientSecret = identityPendingBinding.clientSecret,
sid = identityPendingBinding.sid,
token = params.token
))
)
)
}
if (!tokenResponse.isSuccess()) {

View file

@ -21,9 +21,11 @@ import io.realm.annotations.RealmModule
/**
* Realm module for identity server classes
*/
@RealmModule(library = true,
@RealmModule(
library = true,
classes = [
IdentityDataEntity::class,
IdentityPendingBindingEntity::class
])
]
)
internal class IdentityRealmModule

View file

@ -50,7 +50,8 @@ internal class DefaultBindThreePidsTask @Inject constructor(private val profileA
identityServerUrlWithoutProtocol = identityServerUrlWithoutProtocol,
identityServerAccessToken = identityServerAccessToken,
sid = identityPendingBinding.sid
))
)
)
}
// Binding is over, cleanup the store

View file

@ -135,21 +135,25 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
override suspend fun finalizeAddingThreePid(threePid: ThreePid,
userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
finalizeAddingThreePidTask
.execute(FinalizeAddingThreePidTask.Params(
threePid = threePid,
userInteractiveAuthInterceptor = userInteractiveAuthInterceptor,
userWantsToCancel = false
))
.execute(
FinalizeAddingThreePidTask.Params(
threePid = threePid,
userInteractiveAuthInterceptor = userInteractiveAuthInterceptor,
userWantsToCancel = false
)
)
refreshThreePids()
}
override suspend fun cancelAddingThreePid(threePid: ThreePid) {
finalizeAddingThreePidTask
.execute(FinalizeAddingThreePidTask.Params(
threePid = threePid,
userInteractiveAuthInterceptor = null,
userWantsToCancel = true
))
.execute(
FinalizeAddingThreePidTask.Params(
threePid = threePid,
userInteractiveAuthInterceptor = null,
userWantsToCancel = true
)
)
refreshThreePids()
}

View file

@ -45,7 +45,8 @@ internal class DefaultUnbindThreePidsTask @Inject constructor(private val profil
identityServerUrlWithoutProtocol,
params.threePid.toMedium(),
params.threePid.value
))
)
)
}.isSuccess()
}
}

View file

@ -85,17 +85,19 @@ internal class DefaultPushersService @Inject constructor(
deviceDisplayName: String,
append: Boolean) {
addPusherTask.execute(
AddPusherTask.Params(JsonPusher(
pushKey = email,
kind = Pusher.KIND_EMAIL,
appId = Pusher.APP_ID_EMAIL,
profileTag = "",
lang = lang,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
data = JsonPusherData(brand = emailBranding),
append = append
))
AddPusherTask.Params(
JsonPusher(
pushKey = email,
kind = Pusher.KIND_EMAIL,
appId = Pusher.APP_ID_EMAIL,
profileTag = "",
lang = lang,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
data = JsonPusherData(brand = emailBranding),
append = append
)
)
)
}

View file

@ -67,8 +67,10 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
}.filter {
it.senderId != userId
}
Timber.v("[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
" to check for push rules with ${params.rules.size} rules")
Timber.v(
"[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
" to check for push rules with ${params.rules.size} rules"
)
val matchedEvents = allEvents.mapNotNull { event ->
pushRuleFinder.fulfilledBingRule(event, params.rules)?.let {
Timber.v("[PushRules] Rule $it match for event ${event.eventId}")

View file

@ -116,7 +116,8 @@ internal class CreateRoomBodyBuilder @Inject constructor(
fileUploader.uploadFromUri(
uri = avatarUri,
filename = UUID.randomUUID().toString(),
mimeType = MimeTypes.Jpeg)
mimeType = MimeTypes.Jpeg
)
}
}?.let { response ->
Event(

View file

@ -83,7 +83,8 @@ internal class RoomMemberEventHandler @Inject constructor(
roomMember,
// When an update is happening, insertOrUpdate replace existing values with null if they are not provided,
// but we want to preserve presence record value and not replace it with null
getExistingPresenceState(realm, roomId, userId))
getExistingPresenceState(realm, roomId, userId)
)
realm.insertOrUpdate(roomMemberEntity)
}

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