mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
467f48f1a6
@ -2,6 +2,7 @@ Changes in RiotX 0.19.0 (2020-XX-XX)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Change password (#528)
|
||||
- Cross-Signing | Support SSSS secret sharing (#944)
|
||||
- Cross-Signing | Verify new session from existing session (#1134)
|
||||
- Cross-Signing | Bootstraping cross signing with 4S from mobile (#985)
|
||||
@ -43,6 +44,7 @@ Build 🧱:
|
||||
- Compile with Android SDK 29 (Android Q)
|
||||
|
||||
Other changes:
|
||||
- Add a setting to prevent screenshots of the application, disabled by default (#1027)
|
||||
- Increase File Logger capacities ( + use dev log preferences)
|
||||
|
||||
Changes in RiotX 0.18.1 (2020-03-17)
|
||||
|
@ -31,3 +31,9 @@ fun Throwable.shouldBeRetried(): Boolean {
|
||||
return this is Failure.NetworkConnection
|
||||
|| (this is Failure.ServerError && error.code == MatrixError.M_LIMIT_EXCEEDED)
|
||||
}
|
||||
|
||||
fun Throwable.isInvalidPassword(): Boolean {
|
||||
return this is Failure.ServerError
|
||||
&& error.code == MatrixError.M_FORBIDDEN
|
||||
&& error.message == "Invalid password"
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.failure.GlobalError
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
import im.vector.matrix.android.api.session.account.AccountService
|
||||
import im.vector.matrix.android.api.session.accountdata.AccountDataService
|
||||
import im.vector.matrix.android.api.session.cache.CacheService
|
||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||
@ -59,7 +60,8 @@ interface Session :
|
||||
InitialSyncProgressService,
|
||||
HomeServerCapabilitiesService,
|
||||
SecureStorageService,
|
||||
AccountDataService {
|
||||
AccountDataService,
|
||||
AccountService {
|
||||
|
||||
/**
|
||||
* The params associated to the session
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.account
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
/**
|
||||
* This interface defines methods to manage the account. It's implemented at the session level.
|
||||
*/
|
||||
interface AccountService {
|
||||
|
||||
/**
|
||||
* Ask the homeserver to change the password.
|
||||
* @param password Current password.
|
||||
* @param newPassword New password
|
||||
*/
|
||||
fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.account.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
||||
|
||||
/**
|
||||
* Class to pass request parameters to update the password.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class ChangePasswordParams(
|
||||
@Json(name = "auth")
|
||||
val auth: UserPasswordAuth? = null,
|
||||
|
||||
@Json(name = "new_password")
|
||||
val newPassword: String? = null
|
||||
) {
|
||||
companion object {
|
||||
fun create(userId: String, oldPassword: String, newPassword: String): ChangePasswordParams {
|
||||
return ChangePasswordParams(
|
||||
auth = UserPasswordAuth(user = userId, password = oldPassword),
|
||||
newPassword = newPassword
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,10 @@
|
||||
package im.vector.matrix.android.api.session.homeserver
|
||||
|
||||
data class HomeServerCapabilities(
|
||||
/**
|
||||
* True if it is possible to change the password of the account.
|
||||
*/
|
||||
val canChangePassword: Boolean = true,
|
||||
/**
|
||||
* Max size of file which can be uploaded to the homeserver in bytes. [MAX_UPLOAD_FILE_SIZE_UNKNOWN] if unknown or not retrieved yet
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||
|
||||
/**
|
||||
* This class provides the authentication data to delete a device
|
||||
* This class provides the authentication data by using user and password
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserPasswordAuth(
|
||||
|
@ -26,12 +26,14 @@ internal object HomeServerCapabilitiesMapper {
|
||||
|
||||
fun map(entity: HomeServerCapabilitiesEntity): HomeServerCapabilities {
|
||||
return HomeServerCapabilities(
|
||||
canChangePassword = entity.canChangePassword,
|
||||
maxUploadFileSize = entity.maxUploadFileSize
|
||||
)
|
||||
}
|
||||
|
||||
fun map(domain: HomeServerCapabilities): HomeServerCapabilitiesEntity {
|
||||
return HomeServerCapabilitiesEntity(
|
||||
canChangePassword = domain.canChangePassword,
|
||||
maxUploadFileSize = domain.maxUploadFileSize
|
||||
)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities
|
||||
import io.realm.RealmObject
|
||||
|
||||
internal open class HomeServerCapabilitiesEntity(
|
||||
var canChangePassword: Boolean = true,
|
||||
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
|
||||
var lastUpdatedTimestamp: Long = 0L
|
||||
) : RealmObject() {
|
||||
|
@ -25,6 +25,7 @@ import im.vector.matrix.android.api.failure.GlobalError
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
import im.vector.matrix.android.api.session.InitialSyncProgressService
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.account.AccountService
|
||||
import im.vector.matrix.android.api.session.accountdata.AccountDataService
|
||||
import im.vector.matrix.android.api.session.cache.CacheService
|
||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||
@ -94,6 +95,7 @@ internal class DefaultSession @Inject constructor(
|
||||
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
|
||||
private val accountDataService: Lazy<AccountDataService>,
|
||||
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
|
||||
private val accountService: Lazy<AccountService>,
|
||||
private val timelineEventDecryptor: TimelineEventDecryptor,
|
||||
private val shieldTrustUpdater: ShieldTrustUpdater)
|
||||
: Session,
|
||||
@ -110,7 +112,8 @@ internal class DefaultSession @Inject constructor(
|
||||
SecureStorageService by secureStorageService.get(),
|
||||
HomeServerCapabilitiesService by homeServerCapabilitiesService.get(),
|
||||
ProfileService by profileService.get(),
|
||||
AccountDataService by accountDataService.get() {
|
||||
AccountDataService by accountDataService.get(),
|
||||
AccountService by accountService.get() {
|
||||
|
||||
override val sharedSecretStorageService: SharedSecretStorageService
|
||||
get() = _sharedSecretStorageService.get()
|
||||
|
@ -28,6 +28,7 @@ import im.vector.matrix.android.internal.crypto.verification.SendVerificationMes
|
||||
import im.vector.matrix.android.internal.di.MatrixComponent
|
||||
import im.vector.matrix.android.internal.di.SessionAssistedInjectModule
|
||||
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||
import im.vector.matrix.android.internal.session.account.AccountModule
|
||||
import im.vector.matrix.android.internal.session.cache.CacheModule
|
||||
import im.vector.matrix.android.internal.session.content.ContentModule
|
||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||
@ -71,7 +72,8 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
PushersModule::class,
|
||||
AccountDataModule::class,
|
||||
ProfileModule::class,
|
||||
SessionAssistedInjectModule::class
|
||||
SessionAssistedInjectModule::class,
|
||||
AccountModule::class
|
||||
]
|
||||
)
|
||||
@SessionScope
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.account
|
||||
|
||||
import im.vector.matrix.android.api.session.account.model.ChangePasswordParams
|
||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.POST
|
||||
|
||||
internal interface AccountAPI {
|
||||
|
||||
/**
|
||||
* Ask the homeserver to change the password with the provided new password.
|
||||
* @param params parameters to change password.
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/password")
|
||||
fun changePassword(@Body params: ChangePasswordParams): Call<Unit>
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.account
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import im.vector.matrix.android.api.session.account.AccountService
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import retrofit2.Retrofit
|
||||
|
||||
@Module
|
||||
internal abstract class AccountModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@SessionScope
|
||||
fun providesAccountAPI(retrofit: Retrofit): AccountAPI {
|
||||
return retrofit.create(AccountAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindChangePasswordTask(task: DefaultChangePasswordTask): ChangePasswordTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindAccountService(service: DefaultAccountService): AccountService
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.account
|
||||
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.account.model.ChangePasswordParams
|
||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> {
|
||||
data class Params(
|
||||
val password: String,
|
||||
val newPassword: String
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultChangePasswordTask @Inject constructor(
|
||||
private val accountAPI: AccountAPI,
|
||||
private val eventBus: EventBus,
|
||||
@UserId private val userId: String
|
||||
) : ChangePasswordTask {
|
||||
|
||||
override suspend fun execute(params: ChangePasswordTask.Params) {
|
||||
val changePasswordParams = ChangePasswordParams.create(userId, params.password, params.newPassword)
|
||||
try {
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = accountAPI.changePassword(changePasswordParams)
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
if (throwable is Failure.OtherServerError
|
||||
&& throwable.httpCode == 401
|
||||
/* Avoid infinite loop */
|
||||
&& changePasswordParams.auth?.session == null) {
|
||||
try {
|
||||
MoshiProvider.providesMoshi()
|
||||
.adapter(RegistrationFlowResponse::class.java)
|
||||
.fromJson(throwable.errorBody)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}?.let {
|
||||
// Retry with authentication
|
||||
try {
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = accountAPI.changePassword(
|
||||
changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = it.session))
|
||||
)
|
||||
}
|
||||
return
|
||||
} catch (failure: Throwable) {
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
}
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.account
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.account.AccountService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask,
|
||||
private val taskExecutor: TaskExecutor) : AccountService {
|
||||
|
||||
override fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return changePasswordTask
|
||||
.configureWith(ChangePasswordTask.Params(password, newPassword)) {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
@ -22,6 +22,12 @@ import retrofit2.http.GET
|
||||
|
||||
internal interface CapabilitiesAPI {
|
||||
|
||||
/**
|
||||
* Request the homeserver capabilities
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "capabilities")
|
||||
fun getCapabilities(): Call<GetCapabilitiesResult>
|
||||
|
||||
/**
|
||||
* Request the upload capabilities
|
||||
*/
|
||||
|
@ -51,15 +51,23 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
apiCall = capabilitiesAPI.getUploadCapabilities()
|
||||
}
|
||||
|
||||
val capabilities = runCatching {
|
||||
executeRequest<GetCapabilitiesResult>(eventBus) {
|
||||
apiCall = capabilitiesAPI.getCapabilities()
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
// TODO Add other call here (get version, etc.)
|
||||
|
||||
insertInDb(uploadCapabilities)
|
||||
insertInDb(capabilities, uploadCapabilities)
|
||||
}
|
||||
|
||||
private suspend fun insertInDb(getUploadCapabilitiesResult: GetUploadCapabilitiesResult) {
|
||||
private suspend fun insertInDb(getCapabilitiesResult: GetCapabilitiesResult?, getUploadCapabilitiesResult: GetUploadCapabilitiesResult) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
|
||||
|
||||
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
|
||||
|
||||
homeServerCapabilitiesEntity.maxUploadFileSize = getUploadCapabilitiesResult.maxUploadSize
|
||||
?: HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN
|
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.homeserver
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.extensions.orTrue
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GetCapabilitiesResult(
|
||||
/**
|
||||
* Required. The custom capabilities the server supports, using the Java package naming convention.
|
||||
*/
|
||||
@Json(name = "capabilities")
|
||||
val capabilities: Capabilities? = null
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Capabilities(
|
||||
/**
|
||||
* Capability to indicate if the user can change their password.
|
||||
*/
|
||||
@Json(name = "m.change_password")
|
||||
val changePassword: ChangePassword? = null
|
||||
|
||||
// No need for m.room_versions for the moment
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class ChangePassword(
|
||||
/**
|
||||
* Required. True if the user can change their password, false otherwise.
|
||||
*/
|
||||
@Json(name = "enabled")
|
||||
val enabled: Boolean?
|
||||
)
|
||||
|
||||
// The spec says: If not present, the client should assume that password changes are possible via the API
|
||||
internal fun GetCapabilitiesResult?.canChangePassword(): Boolean {
|
||||
return this?.capabilities?.changePassword?.enabled.orTrue()
|
||||
}
|
@ -20,7 +20,7 @@ import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GetUploadCapabilitiesResult(
|
||||
internal data class GetUploadCapabilitiesResult(
|
||||
/**
|
||||
* The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content.
|
||||
* If not listed or null, the size limit should be treated as unknown.
|
||||
|
@ -18,6 +18,7 @@ package im.vector.riotx.core.error
|
||||
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.failure.MatrixError
|
||||
import im.vector.matrix.android.api.failure.isInvalidPassword
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import java.net.HttpURLConnection
|
||||
@ -54,8 +55,7 @@ class DefaultErrorFormatter @Inject constructor(
|
||||
// Special case for terms and conditions
|
||||
stringProvider.getString(R.string.error_terms_not_accepted)
|
||||
}
|
||||
throwable.error.code == MatrixError.M_FORBIDDEN
|
||||
&& throwable.error.message == "Invalid password" -> {
|
||||
throwable.isInvalidPassword() -> {
|
||||
stringProvider.getString(R.string.auth_invalid_login_param)
|
||||
}
|
||||
throwable.error.code == MatrixError.M_USER_IN_USE -> {
|
||||
|
@ -23,6 +23,7 @@ import android.os.Parcelable
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.MainThread
|
||||
@ -183,6 +184,11 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||
handleGlobalError(it)
|
||||
}
|
||||
|
||||
// Set flag FLAG_SECURE
|
||||
if (vectorPreferences.useFlagSecure()) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
|
||||
doBeforeSetContentView()
|
||||
|
||||
if (getLayoutRes() != -1) {
|
||||
|
@ -28,6 +28,7 @@ import com.airbnb.mvrx.Success
|
||||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.failure.MatrixError
|
||||
import im.vector.matrix.android.api.failure.isInvalidPassword
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import im.vector.riotx.core.extensions.showPassword
|
||||
@ -209,10 +210,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||
} else {
|
||||
// Trick to display the error without text.
|
||||
loginFieldTil.error = " "
|
||||
if (error is Failure.ServerError
|
||||
&& error.error.code == MatrixError.M_FORBIDDEN
|
||||
&& error.error.message == "Invalid password"
|
||||
&& spaceInPassword()) {
|
||||
if (error.isInvalidPassword() && spaceInPassword()) {
|
||||
passwordFieldTil.error = getString(R.string.auth_invalid_login_param_space_in_password)
|
||||
} else {
|
||||
passwordFieldTil.error = errorFormatter.toHumanReadable(error)
|
||||
|
@ -150,6 +150,9 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||
const val SETTINGS_USE_RAGE_SHAKE_KEY = "SETTINGS_USE_RAGE_SHAKE_KEY"
|
||||
const val SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY = "SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY"
|
||||
|
||||
// Security
|
||||
const val SETTINGS_SECURITY_USE_FLAG_SECURE = "SETTINGS_SECURITY_USE_FLAG_SECURE"
|
||||
|
||||
// other
|
||||
const val SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY"
|
||||
private const val SETTINGS_MEDIA_SAVING_PERIOD_SELECTED_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_SELECTED_KEY"
|
||||
@ -199,7 +202,8 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||
SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY,
|
||||
SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY,
|
||||
|
||||
SETTINGS_USE_RAGE_SHAKE_KEY
|
||||
SETTINGS_USE_RAGE_SHAKE_KEY,
|
||||
SETTINGS_SECURITY_USE_FLAG_SECURE
|
||||
)
|
||||
}
|
||||
|
||||
@ -746,4 +750,11 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||
fun displayAllEvents(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_DISPLAY_ALL_EVENTS_KEY, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* The user does not allow screenshots of the application
|
||||
*/
|
||||
fun useFlagSecure(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_FLAG_SECURE, false)
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.cache.DiskCache
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.isInvalidPassword
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import im.vector.riotx.core.extensions.showPassword
|
||||
@ -108,11 +110,15 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
}
|
||||
|
||||
// Password
|
||||
// Hide the preference if password can not be updated
|
||||
if (session.getHomeServerCapabilities().canChangePassword) {
|
||||
mPasswordPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
notImplemented()
|
||||
// onPasswordUpdateClick()
|
||||
onPasswordUpdateClick()
|
||||
false
|
||||
}
|
||||
} else {
|
||||
mPasswordPreference.isVisible = false
|
||||
}
|
||||
|
||||
// Add Email
|
||||
findPreference<EditTextPreference>(ADD_EMAIL_PREFERENCE_KEY)!!.let {
|
||||
@ -684,8 +690,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
|
||||
var passwordShown = false
|
||||
|
||||
showPassword.setOnClickListener(object : View.OnClickListener {
|
||||
override fun onClick(v: View?) {
|
||||
showPassword.setOnClickListener {
|
||||
passwordShown = !passwordShown
|
||||
|
||||
oldPasswordText.showPassword(passwordShown)
|
||||
@ -694,11 +699,11 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
|
||||
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
|
||||
}
|
||||
})
|
||||
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.settings_change_password_submit, null)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.settings_change_password, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener {
|
||||
view.hideKeyboard()
|
||||
@ -707,12 +712,13 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
|
||||
dialog.setOnShowListener {
|
||||
val updateButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
val cancelButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||
updateButton.isEnabled = false
|
||||
|
||||
fun updateUi() {
|
||||
val oldPwd = oldPasswordText.text.toString().trim()
|
||||
val newPwd = newPasswordText.text.toString().trim()
|
||||
val newConfirmPwd = confirmNewPasswordText.text.toString().trim()
|
||||
val oldPwd = oldPasswordText.text.toString()
|
||||
val newPwd = newPasswordText.text.toString()
|
||||
val newConfirmPwd = confirmNewPasswordText.text.toString()
|
||||
|
||||
updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && newPwd == newConfirmPwd
|
||||
|
||||
@ -750,6 +756,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
confirmNewPasswordText.isEnabled = false
|
||||
changePasswordLoader.isVisible = true
|
||||
updateButton.isEnabled = false
|
||||
cancelButton.isEnabled = false
|
||||
} else {
|
||||
showPassword.isEnabled = true
|
||||
oldPasswordText.isEnabled = true
|
||||
@ -757,6 +764,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
confirmNewPasswordText.isEnabled = true
|
||||
changePasswordLoader.isVisible = false
|
||||
updateButton.isEnabled = true
|
||||
cancelButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -768,47 +776,32 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||
|
||||
view.hideKeyboard()
|
||||
|
||||
val oldPwd = oldPasswordText.text.toString().trim()
|
||||
val newPwd = newPasswordText.text.toString().trim()
|
||||
val oldPwd = oldPasswordText.text.toString()
|
||||
val newPwd = newPasswordText.text.toString()
|
||||
|
||||
notImplemented()
|
||||
/* TODO
|
||||
showPasswordLoadingView(true)
|
||||
|
||||
session.updatePassword(oldPwd, newPwd, object : MatrixCallback<Unit> {
|
||||
private fun onDone(@StringRes textResId: Int) {
|
||||
session.changePassword(oldPwd, newPwd, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
showPasswordLoadingView(false)
|
||||
|
||||
if (textResId == R.string.settings_fail_to_update_password_invalid_current_password) {
|
||||
oldPasswordTil.error = getString(textResId)
|
||||
} else {
|
||||
dialog.dismiss()
|
||||
activity.toast(textResId, Toast.LENGTH_LONG)
|
||||
}
|
||||
activity.toast(R.string.settings_password_updated)
|
||||
}
|
||||
|
||||
override fun onSuccess(info: Void?) {
|
||||
onDone(R.string.settings_password_updated)
|
||||
override fun onFailure(failure: Throwable) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (e.error == "Invalid password") {
|
||||
onDone(R.string.settings_fail_to_update_password_invalid_current_password)
|
||||
showPasswordLoadingView(false)
|
||||
if (failure.isInvalidPassword()) {
|
||||
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
|
||||
} else {
|
||||
dialog.dismiss()
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onDone(R.string.settings_fail_to_update_password)
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
}
|
||||
dialog.show()
|
||||
|
@ -39,7 +39,8 @@
|
||||
android:id="@+id/change_password_old_pwd_til"
|
||||
style="@style/VectorTextInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/change_password_old_pwd_text"
|
||||
@ -53,7 +54,9 @@
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/VectorTextInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/change_password_new_pwd_text"
|
||||
@ -69,6 +72,7 @@
|
||||
style="@style/VectorTextInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
|
@ -14,6 +14,12 @@
|
||||
|
||||
<!-- END Strings added by Benoit -->
|
||||
|
||||
<!-- BEGIN Strings added by Benoit2 -->
|
||||
<string name="settings_security_prevent_screenshots_title">Prevent screenshots of the application</string>
|
||||
<string name="settings_security_prevent_screenshots_summary">Enabling this setting adds the FLAG_SECURE to all Activities. Restart the application for the change to take effect.</string>
|
||||
|
||||
<!-- END Strings added by Benoit2 -->
|
||||
|
||||
|
||||
<!-- BEGIN Strings added by Ganfra -->
|
||||
|
||||
@ -29,4 +35,7 @@
|
||||
|
||||
<!-- END Strings added by Others -->
|
||||
|
||||
<!-- BEGIN Strings added by Benoit -->
|
||||
<string name="change_password_summary">Set a new account password…</string>
|
||||
<!---->
|
||||
</resources>
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
android:key="SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY"
|
||||
android:summary="@string/password_hint"
|
||||
android:summary="@string/change_password_summary"
|
||||
android:title="@string/settings_password" />
|
||||
|
||||
<!-- Email will be added here -->
|
||||
|
@ -6,36 +6,35 @@
|
||||
<!-- ************ Cryptography section ************ -->
|
||||
<im.vector.riotx.core.preference.VectorPreferenceCategory
|
||||
android:key="SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY"
|
||||
tools:isPreferenceVisible="true"
|
||||
android:title="@string/settings_cryptography"
|
||||
app:isPreferenceVisible="false"
|
||||
android:title="@string/settings_cryptography">
|
||||
tools:isPreferenceVisible="true">
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
android:key="SETTINGS_ENCRYPTION_CROSS_SIGNING_PREFERENCE_KEY"
|
||||
tools:icon="@drawable/ic_shield_trusted"
|
||||
android:persistent="false"
|
||||
android:title="@string/encryption_information_cross_signing_state"
|
||||
tools:summary="@string/encryption_information_dg_xsigning_complete"
|
||||
app:fragment="im.vector.riotx.features.settings.crosssigning.CrossSigningSettingsFragment"
|
||||
/>
|
||||
tools:icon="@drawable/ic_shield_trusted"
|
||||
tools:summary="@string/encryption_information_dg_xsigning_complete" />
|
||||
|
||||
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_NAME_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_name" />-->
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_NAME_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_name" />-->
|
||||
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_ID_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_id" />-->
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_ID_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_id" />-->
|
||||
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_KEY_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_key" />-->
|
||||
<!-- <im.vector.riotx.core.preference.VectorPreference-->
|
||||
<!-- android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_KEY_PREFERENCE_KEY"-->
|
||||
<!-- android:title="@string/encryption_information_device_key" />-->
|
||||
|
||||
<im.vector.riotx.core.preference.VectorSwitchPreference
|
||||
android:enabled="false"
|
||||
android:key="SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY"
|
||||
android:summary="@string/encryption_never_send_to_unverified_devices_summary"
|
||||
android:title="@string/encryption_never_send_to_unverified_devices_title"
|
||||
android:enabled="false" />
|
||||
android:title="@string/encryption_never_send_to_unverified_devices_title" />
|
||||
|
||||
</im.vector.riotx.core.preference.VectorPreferenceCategory>
|
||||
|
||||
@ -85,4 +84,15 @@
|
||||
|
||||
</im.vector.riotx.core.preference.VectorPreferenceCategory>
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreferenceCategory
|
||||
android:title="@string/settings_other">
|
||||
|
||||
<im.vector.riotx.core.preference.VectorSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="SETTINGS_SECURITY_USE_FLAG_SECURE"
|
||||
android:summary="@string/settings_security_prevent_screenshots_summary"
|
||||
android:title="@string/settings_security_prevent_screenshots_title" />
|
||||
|
||||
</im.vector.riotx.core.preference.VectorPreferenceCategory>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user