Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Benoit Marty 2020-04-16 11:33:22 +02:00
commit 467f48f1a6
28 changed files with 490 additions and 100 deletions

View File

@ -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)

View File

@ -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"
}

View File

@ -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

View File

@ -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
}

View File

@ -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
)
}
}
}

View File

@ -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
*/

View File

@ -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(

View File

@ -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
)
}

View File

@ -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() {

View File

@ -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()

View File

@ -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

View File

@ -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>
}

View File

@ -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
}

View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -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
*/

View File

@ -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

View File

@ -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()
}

View File

@ -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.

View File

@ -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 -> {

View File

@ -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) {

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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()

View File

@ -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

View File

@ -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>

View File

@ -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 -->

View File

@ -6,17 +6,16 @@
<!-- ************ 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-->
@ -32,10 +31,10 @@
<!-- 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>