diff --git a/vector/src/agent/AndroidManifest.xml b/vector/src/agent/AndroidManifest.xml
index 60034f9eec0..da39331dc6c 100755
--- a/vector/src/agent/AndroidManifest.xml
+++ b/vector/src/agent/AndroidManifest.xml
@@ -13,8 +13,12 @@
-
-
+
+
+
+
+
+
@@ -25,8 +29,12 @@
-
-
+
+
+
+
+
+
@@ -37,8 +45,12 @@
-
-
+
+
+
+
+
+
@@ -49,8 +61,12 @@
-
-
+
+
+
+
+
+
@@ -61,8 +77,12 @@
-
-
+
+
+
+
+
+
@@ -73,8 +93,12 @@
-
-
+
+
+
+
+
+
@@ -85,8 +109,12 @@
-
-
+
+
+
+
+
+
@@ -97,8 +125,12 @@
-
-
+
+
+
+
+
+
@@ -109,8 +141,12 @@
-
-
+
+
+
+
+
+
@@ -121,8 +157,12 @@
-
-
+
+
+
+
+
+
@@ -133,8 +173,12 @@
-
-
+
+
+
+
+
+
@@ -145,8 +189,12 @@
-
-
+
+
+
+
+
+
@@ -157,8 +205,12 @@
-
-
+
+
+
+
+
+
@@ -169,8 +221,12 @@
-
-
+
+
+
+
+
+
@@ -181,8 +237,12 @@
-
-
+
+
+
+
+
+
@@ -193,8 +253,28 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/java/fr/gouv/tchap/activity/TchapLoginActivity.java b/vector/src/main/java/fr/gouv/tchap/activity/TchapLoginActivity.java
index a6fc7b5107f..fb47c7c1031 100644
--- a/vector/src/main/java/fr/gouv/tchap/activity/TchapLoginActivity.java
+++ b/vector/src/main/java/fr/gouv/tchap/activity/TchapLoginActivity.java
@@ -310,6 +310,9 @@ protected void onNewIntent(Intent aIntent) {
Log.d(LOG_TAG, "## onNewIntent(): Unexpected value - aIntent=null ");
} else if (null == (receivedBundle = aIntent.getExtras())) {
Log.d(LOG_TAG, "## onNewIntent(): Unexpected value - extras are missing");
+ } else if (receivedBundle.containsKey(VectorUniversalLinkActivity.EXTRA_VALIDATED_EMAIL_PARAMS)) {
+ Log.d(LOG_TAG, "## onNewIntent() Login activity resumed on a successful email verification");
+ resumeOnValidatedEmail(receivedBundle);
} else if (receivedBundle.containsKey(VectorUniversalLinkActivity.EXTRA_EMAIL_VALIDATION_PARAMS)) {
Log.d(LOG_TAG, "## onNewIntent() Login activity started by email verification for registration");
@@ -439,6 +442,9 @@ public void onClick(View view) {
if (receivedBundle.containsKey(VectorUniversalLinkReceiver.EXTRA_UNIVERSAL_LINK_URI)) {
mUniversalLinkUri = receivedBundle.getParcelable(VectorUniversalLinkReceiver.EXTRA_UNIVERSAL_LINK_URI);
Log.d(LOG_TAG, "## onCreate() Login activity started by universal link");
+ } else if (receivedBundle.containsKey(VectorUniversalLinkActivity.EXTRA_VALIDATED_EMAIL_PARAMS)) {
+ Log.d(LOG_TAG, "## onCreate() Login activity resumed on a successful email verification");
+ resumeOnValidatedEmail(receivedBundle);
} else if (receivedBundle.containsKey(VectorUniversalLinkActivity.EXTRA_EMAIL_VALIDATION_PARAMS)) {
Log.d(LOG_TAG, "## onCreate() Login activity started by email verification for registration");
if (processEmailValidationExtras(receivedBundle)) {
@@ -968,6 +974,84 @@ private void onFailureDuringAuthRequest(MatrixError matrixError) {
}
}
+ /**
+ * Parse the given bundle to check if it contains the parameters to pursue the operation for
+ * which the email has been verified.
+ * If yes, it initializes the TchapLoginActivity to finalize a registration or a reset password
+ * This is mainly used when the TchapLoginActivity is triggered from the {@link VectorUniversalLinkActivity}.
+ *
+ * @param bundle bundle to be parsed
+ */
+ private void resumeOnValidatedEmail(Bundle bundle) {
+ HashMap extraParams = (HashMap) bundle.getSerializable(VectorUniversalLinkActivity.EXTRA_VALIDATED_EMAIL_PARAMS);
+
+ if (null != extraParams) {
+ Log.d(LOG_TAG, "## resumeOnValidatedEmail(): IN");
+ Matrix.getInstance(this).clearSessions(this, true, null);
+
+ // display waiting UI..
+ enableLoadingScreen(true);
+ // display wait screen with no text (same as iOS) for now..
+ hideMainLayoutAndToast("");
+
+ String clientSecret = extraParams.get(VectorUniversalLinkActivity.KEY_MAIL_VALIDATION_CLIENT_SECRET);
+ String identityServerSessId = extraParams.get(VectorUniversalLinkActivity.KEY_MAIL_VALIDATION_IDENTITY_SERVER_SESSION_ID);
+ String sessionId = extraParams.get(VectorUniversalLinkActivity.KEY_MAIL_VALIDATION_SESSION_ID);
+ String homeServer = extraParams.get(VectorUniversalLinkActivity.KEY_MAIL_VALIDATION_HOME_SERVER_URL);
+ String identityServer = extraParams.get(VectorUniversalLinkActivity.KEY_MAIL_VALIDATION_IDENTITY_SERVER_URL);
+
+ // When the user tries to update his/her password after forgetting it (tap on the dedicated link)
+ // The HS / IS urls are not provided in the email link.
+ // This link should be only opened by the webclient (known issue server side)
+ // Use the current configuration by default (it might not work on some account if the user uses another HS)
+ if (null == homeServer) {
+ homeServer = getHomeServerUrl();
+ }
+ if (null == identityServer) {
+ identityServer = getIdentityServerUrl();
+ }
+
+ // test if the home server urls are valid
+ try {
+ Uri.parse(homeServer);
+ Uri.parse(identityServer);
+ } catch (Exception e) {
+ // Stop and display a toast to notify email has been validated
+ enableLoadingScreen(false);
+ Toast.makeText(TchapLoginActivity.this, getString(R.string.tchap_email_validation_succeeded), Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ final HomeServerConnectionConfig homeServerConfig
+ = mServerConfig
+ = HomeServerConnectionConfigFactoryKt.createHomeServerConnectionConfig(homeServer, identityServer);
+
+ // if sessionId is null, it means that this request has been triggered by clicking on a "forgot password" link
+ if (null == sessionId) {
+ Log.d(TchapLoginActivity.LOG_TAG, "## resumeOnValidatedEmail(): the password update is in progress");
+
+ mMode = MODE_FORGOT_PASSWORD_WAITING_VALIDATION;
+
+ mForgotPid = new ThreePidCredentials();
+ mForgotPid.clientSecret = clientSecret;
+ mForgotPid.idServer = homeServerConfig.getIdentityServerUri().getHost();
+ mForgotPid.sid = identityServerSessId;
+
+ mIsPasswordResetted = false;
+ onForgotOnEmailValidated(homeServerConfig);
+ } else {
+ // the validation of mail ownership succeed, just resume the registration flow
+ // next step: just register
+ Log.d(TchapLoginActivity.LOG_TAG, "## resumeOnValidatedEmail(): registerAfterEmailValidations() started");
+ mRegistrationManager.setHsConfig(homeServerConfig);
+ mMode = MODE_ACCOUNT_CREATION;
+ mRegistrationManager.registerAfterEmailValidation(TchapLoginActivity.this, clientSecret, identityServerSessId, identityServer, sessionId, TchapLoginActivity.this);
+ }
+ } else {
+ Log.d(LOG_TAG, "## resumeOnValidatedEmail(): skipped");
+ }
+ }
+
/**
* Parse the given bundle to check if it contains the email verification extra.
* If yes, it initializes the TchapLoginActivity to start in registration mode to finalize a registration
@@ -1137,8 +1221,6 @@ public void onUnexpectedError(Exception e) {
* @param registrationFlowResponse the response
*/
private void onRegistrationFlow(RegistrationFlowResponse registrationFlowResponse) {
- enableLoadingScreen(false);
-
mRegistrationResponse = registrationFlowResponse;
}
diff --git a/vector/src/main/java/im/vector/LoginHandler.java b/vector/src/main/java/im/vector/LoginHandler.java
index 619e8e32752..dfb09dfde8c 100644
--- a/vector/src/main/java/im/vector/LoginHandler.java
+++ b/vector/src/main/java/im/vector/LoginHandler.java
@@ -217,7 +217,8 @@ public void submitEmailTokenValidation(final Context aCtx,
final ApiCallback aRespCallback) {
ThirdPidRestClient restClient = new ThirdPidRestClient(aHomeServerConfig);
- restClient.submitValidationToken(
+ // Tchap: submitValidationToken returns an error 403 on Tchap server - We force the legacy version for the moment
+ restClient.submitValidationTokenLegacy(
ThreePid.MEDIUM_EMAIL,
aToken,
aClientSecret,
diff --git a/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java b/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java
index 674120d188e..6d4485bf3c3 100644
--- a/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java
+++ b/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java
@@ -27,6 +27,8 @@
import androidx.appcompat.app.AlertDialog;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import android.os.AsyncTask;
import android.text.TextUtils;
import android.widget.Toast;
@@ -54,6 +56,10 @@
import im.vector.R;
import im.vector.receiver.LoginConfig;
import im.vector.receiver.VectorUniversalLinkReceiver;
+import okhttp3.HttpUrl;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
/**
* Dummy activity used to dispatch the vector URL links.
@@ -65,10 +71,18 @@ public class VectorUniversalLinkActivity extends VectorAppCompatActivity {
private final VectorUniversalLinkReceiver mUniversalLinkReceiver = new VectorUniversalLinkReceiver();
//private static final String SUPPORTED_PATH_CONFIG = "/config/config";
+
+ private static final String MATRIX_PATH_PREFIX = "/_matrix/";
+ // Email validation query
+ private static final String REGISTRATION_EMAIL_VALIDATION_PATH_SUFFIX = "/registration/email/submit_token";
+ private static final String PASSWORD_RESET_EMAIL_VALIDATION_PATH_SUFFIX = "/password_reset/email/submit_token";
// Account validity query
private static final String ACCOUNT_VALIDITY_RENEW_PATH_SUFFIX = "/account_validity/renew";
private static final String ACCOUNT_VALIDITY_RENEW_TOKEN = "token";
+ // Intent Extras
+ public static final String EXTRA_VALIDATED_EMAIL_PARAMS = "EXTRA_VALIDATED_EMAIL_PARAMS";
+
@Override
public int getLayoutRes() {
// display a spinner while binding the email
@@ -91,46 +105,61 @@ public void initUiAndData() {
Uri intentUri = getIntent().getData();
String dataPath = intentUri.getPath();
- if (dataPath.endsWith(EMAIL_VALIDATION_PATH_SUFFIX)) {
- // We consider here an email validation
- final Map mailRegParams = parseMailRegistrationLink(intentUri);
-
- // Assume it is a new account creation when there is a next link, or when no session is already available.
- MXSession session = Matrix.getInstance(this).getDefaultSession();
-
- if (mailRegParams.containsKey(KEY_MAIL_VALIDATION_NEXT_LINK) || (null == session)) {
- if (session == null) {
- // build Login intent
- Intent intent = new Intent(VectorUniversalLinkActivity.this, TchapLoginActivity.class);
- intent.putExtra(EXTRA_EMAIL_VALIDATION_PARAMS, (HashMap) mailRegParams);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
-
- finish();
+ if (dataPath.startsWith(MATRIX_PATH_PREFIX)) {
+ if (dataPath.endsWith(REGISTRATION_EMAIL_VALIDATION_PATH_SUFFIX)) {
+ MXSession session = Matrix.getInstance(this).getDefaultSession();
+ if (session != null) {
+ Log.d(LOG_TAG, "## Prompt the user to logout before finalizing an account creation based on an email validation");
+ promptToLogoutBeforeHandlingRegistrationLink(intentUri.toString());
} else {
- Log.d(LOG_TAG, "## logout the current sessions, before finalizing an account creation based on an email validation");
-
- // This logout is asynchronous, pursue the action in the callback to have the LoginActivity in a "no credentials state".
- CommonActivityUtils.logout(VectorUniversalLinkActivity.this,
- Matrix.getMXSessions(VectorUniversalLinkActivity.this),
- true,
- new SimpleApiCallback() {
- @Override
- public void onSuccess(Void info) {
- Log.d(LOG_TAG, "## logout succeeded");
-
- // build Login intent
- Intent intent = new Intent(VectorUniversalLinkActivity.this, TchapLoginActivity.class);
- intent.putExtra(EXTRA_EMAIL_VALIDATION_PARAMS, (HashMap) mailRegParams);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
-
- finish();
- }
- });
+ new EmailValidationTask().execute(intentUri.toString(), true);
+ }
+ } else if (dataPath.endsWith(PASSWORD_RESET_EMAIL_VALIDATION_PATH_SUFFIX)) {
+ MXSession session = Matrix.getInstance(this).getDefaultSession();
+ new EmailValidationTask().execute(intentUri.toString(), session == null);
+ } else if (dataPath.endsWith(ACCOUNT_VALIDITY_RENEW_PATH_SUFFIX)) {
+ renewAccountValidity(intentUri);
+ } else if (dataPath.endsWith(LEGACY_EMAIL_VALIDATION_PATH_SUFFIX)) {
+ // We consider here an email validation
+ final Map mailRegParams = parseMailRegistrationLink(intentUri);
+
+ // Assume it is a new account creation when there is a next link, or when no session is already available.
+ MXSession session = Matrix.getInstance(this).getDefaultSession();
+
+ if (mailRegParams.containsKey(KEY_MAIL_VALIDATION_NEXT_LINK) || (null == session)) {
+ if (session == null) {
+ // build Login intent
+ Intent intent = new Intent(VectorUniversalLinkActivity.this, TchapLoginActivity.class);
+ intent.putExtra(EXTRA_EMAIL_VALIDATION_PARAMS, (HashMap) mailRegParams);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+ finish();
+ } else {
+ Log.d(LOG_TAG, "## logout the current sessions, before finalizing an account creation based on an email validation");
+
+ // This logout is asynchronous, pursue the action in the callback to have the LoginActivity in a "no credentials state".
+ CommonActivityUtils.logout(VectorUniversalLinkActivity.this,
+ Matrix.getMXSessions(VectorUniversalLinkActivity.this),
+ true,
+ new SimpleApiCallback() {
+ @Override
+ public void onSuccess(Void info) {
+ Log.d(LOG_TAG, "## logout succeeded");
+
+ // build Login intent
+ Intent intent = new Intent(VectorUniversalLinkActivity.this, TchapLoginActivity.class);
+ intent.putExtra(EXTRA_EMAIL_VALIDATION_PARAMS, (HashMap) mailRegParams);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+ finish();
+ }
+ });
+ }
+ } else {
+ emailBinding(intentUri, mailRegParams);
}
- } else {
- emailBinding(intentUri, mailRegParams);
}
// } else if (SUPPORTED_PATH_CONFIG.equals(dataPath)) {
// MXSession mSession = Matrix.getInstance(this).getDefaultSession();
@@ -143,8 +172,6 @@ public void onSuccess(Void info) {
// displayAlreadyLoginPopup();
// return;
// }
- } else if (dataPath.endsWith(ACCOUNT_VALIDITY_RENEW_PATH_SUFFIX)) {
- renewAccountValidity(intentUri);
} else {
intentAction = VectorUniversalLinkReceiver.BROADCAST_ACTION_UNIVERSAL_LINK;
}
@@ -170,6 +197,139 @@ protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mUniversalLinkReceiver);
}
+ /**
+ * Prompt to disconnect when clicking on registration email validation link
+ */
+ private void promptToLogoutBeforeHandlingRegistrationLink(String emailValidationLink) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.dialog_title_warning)
+ .setMessage(R.string.tchap_register_user_already_logged_in_prompt)
+ .setCancelable(false)
+ .setPositiveButton(R.string.logout, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ CommonActivityUtils.logout(VectorUniversalLinkActivity.this,
+ Matrix.getMXSessions(VectorUniversalLinkActivity.this),
+ true,
+ new SimpleApiCallback() {
+ @Override
+ public void onSuccess(Void info) {
+ Log.d(LOG_TAG, "## promptToLogoutBeforeHandlingRegistrationLink(): logout succeeded");
+ new EmailValidationTask().execute(emailValidationLink, true);
+ }
+ });
+ }
+ })
+ .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ })
+ .show();
+ }
+
+ private class EmailValidationTask extends AsyncTask
@@ -25,8 +29,12 @@
-
-
+
+
+
+
+
+
diff --git a/vector/src/protecteed/AndroidManifest.xml b/vector/src/protecteed/AndroidManifest.xml
index df8e1fcb435..b0eb3d4507d 100755
--- a/vector/src/protecteed/AndroidManifest.xml
+++ b/vector/src/protecteed/AndroidManifest.xml
@@ -13,8 +13,12 @@
-
-
+
+
+
+
+
+
@@ -25,8 +29,12 @@
-
-
+
+
+
+
+
+
@@ -37,8 +45,12 @@
-
-
+
+
+
+
+
+
@@ -49,8 +61,12 @@
-
-
+
+
+
+
+
+
@@ -61,8 +77,12 @@
-
-
+
+
+
+
+
+
@@ -73,8 +93,12 @@
-
-
+
+
+
+
+
+
@@ -85,8 +109,12 @@
-
-
+
+
+
+
+
+
@@ -97,8 +125,12 @@
-
-
+
+
+
+
+
+
@@ -109,8 +141,12 @@
-
-
+
+
+
+
+
+
@@ -121,8 +157,12 @@
-
-
+
+
+
+
+
+
@@ -133,8 +173,12 @@
-
-
+
+
+
+
+
+
@@ -145,8 +189,12 @@
-
-
+
+
+
+
+
+
@@ -157,8 +205,12 @@
-
-
+
+
+
+
+
+
@@ -169,8 +221,12 @@
-
-
+
+
+
+
+
+