MOBILE-4034 core: Fix password changed detection in Android

main
Dani Palou 2022-10-27 15:40:36 +02:00
parent 98e54d05be
commit 7b032aee18
4 changed files with 71 additions and 19 deletions

View File

@ -148,7 +148,7 @@ export class AppComponent implements OnInit, AfterViewInit {
CorePlatform.resume.subscribe(() => {
// Wait a second before setting it to false since in iOS there could be some frozen WS calls.
setTimeout(() => {
if (CoreLoginHelper.isWaitingForBrowser()) {
if (CoreLoginHelper.isWaitingForBrowser() && !CoreUtils.isInAppBrowserOpen()) {
CoreLoginHelper.stopWaitingForBrowser();
CoreLoginHelper.checkLogout();
}

View File

@ -35,6 +35,7 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
logoutLabel: string;
protected urlLoadedObserver?: CoreEventObserver;
protected messageObserver?: CoreEventObserver;
protected browserClosedObserver?: CoreEventObserver;
constructor() {
@ -90,9 +91,34 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
return;
}
this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_START, (event) => {
this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_STOP, (event) => {
if (event.url.match(/\/login\/change_password\.php.*return=1/)) {
// Password should have changed.
// Password has changed, close the IAB now.
CoreUtils.closeInAppBrowser();
this.login();
return;
}
if (!event.url.match(/\/login\/change_password\.php/)) {
return;
}
// Use a script to check if the user changed the password, in some platforms we cannot tell using the URL.
CoreUtils.getInAppBrowserInstance()?.executeScript({
code: `
if (
document.querySelector('input[type="password"]') === null &&
document.querySelector('button[type="submit"]') !== null
) {
webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify({ passwordChanged: true }));
}
`,
});
});
this.messageObserver = CoreEvents.on(CoreEvents.IAB_MESSAGE, (data) => {
if (data.passwordChanged) {
CoreUtils.closeInAppBrowser();
this.login();
}
@ -100,8 +126,11 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
this.browserClosedObserver = CoreEvents.on(CoreEvents.IAB_EXIT, () => {
this.urlLoadedObserver?.off();
this.messageObserver?.off();
this.browserClosedObserver?.off();
delete this.urlLoadedObserver;
delete this.messageObserver;
delete this.browserClosedObserver;
});
}
@ -111,6 +140,7 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
*/
ngOnDestroy(): void {
this.urlLoadedObserver?.off();
this.messageObserver?.off();
this.browserClosedObserver?.off();
}

View File

@ -266,6 +266,24 @@ export class CoreUtilsProvider {
}
}
/**
* Get inapp browser instance (if any).
*
* @return IAB instance, undefined if not open.
*/
getInAppBrowserInstance(): InAppBrowserObject | undefined {
return this.iabInstance;
}
/**
* Check if inapp browser is open.
*
* @return Whether it's open.
*/
isInAppBrowserOpen(): boolean {
return !!this.iabInstance;
}
/**
* Clone a variable. It should be an object, array or primitive type.
*
@ -1024,15 +1042,14 @@ export class CoreUtilsProvider {
this.setInAppBrowserToolbarColors(options);
this.iabInstance?.close(); // Close window if there is one already open, only allow one.
this.iabInstance = InAppBrowser.create(url, '_blank', options);
if (CorePlatform.isMobile()) {
let loadStopSubscription: Subscription | undefined;
const loadStartUrls: string[] = [];
// Trigger global events when a url is loaded or the window is closed. This is to make it work like in Ionic 1.
const loadStartSubscription = this.iabInstance.on('loadstart').subscribe((event) => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
// Store the last loaded URLs (max 10).
loadStartUrls.push(event.url);
@ -1044,25 +1061,26 @@ export class CoreUtilsProvider {
});
});
if (CoreApp.isAndroid()) {
// Load stop is needed with InAppBrowser v3. Custom URL schemes no longer trigger load start, simulate it.
loadStopSubscription = this.iabInstance.on('loadstop').subscribe((event) => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
if (loadStartUrls.indexOf(event.url) == -1) {
// The URL was stopped but not started, probably a custom URL scheme.
CoreEvents.trigger(CoreEvents.IAB_LOAD_START, event);
}
});
const loadStopSubscription = this.iabInstance.on('loadstop').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_LOAD_STOP, event);
});
}
});
const messageSubscription = this.iabInstance.on('message').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_MESSAGE, event.data);
});
});
const exitSubscription = this.iabInstance.on('exit').subscribe((event) => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
loadStartSubscription.unsubscribe();
loadStopSubscription && loadStopSubscription.unsubscribe();
loadStopSubscription.unsubscribe();
messageSubscription.unsubscribe();
exitSubscription.unsubscribe();
this.iabInstance = undefined;
CoreEvents.trigger(CoreEvents.IAB_EXIT, event);
});
});

View File

@ -53,6 +53,8 @@ export interface CoreEventsData {
[CoreEvents.SECTION_STATUS_CHANGED]: CoreEventSectionStatusChangedData;
[CoreEvents.ACTIVITY_DATA_SENT]: CoreEventActivityDataSentData;
[CoreEvents.IAB_LOAD_START]: InAppBrowserEvent;
[CoreEvents.IAB_LOAD_STOP]: InAppBrowserEvent;
[CoreEvents.IAB_MESSAGE]: Record<string, unknown>;
[CoreEvents.LOGIN_SITE_CHECKED]: CoreEventLoginSiteCheckedData;
[CoreEvents.LOGIN_SITE_UNCHECKED]: CoreEventLoginSiteUncheckedData;
[CoreEvents.SEND_ON_ENTER_CHANGED]: CoreEventSendOnEnterChangedData;
@ -99,7 +101,9 @@ export class CoreEvents {
static readonly LOGIN_SITE_CHECKED = 'login_site_checked';
static readonly LOGIN_SITE_UNCHECKED = 'login_site_unchecked';
static readonly IAB_LOAD_START = 'inappbrowser_load_start';
static readonly IAB_LOAD_STOP = 'inappbrowser_load_stop';
static readonly IAB_EXIT = 'inappbrowser_exit';
static readonly IAB_MESSAGE = 'inappbrowser_message';
static readonly APP_LAUNCHED_URL = 'app_launched_url'; // App opened with a certain URL (custom URL scheme).
static readonly FILE_SHARED = 'file_shared';
static readonly KEYBOARD_CHANGE = 'keyboard_change';