forked from EVOgeek/Vmeda.Online
MOBILE-4201 login: Show Login in browser on credentials and reconnect
parent
75171da002
commit
47a9a2ae06
|
@ -2085,7 +2085,6 @@
|
||||||
"core.login.invalidurl": "scorm",
|
"core.login.invalidurl": "scorm",
|
||||||
"core.login.invalidvaluemax": "local_moodlemobileapp",
|
"core.login.invalidvaluemax": "local_moodlemobileapp",
|
||||||
"core.login.invalidvaluemin": "local_moodlemobileapp",
|
"core.login.invalidvaluemin": "local_moodlemobileapp",
|
||||||
"core.login.loggedoutssodescription": "local_moodlemobileapp",
|
|
||||||
"core.login.login": "moodle",
|
"core.login.login": "moodle",
|
||||||
"core.login.loginbutton": "local_moodlemobileapp",
|
"core.login.loginbutton": "local_moodlemobileapp",
|
||||||
"core.login.logininsiterequired": "local_moodlemobileapp",
|
"core.login.logininsiterequired": "local_moodlemobileapp",
|
||||||
|
@ -2124,7 +2123,6 @@
|
||||||
"core.login.recaptchaincorrect": "local_moodlemobileapp",
|
"core.login.recaptchaincorrect": "local_moodlemobileapp",
|
||||||
"core.login.reconnect": "local_moodlemobileapp",
|
"core.login.reconnect": "local_moodlemobileapp",
|
||||||
"core.login.reconnecthelp": "local_moodlemobileapp",
|
"core.login.reconnecthelp": "local_moodlemobileapp",
|
||||||
"core.login.reconnectssodescription": "local_moodlemobileapp",
|
|
||||||
"core.login.reconnectsupportsubject": "local_moodlemobileapp",
|
"core.login.reconnectsupportsubject": "local_moodlemobileapp",
|
||||||
"core.login.reconnecttosite": "local_moodlemobileapp",
|
"core.login.reconnecttosite": "local_moodlemobileapp",
|
||||||
"core.login.removeaccount": "local_moodlemobileapp",
|
"core.login.removeaccount": "local_moodlemobileapp",
|
||||||
|
@ -2231,6 +2229,7 @@
|
||||||
"core.openfile": "local_moodlemobileapp",
|
"core.openfile": "local_moodlemobileapp",
|
||||||
"core.openfullimage": "local_moodlemobileapp",
|
"core.openfullimage": "local_moodlemobileapp",
|
||||||
"core.openinbrowser": "local_moodlemobileapp",
|
"core.openinbrowser": "local_moodlemobileapp",
|
||||||
|
"core.openinbrowserdescription": "local_moodlemobileapp",
|
||||||
"core.openmodinbrowser": "local_moodlemobileapp",
|
"core.openmodinbrowser": "local_moodlemobileapp",
|
||||||
"core.opensecurityquestion": "local_moodlemobileapp",
|
"core.opensecurityquestion": "local_moodlemobileapp",
|
||||||
"core.opensettings": "local_moodlemobileapp",
|
"core.opensettings": "local_moodlemobileapp",
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
"invalidurl": "Invalid URL specified",
|
"invalidurl": "Invalid URL specified",
|
||||||
"invalidvaluemax": "The maximum value is {{$a}}",
|
"invalidvaluemax": "The maximum value is {{$a}}",
|
||||||
"invalidvaluemin": "The minimum value is {{$a}}",
|
"invalidvaluemin": "The minimum value is {{$a}}",
|
||||||
"loggedoutssodescription": "You have to authenticate again. You need to log in to the site in a browser window.",
|
|
||||||
"login": "Log in",
|
"login": "Log in",
|
||||||
"loginbutton": "Log in",
|
"loginbutton": "Log in",
|
||||||
"logininsiterequired": "You need to log in to the site in a browser window.",
|
"logininsiterequired": "You need to log in to the site in a browser window.",
|
||||||
|
@ -103,7 +102,6 @@
|
||||||
"recaptchaincorrect": "The security question answer is incorrect.",
|
"recaptchaincorrect": "The security question answer is incorrect.",
|
||||||
"reconnect": "Reconnect",
|
"reconnect": "Reconnect",
|
||||||
"reconnecthelp": "If you have problems reconnecting, try again later or contact your school or learning provider.",
|
"reconnecthelp": "If you have problems reconnecting, try again later or contact your school or learning provider.",
|
||||||
"reconnectssodescription": "Your session has expired. Please log in again in a browser window to continue.",
|
|
||||||
"reconnectsupportsubject": "Need help reconnecting",
|
"reconnectsupportsubject": "Need help reconnecting",
|
||||||
"reconnecttosite": "Reconnect to the site",
|
"reconnecttosite": "Reconnect to the site",
|
||||||
"removeaccount": "Remove account",
|
"removeaccount": "Remove account",
|
||||||
|
|
|
@ -99,6 +99,11 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.core-login-inbrowser {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:host-context(html.dark) {
|
:host-context(html.dark) {
|
||||||
|
|
|
@ -38,14 +38,14 @@
|
||||||
<div [innerHTML]="exceededAttemptsHTML" (click)="exceededAttemptsClicked($event)"></div>
|
<div [innerHTML]="exceededAttemptsHTML" (click)="exceededAttemptsClicked($event)"></div>
|
||||||
</core-login-exceeded-attempts>
|
</core-login-exceeded-attempts>
|
||||||
|
|
||||||
<form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm>
|
<form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm *ngIf="!isBrowserSSO">
|
||||||
<ion-item *ngIf="siteChecked && !isBrowserSSO">
|
<ion-item>
|
||||||
<ion-label class="sr-only">{{ 'core.login.username' | translate }}</ion-label>
|
<ion-label class="sr-only">{{ 'core.login.username' | translate }}</ion-label>
|
||||||
<ion-input type="text" name="username" placeholder="{{ 'core.login.username' | translate }}" formControlName="username"
|
<ion-input type="text" name="username" placeholder="{{ 'core.login.username' | translate }}" formControlName="username"
|
||||||
autocapitalize="none" autocorrect="off" autocomplete="username" enterkeyhint="next" required="true">
|
autocapitalize="none" autocorrect="off" autocomplete="username" enterkeyhint="next" required="true">
|
||||||
</ion-input>
|
</ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item *ngIf="siteChecked && !isBrowserSSO" class="ion-margin-bottom">
|
<ion-item class="ion-margin-bottom">
|
||||||
<ion-label class="sr-only">{{ 'core.login.password' | translate }}</ion-label>
|
<ion-label class="sr-only">{{ 'core.login.password' | translate }}</ion-label>
|
||||||
<core-show-password name="password">
|
<core-show-password name="password">
|
||||||
<ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}"
|
<ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}"
|
||||||
|
@ -53,19 +53,27 @@
|
||||||
</ion-input>
|
</ion-input>
|
||||||
</core-show-password>
|
</core-show-password>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-button expand="block" type="submit" [disabled]="siteChecked && !isBrowserSSO && !credForm.valid"
|
<ion-button expand="block" type="submit" [disabled]="!credForm.valid" class="ion-margin core-login-login-button ion-text-wrap">
|
||||||
class="ion-margin core-login-login-button ion-text-wrap">
|
|
||||||
{{ 'core.login.loginbutton' | translate }}
|
{{ 'core.login.loginbutton' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
||||||
<input type="submit" class="core-submit-hidden-enter" />
|
<input type="submit" class="core-submit-hidden-enter" />
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Forgotten password option. -->
|
<!-- Forgotten password option. -->
|
||||||
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear"
|
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear"
|
||||||
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
||||||
{{ 'core.login.forgotten' | translate }}
|
{{ 'core.login.forgotten' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<ng-container *ngIf="isBrowserSSO">
|
||||||
|
<ion-button expand="block" (click)="openBrowserSSO()" class="ion-margin core-login-login-button ion-text-wrap">
|
||||||
|
{{ 'core.login.loginbutton' | translate }}
|
||||||
|
<ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<p class="text-center core-login-inbrowser">{{ 'core.openinbrowserdescription' | translate }}</p>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [siteUrl]="siteUrl"></core-login-methods>
|
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [siteUrl]="siteUrl"></core-login-methods>
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { debounceTime } from 'rxjs/operators';
|
||||||
|
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreNetwork } from '@services/network';
|
import { CoreNetwork } from '@services/network';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSiteCheckResponse, CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
|
@ -48,7 +48,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
credForm!: FormGroup;
|
credForm!: FormGroup;
|
||||||
siteUrl!: string;
|
siteUrl!: string;
|
||||||
siteChecked = false;
|
|
||||||
siteName?: string;
|
siteName?: string;
|
||||||
logoUrl?: string;
|
logoUrl?: string;
|
||||||
authInstructions?: string;
|
authInstructions?: string;
|
||||||
|
@ -60,8 +59,9 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
loginAttempts = 0;
|
loginAttempts = 0;
|
||||||
supportConfig?: CoreUserSupportConfig;
|
supportConfig?: CoreUserSupportConfig;
|
||||||
exceededAttemptsHTML?: SafeHtml | string | null;
|
exceededAttemptsHTML?: SafeHtml | string | null;
|
||||||
|
siteConfig?: CoreSitePublicConfigResponse;
|
||||||
|
|
||||||
protected siteConfig?: CoreSitePublicConfigResponse;
|
protected siteCheck?: CoreSiteCheckResponse;
|
||||||
protected eventThrown = false;
|
protected eventThrown = false;
|
||||||
protected viewLeft = false;
|
protected viewLeft = false;
|
||||||
protected siteId?: string;
|
protected siteId?: string;
|
||||||
|
@ -77,10 +77,19 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
this.siteCheck = CoreNavigator.getRouteParam<CoreSiteCheckResponse>('siteCheck');
|
||||||
|
if (this.siteCheck?.siteUrl) {
|
||||||
|
this.siteUrl = this.siteCheck.siteUrl;
|
||||||
|
} else {
|
||||||
this.siteUrl = CoreNavigator.getRequiredRouteParam<string>('siteUrl');
|
this.siteUrl = CoreNavigator.getRequiredRouteParam<string>('siteUrl');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.siteCheck?.config) {
|
||||||
|
this.siteConfig = this.siteCheck.config;
|
||||||
|
}
|
||||||
|
|
||||||
this.siteName = CoreNavigator.getRouteParam('siteName');
|
this.siteName = CoreNavigator.getRouteParam('siteName');
|
||||||
this.logoUrl = !CoreConstants.CONFIG.forceLoginLogo && CoreNavigator.getRouteParam('logoUrl') || undefined;
|
this.logoUrl = !CoreConstants.CONFIG.forceLoginLogo && CoreNavigator.getRouteParam('logoUrl') || undefined;
|
||||||
this.siteConfig = CoreNavigator.getRouteParam<CoreSitePublicConfigResponse>('siteConfig');
|
|
||||||
this.urlToOpen = CoreNavigator.getRouteParam('urlToOpen');
|
this.urlToOpen = CoreNavigator.getRouteParam('urlToOpen');
|
||||||
this.supportConfig = this.siteConfig && new CoreUserGuestSupportConfig(this.siteConfig);
|
this.supportConfig = this.siteConfig && new CoreUserGuestSupportConfig(this.siteConfig);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -94,21 +103,9 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
password: ['', Validators.required],
|
password: ['', Validators.required],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.siteConfig) {
|
await this.checkSite(this.siteUrl);
|
||||||
this.treatSiteConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite();
|
if (CorePlatform.isIOS() && !this.isBrowserSSO) {
|
||||||
|
|
||||||
if (isSingleFixedSite || !this.siteConfig) {
|
|
||||||
// Fixed URL or not siteConfig retrieved from params, we need to check if it uses browser SSO login.
|
|
||||||
this.checkSite(this.siteUrl, true);
|
|
||||||
} else {
|
|
||||||
this.siteChecked = true;
|
|
||||||
this.pageLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CorePlatform.isIOS()) {
|
|
||||||
// Make iOS auto-fill work. The field that isn't focused doesn't get updated, do it manually.
|
// Make iOS auto-fill work. The field that isn't focused doesn't get updated, do it manually.
|
||||||
// Debounce it to prevent triggering this function too often when the user is typing.
|
// Debounce it to prevent triggering this function too often when the user is typing.
|
||||||
this.valueChangeSubscription = this.credForm.valueChanges.pipe(debounceTime(1000)).subscribe((changes) => {
|
this.valueChangeSubscription = this.credForm.valueChanges.pipe(debounceTime(1000)).subscribe((changes) => {
|
||||||
|
@ -147,46 +144,26 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
* This should be used only if a fixed URL is set, otherwise this check is already performed in CoreLoginSitePage.
|
* This should be used only if a fixed URL is set, otherwise this check is already performed in CoreLoginSitePage.
|
||||||
*
|
*
|
||||||
* @param siteUrl Site URL to check.
|
* @param siteUrl Site URL to check.
|
||||||
* @param onInit Whether the check site is done when initializing the page.
|
|
||||||
* @returns Promise resolved when done.
|
* @returns Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected async checkSite(siteUrl: string, onInit = false): Promise<void> {
|
protected async checkSite(siteUrl: string): Promise<void> {
|
||||||
this.pageLoaded = false;
|
this.pageLoaded = false;
|
||||||
|
|
||||||
// If the site is configured with http:// protocol we force that one, otherwise we use default mode.
|
// If the site is configured with http:// protocol we force that one, otherwise we use default mode.
|
||||||
const protocol = siteUrl.indexOf('http://') === 0 ? 'http://' : undefined;
|
const protocol = siteUrl.indexOf('http://') === 0 ? 'http://' : undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await CoreSites.checkSite(siteUrl, protocol);
|
if (!this.siteCheck) {
|
||||||
|
this.siteCheck = await CoreSites.checkSite(siteUrl, protocol);
|
||||||
this.siteChecked = true;
|
|
||||||
this.siteUrl = result.siteUrl;
|
|
||||||
|
|
||||||
this.siteConfig = result.config;
|
|
||||||
this.treatSiteConfig();
|
|
||||||
|
|
||||||
if (CoreLoginHelper.isSSOLoginNeeded(result.code)) {
|
|
||||||
// SSO. User needs to authenticate in a browser.
|
|
||||||
this.isBrowserSSO = true;
|
|
||||||
|
|
||||||
if (this.showScanQR && onInit) {
|
|
||||||
// Don't open browser automatically, let the user view the scan QR button.
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there's no SSO authentication ongoing and the view hasn't changed.
|
this.siteUrl = this.siteCheck.siteUrl;
|
||||||
if (!CoreApp.isSSOAuthenticationOngoing() && !this.viewLeft) {
|
this.siteConfig = this.siteCheck.config;
|
||||||
CoreLoginHelper.confirmAndOpenBrowserForSSOLogin(
|
|
||||||
result.siteUrl,
|
|
||||||
result.code,
|
|
||||||
result.service,
|
|
||||||
result.config?.launchurl,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.isBrowserSSO = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
await this.treatSiteConfig();
|
||||||
|
|
||||||
|
// Check if user needs to authenticate in a browser.
|
||||||
|
this.isBrowserSSO = CoreLoginHelper.isSSOLoginNeeded(this.siteCheck.code);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.showErrorModal(error);
|
CoreDomUtils.showErrorModal(error);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -198,7 +175,13 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
* Treat the site configuration (if it exists).
|
* Treat the site configuration (if it exists).
|
||||||
*/
|
*/
|
||||||
protected async treatSiteConfig(): Promise<void> {
|
protected async treatSiteConfig(): Promise<void> {
|
||||||
if (this.siteConfig) {
|
if (!this.siteConfig) {
|
||||||
|
this.authInstructions = undefined;
|
||||||
|
this.canSignup = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.siteName = this.siteConfig.sitename;
|
this.siteName = this.siteConfig.sitename;
|
||||||
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||||
this.authInstructions = this.siteConfig.authinstructions || Translate.instant('core.login.loginsteps');
|
this.authInstructions = this.siteConfig.authinstructions || Translate.instant('core.login.loginsteps');
|
||||||
|
@ -217,10 +200,29 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
this.eventThrown = true;
|
this.eventThrown = true;
|
||||||
CoreEvents.trigger(CoreEvents.LOGIN_SITE_CHECKED, { config: this.siteConfig });
|
CoreEvents.trigger(CoreEvents.LOGIN_SITE_CHECKED, { config: this.siteConfig });
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.authInstructions = undefined;
|
|
||||||
this.canSignup = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to authenticate the user using the browser.
|
||||||
|
*
|
||||||
|
* @param e Event.
|
||||||
|
* @returns Promise resolved when done.
|
||||||
|
*/
|
||||||
|
async openBrowserSSO(e?: Event): Promise<void> {
|
||||||
|
e?.preventDefault();
|
||||||
|
e?.stopPropagation();
|
||||||
|
|
||||||
|
// Check that there's no SSO authentication ongoing and the view hasn't changed.
|
||||||
|
if (CoreApp.isSSOAuthenticationOngoing() || this.viewLeft || !this.siteCheck) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreLoginHelper.confirmAndOpenBrowserForSSOLogin(
|
||||||
|
this.siteCheck.siteUrl,
|
||||||
|
this.siteCheck.code,
|
||||||
|
this.siteCheck.service,
|
||||||
|
this.siteCheck.config?.launchurl,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,10 +232,8 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
* @returns Promise resolved when done.
|
* @returns Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
async login(e?: Event): Promise<void> {
|
async login(e?: Event): Promise<void> {
|
||||||
if (e) {
|
e?.preventDefault();
|
||||||
e.preventDefault();
|
e?.stopPropagation();
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreApp.closeKeyboard();
|
CoreApp.closeKeyboard();
|
||||||
|
|
||||||
|
@ -242,18 +242,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
const username = this.credForm.value.username;
|
const username = this.credForm.value.username;
|
||||||
const password = this.credForm.value.password;
|
const password = this.credForm.value.password;
|
||||||
|
|
||||||
if (!this.siteChecked || this.isBrowserSSO) {
|
|
||||||
// Site wasn't checked (it failed) or a previous check determined it was SSO. Let's check again.
|
|
||||||
await this.checkSite(siteUrl);
|
|
||||||
|
|
||||||
if (!this.isBrowserSSO && this.siteChecked) {
|
|
||||||
// Site doesn't use browser SSO, throw app's login again.
|
|
||||||
return this.login();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!username) {
|
if (!username) {
|
||||||
CoreDomUtils.showErrorModal('core.login.usernamerequired', true);
|
CoreDomUtils.showErrorModal('core.login.usernamerequired', true);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,15 @@
|
||||||
<ion-content class="ion-padding" (keydown)="keyDown($event)" (keyup)="keyUp($event)">
|
<ion-content class="ion-padding" (keydown)="keyDown($event)" (keyup)="keyUp($event)">
|
||||||
<core-loading [hideUntil]="!showLoading">
|
<core-loading [hideUntil]="!showLoading">
|
||||||
<div class="list-item-limited-width">
|
<div class="list-item-limited-width">
|
||||||
|
<ion-card *ngIf="!isLoggedOut" class="core-danger-card core-login-reconnect-warning">
|
||||||
|
<ion-item>
|
||||||
|
<ion-icon name="fas-circle-exclamation" slot="start" aria-hidden="true"></ion-icon>
|
||||||
|
<ion-label>
|
||||||
|
<p>{{ 'core.lostconnection' | translate }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-card>
|
||||||
|
|
||||||
<div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showUserAvatar}">
|
<div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showUserAvatar}">
|
||||||
<div class="core-login-site-logo" *ngIf="!showUserAvatar">
|
<div class="core-login-site-logo" *ngIf="!showUserAvatar">
|
||||||
<!-- Show site logo or a default image. -->
|
<!-- Show site logo or a default image. -->
|
||||||
|
@ -39,15 +48,6 @@
|
||||||
<core-format-text [text]="siteInfo?.fullname" [filter]="false"></core-format-text>
|
<core-format-text [text]="siteInfo?.fullname" [filter]="false"></core-format-text>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ion-card *ngIf="!isLoggedOut" class="core-danger-card core-login-reconnect-warning">
|
|
||||||
<ion-item>
|
|
||||||
<ion-icon name="fas-circle-exclamation" slot="start" aria-hidden="true"></ion-icon>
|
|
||||||
<ion-label>
|
|
||||||
<p>{{ 'core.lostconnection' | translate }}</p>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
</ion-card>
|
|
||||||
|
|
||||||
<core-login-exceeded-attempts *ngIf="exceededAttemptsHTML && supportConfig && reconnectAttempts >= 3"
|
<core-login-exceeded-attempts *ngIf="exceededAttemptsHTML && supportConfig && reconnectAttempts >= 3"
|
||||||
[supportConfig]="supportConfig" [supportSubject]="'core.login.exceededloginattemptssupportsubject' | translate">
|
[supportConfig]="supportConfig" [supportSubject]="'core.login.exceededloginattemptssupportsubject' | translate">
|
||||||
<div [innerHTML]="exceededAttemptsHTML" (click)="exceededAttemptsClicked($event)"></div>
|
<div [innerHTML]="exceededAttemptsHTML" (click)="exceededAttemptsClicked($event)"></div>
|
||||||
|
@ -70,16 +70,19 @@
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- Forgotten password option. -->
|
<!-- Forgotten password option. -->
|
||||||
<ion-button *ngIf="showForgottenPassword && !isBrowserSSO" expand="block" fill="clear"
|
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear"
|
||||||
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
||||||
{{ 'core.login.forgotten' | translate }}
|
{{ 'core.login.forgotten' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<ion-button expand="block" *ngIf="isBrowserSSO" (click)="openBrowserSSO()"
|
<ng-container *ngIf="isBrowserSSO">
|
||||||
class="ion-margin core-login-login-button ion-text-wrap">
|
<ion-button expand="block" (click)="openBrowserSSO()" class="ion-margin core-login-login-button ion-text-wrap">
|
||||||
{{ 'core.login.loginbutton' | translate }}
|
{{ 'core.login.loginbutton' | translate }}
|
||||||
|
<ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
<p class="text-center core-login-inbrowser">{{ 'core.openinbrowserdescription' | translate }}</p>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<!-- Additional Login methods -->
|
<!-- Additional Login methods -->
|
||||||
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [reconnect]="true" [siteUrl]="siteUrl"
|
<core-login-methods *ngIf="siteConfig" [siteConfig]="siteConfig" [reconnect]="true" [siteUrl]="siteUrl"
|
||||||
|
|
|
@ -345,27 +345,18 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Process login to a site.
|
* Process login to a site.
|
||||||
*
|
*
|
||||||
* @param response Response obtained from the site check request.
|
* @param siteCheck Response obtained from the site check request.
|
||||||
* @param foundSite The site clicked, if any, from the found sites list.
|
* @param foundSite The site clicked, if any, from the found sites list.
|
||||||
*
|
*
|
||||||
* @returns Promise resolved after logging in.
|
* @returns Promise resolved after logging in.
|
||||||
*/
|
*/
|
||||||
protected async login(response: CoreSiteCheckResponse, foundSite?: CoreLoginSiteInfoExtended): Promise<void> {
|
protected async login(siteCheck: CoreSiteCheckResponse, foundSite?: CoreLoginSiteInfoExtended): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await CoreSites.checkApplication(response.config);
|
await CoreSites.checkApplication(siteCheck.config);
|
||||||
|
|
||||||
CoreForms.triggerFormSubmittedEvent(this.formElement, true);
|
CoreForms.triggerFormSubmittedEvent(this.formElement, true);
|
||||||
|
|
||||||
if (CoreLoginHelper.isSSOLoginNeeded(response.code)) {
|
const pageParams = { siteCheck };
|
||||||
// SSO. User needs to authenticate in a browser.
|
|
||||||
CoreLoginHelper.confirmAndOpenBrowserForSSOLogin(
|
|
||||||
response.siteUrl,
|
|
||||||
response.code,
|
|
||||||
response.service,
|
|
||||||
response.config?.launchurl,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const pageParams = { siteUrl: response.siteUrl, siteConfig: response.config };
|
|
||||||
if (foundSite && !this.fixedSites) {
|
if (foundSite && !this.fixedSites) {
|
||||||
pageParams['siteName'] = foundSite.name;
|
pageParams['siteName'] = foundSite.name;
|
||||||
pageParams['logoUrl'] = foundSite.imageurl;
|
pageParams['logoUrl'] = foundSite.imageurl;
|
||||||
|
@ -374,7 +365,6 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
CoreNavigator.navigate('/login/credentials', {
|
CoreNavigator.navigate('/login/credentials', {
|
||||||
params: pageParams,
|
params: pageParams,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
|
@ -573,17 +563,14 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if site uses SSO.
|
// Check if site uses SSO.
|
||||||
const response = await CoreSites.checkSite(siteUrl);
|
const siteCheck = await CoreSites.checkSite(siteUrl);
|
||||||
|
|
||||||
await CoreSites.checkApplication(response.config);
|
await CoreSites.checkApplication(siteCheck.config);
|
||||||
|
|
||||||
if (!CoreLoginHelper.isSSOLoginNeeded(response.code)) {
|
if (!CoreLoginHelper.isSSOLoginNeeded(siteCheck.code)) {
|
||||||
// No SSO, go to credentials page.
|
// No SSO, go to credentials page.
|
||||||
await CoreNavigator.navigate('/login/credentials', {
|
await CoreNavigator.navigate('/login/credentials', {
|
||||||
params: {
|
params: { siteCheck },
|
||||||
siteUrl: response.siteUrl,
|
|
||||||
siteConfig: response.config,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -924,9 +924,8 @@ export class CoreLoginHelperProvider {
|
||||||
async sessionExpired(data: CoreEventSessionExpiredData & CoreEventSiteData): Promise<void> {
|
async sessionExpired(data: CoreEventSessionExpiredData & CoreEventSiteData): Promise<void> {
|
||||||
const siteId = data?.siteId;
|
const siteId = data?.siteId;
|
||||||
const currentSite = CoreSites.getCurrentSite();
|
const currentSite = CoreSites.getCurrentSite();
|
||||||
const siteUrl = currentSite?.getURL();
|
|
||||||
|
|
||||||
if (!currentSite || !siteUrl) {
|
if (!currentSite) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,70 +946,6 @@ export class CoreLoginHelperProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check authentication method.
|
// Check authentication method.
|
||||||
const result = await CoreSites.checkSite(siteUrl);
|
|
||||||
|
|
||||||
if (this.isSSOLoginNeeded(result.code)) {
|
|
||||||
// SSO. User needs to authenticate in a browser. Check if we need to display a message.
|
|
||||||
if (!CoreApp.isSSOAuthenticationOngoing() && !this.waitingForBrowser) {
|
|
||||||
try {
|
|
||||||
if (this.shouldShowSSOConfirm(result.code)) {
|
|
||||||
await CoreDomUtils.showConfirm(Translate.instant('core.login.' +
|
|
||||||
(currentSite.isLoggedOut() ? 'loggedoutssodescription' : 'reconnectssodescription')));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.waitForBrowser();
|
|
||||||
|
|
||||||
this.openBrowserForSSOLogin(
|
|
||||||
result.siteUrl,
|
|
||||||
result.code,
|
|
||||||
result.service,
|
|
||||||
result.config?.launchurl,
|
|
||||||
redirectData,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
// User cancelled, logout him.
|
|
||||||
CoreSites.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (currentSite.isOAuth()) {
|
|
||||||
// User authenticated using an OAuth method. Check if it's still valid.
|
|
||||||
// @TODO Why disabledFeatures is not checked here?
|
|
||||||
const identityProviders = this.getValidIdentityProviders(result.config);
|
|
||||||
const providerToUse = identityProviders.find((provider) => {
|
|
||||||
const params = CoreUrlUtils.extractUrlParams(provider.url);
|
|
||||||
|
|
||||||
return Number(params.id) == currentSite.getOAuthId();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (providerToUse) {
|
|
||||||
if (!CoreApp.isSSOAuthenticationOngoing() && !this.waitingForBrowser) {
|
|
||||||
// Open browser to perform the OAuth.
|
|
||||||
const confirmMessage = Translate.instant('core.login.' +
|
|
||||||
(currentSite.isLoggedOut() ? 'loggedoutssodescription' : 'reconnectssodescription'));
|
|
||||||
|
|
||||||
try {
|
|
||||||
await CoreDomUtils.showConfirm(confirmMessage);
|
|
||||||
|
|
||||||
this.waitForBrowser();
|
|
||||||
CoreSites.unsetCurrentSite(); // Unset current site to make authentication work fine.
|
|
||||||
|
|
||||||
this.openBrowserForOAuthLogin(
|
|
||||||
siteUrl,
|
|
||||||
providerToUse,
|
|
||||||
result.config?.launchurl,
|
|
||||||
redirectData,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
// User cancelled, logout him.
|
|
||||||
CoreSites.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const info = currentSite.getInfo();
|
const info = currentSite.getInfo();
|
||||||
if (info !== undefined && info.username !== undefined) {
|
if (info !== undefined && info.username !== undefined) {
|
||||||
// If current page is already reconnect, stop.
|
// If current page is already reconnect, stop.
|
||||||
|
@ -1026,7 +961,6 @@ export class CoreLoginHelperProvider {
|
||||||
reset: true,
|
reset: true,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Error checking site.
|
// Error checking site.
|
||||||
if (currentSite.isLoggedOut()) {
|
if (currentSite.isLoggedOut()) {
|
||||||
|
|
|
@ -235,6 +235,7 @@
|
||||||
"openfile": "Open file",
|
"openfile": "Open file",
|
||||||
"openfullimage": "Click here to display the full size image",
|
"openfullimage": "Click here to display the full size image",
|
||||||
"openinbrowser": "Open in browser",
|
"openinbrowser": "Open in browser",
|
||||||
|
"openinbrowserdescription": "You will be taken to a web browser",
|
||||||
"openmodinbrowser": "Open {{$a}} in browser",
|
"openmodinbrowser": "Open {{$a}} in browser",
|
||||||
"opensecurityquestion": "Open security question",
|
"opensecurityquestion": "Open security question",
|
||||||
"opensettings": "Open settings",
|
"opensettings": "Open settings",
|
||||||
|
|
|
@ -386,16 +386,15 @@ export class CoreCustomURLSchemesProvider {
|
||||||
* Go to page to add a site, or open a browser if SSO.
|
* Go to page to add a site, or open a browser if SSO.
|
||||||
*
|
*
|
||||||
* @param data URL data.
|
* @param data URL data.
|
||||||
* @param checkResponse Result of checkSite.
|
* @param siteCheck Result of checkSite.
|
||||||
* @returns Promise resolved when done.
|
* @returns Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected async goToAddSite(data: CoreCustomURLSchemesParams, checkResponse: CoreSiteCheckResponse): Promise<void> {
|
protected async goToAddSite(data: CoreCustomURLSchemesParams, siteCheck: CoreSiteCheckResponse): Promise<void> {
|
||||||
const ssoNeeded = CoreLoginHelper.isSSOLoginNeeded(checkResponse.code);
|
const ssoNeeded = CoreLoginHelper.isSSOLoginNeeded(siteCheck.code);
|
||||||
const pageParams = {
|
const pageParams = {
|
||||||
siteUrl: checkResponse.siteUrl,
|
|
||||||
username: data.username,
|
username: data.username,
|
||||||
urlToOpen: data.redirect,
|
urlToOpen: data.redirect,
|
||||||
siteConfig: checkResponse.config,
|
siteCheck,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (CoreSites.isLoggedIn()) {
|
if (CoreSites.isLoggedIn()) {
|
||||||
|
@ -416,10 +415,10 @@ export class CoreCustomURLSchemesProvider {
|
||||||
|
|
||||||
if (ssoNeeded) {
|
if (ssoNeeded) {
|
||||||
CoreLoginHelper.confirmAndOpenBrowserForSSOLogin(
|
CoreLoginHelper.confirmAndOpenBrowserForSSOLogin(
|
||||||
checkResponse.siteUrl,
|
siteCheck.siteUrl,
|
||||||
checkResponse.code,
|
siteCheck.code,
|
||||||
checkResponse.service,
|
siteCheck.service,
|
||||||
checkResponse.config?.launchurl,
|
siteCheck.config?.launchurl,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await CoreNavigator.navigateToLoginCredentials(pageParams);
|
await CoreNavigator.navigateToLoginCredentials(pageParams);
|
||||||
|
|
Loading…
Reference in New Issue