diff --git a/CHANGES.rst b/CHANGES.rst index b7ca2855c0..f095290ffb 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,6 +15,7 @@ Features: - Privacy: Remove the ability to set an IS at login/registration (#3264) - Privacy: Allow password reset when no IS (#3261) - Privacy: Allow email registration when no IS (#3260) + - Privacy: Separate Add and Bind for 3PID #3300 Improvements: - diff --git a/vector/src/main/java/im/vector/LoginHandler.java b/vector/src/main/java/im/vector/LoginHandler.java index 3ec8015d57..4bb127d8a7 100644 --- a/vector/src/main/java/im/vector/LoginHandler.java +++ b/vector/src/main/java/im/vector/LoginHandler.java @@ -214,10 +214,9 @@ public void submitEmailTokenValidation(final Context aCtx, final String aClientSecret, final String aSid, final ApiCallback aRespCallback) { - final ThreePid pid = new ThreePid(null, ThreePid.MEDIUM_EMAIL); ThirdPidRestClient restClient = new ThirdPidRestClient(aHomeServerConfig); - pid.submitValidationToken(restClient, aToken, aClientSecret, aSid, new UnrecognizedCertApiCallback(aHomeServerConfig, aRespCallback) { + restClient.submitValidationToken(ThreePid.MEDIUM_EMAIL, aToken, aClientSecret, aSid, new UnrecognizedCertApiCallback(aHomeServerConfig, aRespCallback) { @Override public void onSuccess(Boolean info) { aRespCallback.onSuccess(info); diff --git a/vector/src/main/java/im/vector/RegistrationManager.java b/vector/src/main/java/im/vector/RegistrationManager.java index f08f0254aa..6ad0ba553e 100644 --- a/vector/src/main/java/im/vector/RegistrationManager.java +++ b/vector/src/main/java/im/vector/RegistrationManager.java @@ -31,10 +31,13 @@ import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.core.callback.ApiCallback; import org.matrix.androidsdk.core.model.MatrixError; +import org.matrix.androidsdk.features.identityserver.IdentityServerManager; import org.matrix.androidsdk.login.RegistrationToolsKt; import org.matrix.androidsdk.rest.client.LoginRestClient; import org.matrix.androidsdk.rest.client.ProfileRestClient; import org.matrix.androidsdk.rest.client.ThirdPidRestClient; +import org.matrix.androidsdk.rest.model.RequestEmailValidationResponse; +import org.matrix.androidsdk.rest.model.RequestPhoneNumberValidationResponse; import org.matrix.androidsdk.rest.model.login.AuthParams; import org.matrix.androidsdk.rest.model.login.AuthParamsCaptcha; import org.matrix.androidsdk.rest.model.login.AuthParamsLoginPassword; @@ -261,18 +264,18 @@ public void attemptRegistration(final Context context, final RegistrationListene final String registrationType; if (mRegistrationResponse != null && !TextUtils.isEmpty(mRegistrationResponse.session)) { AuthParams authParams = null; - if (mPhoneNumber != null && !isCompleted(LoginRestClient.LOGIN_FLOW_TYPE_MSISDN) && !TextUtils.isEmpty(mPhoneNumber.sid)) { + if (mPhoneNumber != null && !isCompleted(LoginRestClient.LOGIN_FLOW_TYPE_MSISDN) && !TextUtils.isEmpty(mPhoneNumber.getSid())) { Uri identityServerUri = mHsConfig.getIdentityServerUri(); if (identityServerUri == null) { listener.onIdentityServerMissing(); return; } else { registrationType = LoginRestClient.LOGIN_FLOW_TYPE_MSISDN; - authParams = getThreePidAuthParams(mPhoneNumber.clientSecret, identityServerUri.getHost(), - mPhoneNumber.sid, LoginRestClient.LOGIN_FLOW_TYPE_MSISDN); + authParams = getThreePidAuthParams(mPhoneNumber.getClientSecret(), identityServerUri.getHost(), + mPhoneNumber.getSid(), LoginRestClient.LOGIN_FLOW_TYPE_MSISDN); } } else if (mEmail != null && !isCompleted(LoginRestClient.LOGIN_FLOW_TYPE_EMAIL_IDENTITY)) { - if (TextUtils.isEmpty(mEmail.sid)) { + if (TextUtils.isEmpty(mEmail.getSid())) { // Email token needs to be requested before doing validation Log.d(LOG_TAG, "attemptRegistration: request email validation"); requestValidationToken(context, mEmail, new ThreePidRequestListener() { @@ -283,7 +286,7 @@ public void onIdentityServerMissing() { @Override public void onThreePidRequested(ThreePid pid) { - if (!TextUtils.isEmpty(pid.sid)) { + if (!TextUtils.isEmpty(pid.getSid())) { // The session id for the email validation has just been received. // We trigger here a new registration request without delay to attach the current username // and the pwd to the registration session. @@ -307,8 +310,8 @@ public void onThreePidRequestFailed(String errorMessage) { return; } else { registrationType = LoginRestClient.LOGIN_FLOW_TYPE_EMAIL_IDENTITY; - authParams = getThreePidAuthParams(mEmail.clientSecret, identityServerUri.getHost(), - mEmail.sid, LoginRestClient.LOGIN_FLOW_TYPE_EMAIL_IDENTITY); + authParams = getThreePidAuthParams(mEmail.getClientSecret(), identityServerUri.getHost(), + mEmail.getSid(), LoginRestClient.LOGIN_FLOW_TYPE_EMAIL_IDENTITY); } } } else if (!TextUtils.isEmpty(mCaptchaResponse) && !isCompleted(LoginRestClient.LOGIN_FLOW_TYPE_RECAPTCHA)) { @@ -590,27 +593,31 @@ public boolean canSkipThreePid() { */ public void submitValidationToken(final String token, final ThreePid pid, final ThreePidValidationListener listener) { if (getThirdPidRestClient() != null) { - pid.submitValidationToken(getThirdPidRestClient(), token, pid.clientSecret, pid.sid, new ApiCallback() { - @Override - public void onSuccess(Boolean isSuccess) { - listener.onThreePidValidated(isSuccess); - } + getThirdPidRestClient().submitValidationToken( + pid.getMedium(), + token, + pid.getClientSecret(), + pid.getSid(), new ApiCallback() { + @Override + public void onSuccess(Boolean isSuccess) { + listener.onThreePidValidated(isSuccess); + } - @Override - public void onNetworkError(Exception e) { - listener.onThreePidValidated(false); - } + @Override + public void onNetworkError(Exception e) { + listener.onThreePidValidated(false); + } - @Override - public void onMatrixError(MatrixError e) { - listener.onThreePidValidated(false); - } + @Override + public void onMatrixError(MatrixError e) { + listener.onThreePidValidated(false); + } - @Override - public void onUnexpectedError(Exception e) { - listener.onThreePidValidated(false); - } - }); + @Override + public void onUnexpectedError(Exception e) { + listener.onThreePidValidated(false); + } + }); } } @@ -642,7 +649,7 @@ public ThreePid getEmailThreePid() { * @param listener */ public void addPhoneNumberThreePid(final Context context, final String phoneNumber, final String countryCode, final ThreePidRequestListener listener) { - final ThreePid pid = new ThreePid(phoneNumber, countryCode, ThreePid.MEDIUM_MSISDN); + final ThreePid pid = ThreePid.Companion.fromPhoneNumber(phoneNumber, countryCode); requestValidationToken(context, pid, listener); } @@ -908,19 +915,25 @@ private void doRequestValidationToken(final Context context, final @Nullable String isUrl, final ThreePidRequestListener listener) { if (getThirdPidRestClient() != null) { - switch (pid.medium) { + switch (pid.getMedium()) { case ThreePid.MEDIUM_EMAIL: - String nextLink = NEXTLINK_BASE_URL + "/#/register?client_secret=" + pid.clientSecret; + String nextLink = NEXTLINK_BASE_URL + "/#/register?client_secret=" + pid.getClientSecret(); nextLink += "&hs_url=" + mHsConfig.getHomeserverUri().toString(); if (isUrl != null) { nextLink += "&is_url=" + isUrl; } nextLink += "&session_id=" + mRegistrationResponse.session; - pid.requestEmailValidationToken( - null, - getProfileRestClient(), nextLink, true, new ApiCallback() { + + getProfileRestClient().requestEmailValidationToken(IdentityServerManager.Companion.removeProtocol(isUrl), + pid.getEmailAddress(), + pid.getClientSecret(), + pid.getSendAttempt(), + nextLink, + true, + new ApiCallback() { @Override - public void onSuccess(Void aVoid) { + public void onSuccess(RequestEmailValidationResponse info) { + pid.setSid(info.sid); listener.onThreePidRequested(pid); } @@ -949,36 +962,44 @@ public void onMatrixError(MatrixError e) { }); break; case ThreePid.MEDIUM_MSISDN: - pid.requestPhoneNumberValidationToken(null, getProfileRestClient(), true, new ApiCallback() { - @Override - public void onSuccess(Void aVoid) { - mPhoneNumber = pid; - listener.onThreePidRequested(pid); - } + getProfileRestClient().requestPhoneNumberValidationToken( + IdentityServerManager.Companion.removeProtocol(isUrl), + pid.getPhoneNumber(), + pid.getCountry(), + pid.getClientSecret(), + pid.getSendAttempt(), + true, + new ApiCallback() { + @Override + public void onSuccess(RequestPhoneNumberValidationResponse info) { + pid.setSid(info.sid); + mPhoneNumber = pid; + listener.onThreePidRequested(pid); + } - @Override - public void onNetworkError(final Exception e) { - warnAfterCertificateError(context, e, pid, listener); - } + @Override + public void onNetworkError(final Exception e) { + warnAfterCertificateError(context, e, pid, listener); + } - @Override - public void onUnexpectedError(Exception e) { - String errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_error, e.getLocalizedMessage()); - listener.onThreePidRequestFailed(errorMessage); - } + @Override + public void onUnexpectedError(Exception e) { + String errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_error, e.getLocalizedMessage()); + listener.onThreePidRequestFailed(errorMessage); + } - @Override - public void onMatrixError(MatrixError e) { - String errorMessage = null; - if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) { - errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_already_used_error, null); - } else { - errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_error, e.mReason); - } + @Override + public void onMatrixError(MatrixError e) { + String errorMessage = null; + if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) { + errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_already_used_error, null); + } else { + errorMessage = build3PidErrorMessage(context, R.string.account_phone_number_error, e.mReason); + } - listener.onThreePidRequestFailed(errorMessage); - } - }); + listener.onThreePidRequestFailed(errorMessage); + } + }); break; } } diff --git a/vector/src/main/java/im/vector/activity/LoginActivity.java b/vector/src/main/java/im/vector/activity/LoginActivity.java index 86b4b60048..505c4b0eb9 100644 --- a/vector/src/main/java/im/vector/activity/LoginActivity.java +++ b/vector/src/main/java/im/vector/activity/LoginActivity.java @@ -1308,11 +1308,10 @@ public void onSuccess(ThreePid thirdPid) { mMode = MODE_FORGOT_PASSWORD_WAITING_VALIDATION; refreshDisplay(true); - mForgotPid = new ThreePidCredentials(); - mForgotPid.clientSecret = thirdPid.getClientSecret(); - mForgotPid.idServer = identityServerUri.getHost(); - mForgotPid.sid = thirdPid.getSid(); - } + mForgotPid = new ThreePidCredentials(); + mForgotPid.clientSecret = thirdPid.getClientSecret(); + mForgotPid.idServer = identityServerHost; + mForgotPid.sid = thirdPid.getSid(); } } @@ -2281,7 +2280,7 @@ private void restoreSavedData(@NonNull Bundle savedInstanceState) { mUniversalLinkUri = savedInstanceState.getParcelable(VectorUniversalLinkReceiver.EXTRA_UNIVERSAL_LINK_URI); } - mPendingEmailValidation = (ThreePid) savedInstanceState.getSerializable(SAVED_CREATION_EMAIL_THREEPID); + mPendingEmailValidation = savedInstanceState.getParcelable(SAVED_CREATION_EMAIL_THREEPID); } @Override @@ -2302,7 +2301,7 @@ public void onSaveInstanceState(Bundle savedInstanceState) { // Retrieve the current email three pid ThreePid email3pid = mRegistrationManager.getEmailThreePid(); if (null != email3pid) { - savedInstanceState.putSerializable(SAVED_CREATION_EMAIL_THREEPID, email3pid); + savedInstanceState.putParcelable(SAVED_CREATION_EMAIL_THREEPID, email3pid); } } @@ -2667,7 +2666,7 @@ void submitThreePids() { if (!TextUtils.isEmpty(email)) { // Communicate email to singleton (will be validated later on) - mRegistrationManager.addEmailThreePid(new ThreePid(email, ThreePid.MEDIUM_EMAIL)); + mRegistrationManager.addEmailThreePid(ThreePid.Companion.fromEmail(email)); } if (mRegistrationPhoneNumberHandler.getPhoneNumber() != null) { @@ -2684,7 +2683,7 @@ public void onIdentityServerMissing() { @Override public void onThreePidRequested(ThreePid pid) { enableLoadingScreen(false); - if (!TextUtils.isEmpty(pid.sid)) { + if (!TextUtils.isEmpty(pid.getSid())) { onPhoneNumberSidReceived(pid); } } diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java index b4d8ee8b6e..bd49371e9c 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java +++ b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java @@ -261,15 +261,11 @@ private void addPhoneNumber(final Phonenumber.PhoneNumber phoneNumber) { final String e164phone = PhoneNumberUtils.getE164format(phoneNumber); // Extract from phone number object instead of using mCurrentRegionCode just in case final String countryCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(phoneNumber.getCountryCode()); - final ThreePid pid = new ThreePid(e164phone, countryCode, ThreePid.MEDIUM_MSISDN); + final ThreePid pid = ThreePid.Companion.fromPhoneNumber(e164phone, countryCode); - Uri identityServer = null; - if (mSession.getIdentityServerManager().getIdentityServerUrl() != null) { - identityServer = Uri.parse(mSession.getIdentityServerManager().getIdentityServerUrl()); - } - mSession.getMyUser().requestPhoneNumberValidationToken(identityServer,pid, new ApiCallback() { + mSession.getIdentityServerManager().startAddSessionForPhoneNumber(pid,null, new ApiCallback() { @Override - public void onSuccess(Void info) { + public void onSuccess(ThreePid pid) { hideWaitingView(); Intent intent = PhoneNumberVerificationActivity.getIntent(PhoneNumberAdditionActivity.this, mSession.getCredentials().userId, pid); diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java index 737fce7e0b..d4f0ef6aed 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -36,6 +35,7 @@ import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.core.callback.ApiCallback; import org.matrix.androidsdk.core.model.MatrixError; +import org.matrix.androidsdk.rest.model.SuccessResult; import org.matrix.androidsdk.rest.model.pid.ThreePid; import im.vector.Matrix; @@ -103,7 +103,7 @@ public void initUiAndData() { return; } - mThreePid = (ThreePid) intent.getSerializableExtra(EXTRA_PID); + mThreePid = intent.getParcelableExtra(EXTRA_PID); mPhoneNumberCode.addTextChangedListener(this); mPhoneNumberCode.setOnEditorActionListener(this); @@ -148,14 +148,11 @@ private void submitCode() { mPhoneNumberCodeLayout.setError(getString(R.string.settings_phone_number_verification_error_empty_code)); } else { showWaitingView(); - mSession.getIdentityServerManager().submitValidationToken(mThreePid.medium, - mPhoneNumberCode.getText().toString(), - mThreePid.clientSecret, - mThreePid.sid, - new ApiCallback() { + mSession.getIdentityServerManager().submitValidationToken(mThreePid, mPhoneNumberCode.getText().toString(), + new ApiCallback() { @Override - public void onSuccess(Boolean isSuccess) { - if (isSuccess) { + public void onSuccess(SuccessResult result) { + if (result.success) { // the validation of mail ownership succeed, just resume the registration flow // next step: just register Log.e(LOG_TAG, "## submitPhoneNumberValidationToken(): onSuccess() - registerAfterEmailValidations() started"); @@ -187,9 +184,7 @@ public void onUnexpectedError(Exception e) { } private void registerAfterPhoneNumberValidation(final ThreePid pid) { - String idServer = mSession.getIdentityServerManager().getIdentityServerUrl(); - if (idServer == null) return; - mSession.getMyUser().add3Pid(Uri.parse(idServer), pid, false, new ApiCallback() { + mSession.getIdentityServerManager().finalizeAddSessionForEmail(pid, new ApiCallback() { @Override public void onSuccess(Void info) { Intent intent = new Intent(); diff --git a/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java index eb8e09f4c1..a6a0d9553d 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java @@ -36,8 +36,10 @@ import org.matrix.androidsdk.core.model.MatrixError; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.features.identityserver.IdentityServerNotConfiguredException; import org.matrix.androidsdk.rest.model.CreateRoomParams; import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.rest.model.pid.Invite3Pid; import java.util.ArrayList; import java.util.Comparator; @@ -48,6 +50,7 @@ import im.vector.R; import im.vector.adapters.ParticipantAdapterItem; import im.vector.adapters.VectorRoomCreationAdapter; +import kotlin.Pair; public class VectorRoomCreationActivity extends MXCActionBarActivity { // tags @@ -434,11 +437,14 @@ private void createRoom(final List participants) { } } - boolean res = params.addParticipantIds(mSession.getIdentityServerManager().getIdentityServerUri(), mSession.getHomeServerConfig(), ids); + try { + Pair, List> listPair = mSession. + getIdentityServerManager(). + getInvite3pid(mSession.getHomeServerConfig().getCredentials().userId, ids); + + params.invite3pids = listPair.getFirst(); + params.invitedUserIds = listPair.getSecond(); - if (res) { - Toast.makeText(this, R.string.identity_server_not_defined, Toast.LENGTH_LONG).show(); - } else { mSession.createRoom(params, new ApiCallback() { @Override public void onSuccess(final String roomId) { @@ -486,6 +492,9 @@ public void onUnexpectedError(final Exception e) { onError(e.getLocalizedMessage()); } }); + } catch (IdentityServerNotConfiguredException e) { + Toast.makeText(this, R.string.identity_server_not_defined, Toast.LENGTH_LONG).show(); } + } } diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index e4ed838c83..b13d6811fc 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -42,7 +42,6 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.content.edit -import androidx.core.net.toUri import androidx.core.view.isVisible import androidx.preference.* import com.bumptech.glide.Glide @@ -97,7 +96,6 @@ import java.lang.ref.WeakReference import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* -import java.util.logging.Logger class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -1541,7 +1539,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref * @param preferenceSummary the displayed 3pid */ private fun displayDelete3PIDConfirmationDialog(pid: ThirdPartyIdentifier, preferenceSummary: CharSequence) { - val mediumFriendlyName = ThreePid.getMediumFriendlyName(pid.medium, activity).toLowerCase(VectorLocale.applicationLocale) + val mediumFriendlyName = ThreePid.getMediumFriendlyName(pid.medium, requireContext()).toLowerCase(VectorLocale.applicationLocale) val dialogMessage = getString(R.string.settings_delete_threepid_confirmation, mediumFriendlyName, preferenceSummary) activity?.let { @@ -1897,33 +1895,32 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref return } - val pid = ThreePid(email, ThreePid.MEDIUM_EMAIL) + val pid = ThreePid.fromEmail(email) displayLoadingView() - mSession.myUser.requestEmailValidationToken( - mSession.identityServerManager.getIdentityServerUrl()?.toUri(), - pid, object : ApiCallback { - override fun onSuccess(info: Void?) { - activity?.runOnUiThread { showEmailValidationDialog(pid) } - } + mSession.identityServerManager.startAddSessionForEmail(pid, null, + object : ApiCallback { + override fun onSuccess(info: ThreePid) { + activity?.runOnUiThread { showEmailValidationDialog(pid) } + } - override fun onNetworkError(e: Exception) { - onCommonDone(e.localizedMessage) - } + override fun onNetworkError(e: Exception) { + onCommonDone(e.localizedMessage) + } - override fun onMatrixError(e: MatrixError) { - if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) { - onCommonDone(getString(R.string.account_email_already_used_error)) - } else { - onCommonDone(e.localizedMessage) - } - } + override fun onMatrixError(e: MatrixError) { + if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) { + onCommonDone(getString(R.string.account_email_already_used_error)) + } else { + onCommonDone(e.localizedMessage) + } + } - override fun onUnexpectedError(e: Exception) { - onCommonDone(e.localizedMessage) - } - }) + override fun onUnexpectedError(e: Exception) { + onCommonDone(e.localizedMessage) + } + }) } /** @@ -1937,39 +1934,38 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref .setTitle(R.string.account_email_validation_title) .setMessage(R.string.account_email_validation_message) .setPositiveButton(R.string._continue) { _, _ -> - // We do not bind anymore emails when registering, so let's do the same here - val idServer = mSession.identityServerManager.getIdentityServerUrl() - if (idServer == null) { - onCommonDone(requireContext().getString(R.string.identity_server_not_defined)) - } else { - mSession.myUser.add3Pid(idServer.toUri(), pid, false, object : ApiCallback { - override fun onSuccess(info: Void?) { + mSession.identityServerManager.finalizeAddSessionForEmail(pid, object : ApiCallback { + override fun onSuccess(info: Void?) { + it.runOnUiThread { + hideLoadingView() + mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback(){ + override fun onSuccess(info: Void?) { + refreshEmailsList() + } + }) + } + } + + override fun onNetworkError(e: Exception) { + onCommonDone(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) { it.runOnUiThread { hideLoadingView() - refreshEmailsList() + it.toast(R.string.account_email_validation_error) } - } - - override fun onNetworkError(e: Exception) { + } else { onCommonDone(e.localizedMessage) } + } - override fun onMatrixError(e: MatrixError) { - if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) { - it.runOnUiThread { - hideLoadingView() - it.toast(R.string.account_email_validation_error) - } - } else { - onCommonDone(e.localizedMessage) - } - } + override fun onUnexpectedError(e: Exception) { + onCommonDone(e.localizedMessage) + } + }) - override fun onUnexpectedError(e: Exception) { - onCommonDone(e.localizedMessage) - } - }) - } } .setNegativeButton(R.string.cancel) { _, _ -> hideLoadingView() @@ -1987,7 +1983,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref * Refresh phone number list */ private fun refreshPhoneNumbersList() { - val isURL = mSession.identityServerManager.getIdentityServerUrl() + val isURL = mSession.identityServerManager.getIdentityServerUrl() if (isURL != null) { updatePhoneNumbersList() } else { diff --git a/vector/src/main/java/im/vector/fragments/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/fragments/discovery/DiscoverySettingsViewModel.kt index c7f604e7fb..9fbb84550f 100644 --- a/vector/src/main/java/im/vector/fragments/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/fragments/discovery/DiscoverySettingsViewModel.kt @@ -16,7 +16,6 @@ package im.vector.fragments.discovery import android.text.TextUtils -import androidx.core.net.toUri import com.airbnb.mvrx.* import com.google.i18n.phonenumbers.PhoneNumberUtil import im.vector.Matrix @@ -25,6 +24,7 @@ import org.matrix.androidsdk.MXSession import org.matrix.androidsdk.core.callback.ApiCallback import org.matrix.androidsdk.core.model.MatrixError import org.matrix.androidsdk.features.identityserver.IdentityServerManager +import org.matrix.androidsdk.rest.model.SuccessResult import org.matrix.androidsdk.rest.model.pid.ThirdPartyIdentifier import org.matrix.androidsdk.rest.model.pid.ThreePid @@ -101,101 +101,31 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v fun shareEmail(email: String) = withState { state -> if (state.identityServer.invoke() == null) return@withState - val currentMails = state.emailList.invoke() ?: return@withState - changeMailState(email, Loading()) - val pid = ThirdPartyIdentifier().apply { - medium = ThreePid.MEDIUM_EMAIL - address = email - } - val existing3pid = state.emailList.invoke()?.find { it.value == email }?.let { it._3pid } - - mxSession?.myUser?.delete3Pid(pid, object : ApiCallback { - override fun onSuccess(info: Void?) { - request3pidToken(existing3pid, ThreePid.MEDIUM_EMAIL, email, PidInfo.SharedState.NOT_VERIFIED_FOR_BIND) - } - - override fun onUnexpectedError(e: java.lang.Exception) { - handleDeleteError(e) - } - - override fun onNetworkError(e: java.lang.Exception) { - handleDeleteError(e) - } - - override fun onMatrixError(e: MatrixError) { - handleDeleteError(Exception(e.message)) - } - - private fun handleDeleteError(e: java.lang.Exception) { - changeMailState(email, Fail(e)) - } - - }) - } + changeMailState(email, Loading(), null) - private fun request3pidToken(existingPid: ThreePid?, medium: String, address: String, state: PidInfo.SharedState) { - var threePid: ThreePid? = existingPid - if (threePid == null) { - if (medium == ThreePid.MEDIUM_EMAIL) { - threePid = ThreePid(address, medium) - } else if (medium == ThreePid.MEDIUM_MSISDN) { - val phoneNumber = PhoneNumberUtil.getInstance() - .parse("+${address}", null) - val countryCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(phoneNumber.countryCode) - threePid = ThreePid(PhoneNumberUtils.getE164format(phoneNumber), countryCode, ThreePid.MEDIUM_MSISDN) - } - } - - //mm should not happen - if (threePid == null) return - - val callback = object : ApiCallback { - override fun onSuccess(info: Void?) { - if (medium == ThreePid.MEDIUM_EMAIL) { - changeMailState(address, Success(state), threePid) - } else if (medium == ThreePid.MEDIUM_MSISDN) { - changePNState(address, Success(state), threePid) - } - } - - override fun onUnexpectedError(e: java.lang.Exception) { - reportError(e) - } + mxSession?.identityServerManager?.startBindSessionForEmail(email, null, + object : ApiCallback { + override fun onSuccess(threePid: ThreePid) { + changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND), threePid) + } - override fun onNetworkError(e: java.lang.Exception) { - reportError(e) - } + override fun onUnexpectedError(e: java.lang.Exception) { + handleDeleteError(e) + } - private fun reportError(e: java.lang.Exception) { - if (medium == ThreePid.MEDIUM_EMAIL) { - changeMailState(address, Fail(e), threePid) - } else if (medium == ThreePid.MEDIUM_MSISDN) { - changePNState(address, Fail(e)) - } - } + override fun onNetworkError(e: java.lang.Exception) { + handleDeleteError(e) + } + override fun onMatrixError(e: MatrixError) { + handleDeleteError(Exception(e.message)) + } - override fun onMatrixError(e: MatrixError) { - reportError(java.lang.Exception(e.message)) - if (TextUtils.equals(MatrixError.THREEPID_IN_USE, e.errcode)) { - // This may just mean they are dealing with an old homeserver, - // versus the 3PID already being bound on this homeserver by another user. - // -> Delete 3pid then retry? - } - } + private fun handleDeleteError(e: java.lang.Exception) { + changeMailState(email, Fail(e)) + } - } - if (medium == ThreePid.MEDIUM_EMAIL) { - mxSession?.myUser?.requestEmailValidationToken( - mxSession.identityServerManager.getIdentityServerUrl()?.toUri(), - threePid, - callback) - } else if (medium == ThreePid.MEDIUM_MSISDN) { - mxSession?.myUser?.requestPhoneNumberValidationToken( - mxSession.identityServerManager.getIdentityServerUrl()?.toUri(), - threePid, - callback) - } + }) } @@ -255,14 +185,13 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v if (state.emailList.invoke() == null) return@withState changeMailState(email, Loading()) - val pid = ThirdPartyIdentifier().apply { - medium = ThreePid.MEDIUM_EMAIL - address = email - } - - mxSession?.myUser?.delete3Pid(pid, object : ApiCallback { - override fun onSuccess(info: Void?) { - request3pidToken(null, ThreePid.MEDIUM_EMAIL, email, PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) + mxSession?.identityServerManager?.startUnBindSession(ThreePid.MEDIUM_EMAIL, email, null, object : ApiCallback> { + override fun onSuccess(info: Pair) { + if (info.first /*requires mail validation */) { + changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND), info.second) + } else { + changeMailState(email, Success(PidInfo.SharedState.NOT_SHARED)) + } } override fun onUnexpectedError(e: java.lang.Exception) { @@ -282,6 +211,7 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v } }) + } fun revokePN(pn: String) = withState { state -> @@ -289,14 +219,17 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v if (state.emailList.invoke() == null) return@withState changePNState(pn, Loading()) - val pid = ThirdPartyIdentifier().apply { - medium = ThreePid.MEDIUM_MSISDN - address = pn - } + val phoneNumber = PhoneNumberUtil.getInstance() + .parse("+${pn}", null) + val countryCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(phoneNumber.countryCode) - mxSession?.myUser?.delete3Pid(pid, object : ApiCallback { - override fun onSuccess(info: Void?) { - request3pidToken(null, ThreePid.MEDIUM_MSISDN, pn, PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) + mxSession?.identityServerManager?.startUnBindSession(ThreePid.MEDIUM_MSISDN, pn, countryCode, object : ApiCallback> { + override fun onSuccess(info: Pair) { + if (info.first /*requires mail validation */) { + changePNState(pn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND), info.second) + } else { + changePNState(pn, Success(PidInfo.SharedState.NOT_SHARED)) + } } override fun onUnexpectedError(e: java.lang.Exception) { @@ -316,22 +249,21 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v } }) + } fun sharePN(pn: String) = withState { state -> if (state.identityServer.invoke() == null) return@withState changePNState(pn, Loading()) - val pid = ThirdPartyIdentifier().apply { - medium = ThreePid.MEDIUM_MSISDN - address = pn - } + val phoneNumber = PhoneNumberUtil.getInstance() + .parse("+${pn}", null) + val countryCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(phoneNumber.countryCode) - val existing3pid = state.phoneNumbersList.invoke()?.find { it.value == pn }?.let { it._3pid } - mxSession?.myUser?.delete3Pid(pid, object : ApiCallback { - override fun onSuccess(info: Void?) { - request3pidToken(existing3pid, ThreePid.MEDIUM_MSISDN, pn, PidInfo.SharedState.NOT_VERIFIED_FOR_BIND) + mxSession?.identityServerManager?.startBindSessionForPhoneNumber(pn, countryCode, null, object : ApiCallback { + override fun onSuccess(id: ThreePid) { + changePNState(pn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND), id) } override fun onUnexpectedError(e: java.lang.Exception) { @@ -352,33 +284,6 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v } }) - //Fake call -// val currentPN = state.phoneNumbersList.invoke() ?: return@withState -// val updated = currentPN.map { -// if (it.value == pn) { -// it.copy(isShared = Loading()) -// } else { -// it -// } -// } -// setState { -// copy(phoneNumbersList = Success(updated)) -// } -// GlobalScope.launch { -// kotlinx.coroutines.delay(1000) -// setState { -// val currentPN = phoneNumbersList.invoke() ?: emptyList() -// copy(phoneNumbersList = Success( -// currentPN.map { -// if (it.value == pn) { -// it.copy(isShared = Success(PidInfo.SharedState.SHARED)) -// } else { -// it -// } -// } -// )) -// } -// } } private fun changePNState(pn: String, sharedState: Async) { @@ -542,12 +447,10 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v val pid = state.phoneNumbersList.invoke()?.find { it.value == msisdn }?._3pid ?: return@withState - mxSession?.identityServerManager?.submitValidationToken(ThreePid.MEDIUM_MSISDN, + mxSession?.identityServerManager?.submitValidationToken(pid, code, - pid.clientSecret, - pid.sid, - object : ApiCallback { - override fun onSuccess(info: Boolean?) { + object : ApiCallback { + override fun onSuccess(info: SuccessResult) { add3pid(ThreePid.MEDIUM_MSISDN, msisdn, bind) } @@ -567,57 +470,52 @@ class DiscoverySettingsViewModel(initialState: DiscoverySettingsState, private v ) } - fun add3pid(medium: String, address: String, bind: Boolean) { + fun add3pid(medium: String, address: String, bind: Boolean) = withState { state -> + val _3pid: ThreePid if (medium == ThreePid.MEDIUM_EMAIL) { changeMailState(address, Loading()) + _3pid = state.emailList.invoke()?.find { it.value == address }?._3pid + ?: return@withState } else { changePNState(address, Loading()) + _3pid = state.phoneNumbersList.invoke()?.find { it.value == address }?._3pid + ?: return@withState } - withState { state -> - val _3pid = if (medium == ThreePid.MEDIUM_EMAIL) { - state.emailList.invoke()?.find { it.value == address }?._3pid - } else { - state.phoneNumbersList.invoke()?.find { it.value == address }?._3pid + + mxSession?.identityServerManager?.finalizeBindSessionFor3PID(_3pid, object : ApiCallback { + override fun onSuccess(info: Void?) { + val sharedState = Success(if (bind) PidInfo.SharedState.SHARED else PidInfo.SharedState.NOT_SHARED) + if (medium == ThreePid.MEDIUM_EMAIL) { + changeMailState(address, sharedState, null) + } else { + changePNState(address, sharedState, null) + } } - mxSession?.myUser?.add3Pid( - mxSession.identityServerManager.getIdentityServerUrl()?.toUri(), - _3pid, - bind, - object : ApiCallback { - override fun onSuccess(info: Void?) { - val sharedState = Success(if (bind) PidInfo.SharedState.SHARED else PidInfo.SharedState.NOT_SHARED) - if (medium == ThreePid.MEDIUM_EMAIL) { - changeMailState(address, sharedState, null) - } else { - changePNState(address, sharedState, null) - } - } + override fun onUnexpectedError(e: java.lang.Exception) { + reportError(e) + } - override fun onUnexpectedError(e: java.lang.Exception) { - reportError(e) - } + override fun onNetworkError(e: java.lang.Exception) { + reportError(e) + } - override fun onNetworkError(e: java.lang.Exception) { - reportError(e) - } + private fun reportError(e: java.lang.Exception) { + val sharedState = Success(if (bind) PidInfo.SharedState.NOT_VERIFIED_FOR_BIND else PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) + if (medium == ThreePid.MEDIUM_EMAIL) { + changeMailState(address, sharedState) + } else { + changePNState(address, sharedState) + } + } - private fun reportError(e: java.lang.Exception) { - val sharedState = Success(if (bind) PidInfo.SharedState.NOT_VERIFIED_FOR_BIND else PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) - if (medium == ThreePid.MEDIUM_EMAIL) { - changeMailState(address, sharedState) - } else { - changePNState(address, sharedState) - } - } + override fun onMatrixError(e: MatrixError) { + reportError(java.lang.Exception(e.message)) + } - override fun onMatrixError(e: MatrixError) { - reportError(java.lang.Exception(e.message)) - } + }) - }) - } } companion object : MvRxViewModelFactory {