From 3cfd550b58f05bcdfcbe2369e1afd7d5dab8189d Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 15 Nov 2024 12:50:13 +0100 Subject: [PATCH 1/2] MOBILE-4693 error: Also display accordion for debug info in error modals --- src/addons/mod/forum/pages/search/search.ts | 6 +-- src/core/classes/errors/error.ts | 14 ++++- src/core/classes/errors/siteerror.ts | 11 ++-- src/core/features/login/pages/site/site.ts | 8 +-- .../features/login/services/login-helper.ts | 10 ++-- .../pages/global-search/global-search.ts | 6 +-- src/core/services/error-accordion.ts | 12 ++--- src/core/services/error-helper.ts | 36 ++++++++++++- src/core/services/sites.ts | 7 ++- src/core/services/utils/dom.ts | 52 +++++++------------ 10 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/addons/mod/forum/pages/search/search.ts b/src/addons/mod/forum/pages/search/search.ts index ddf2e48c5..d95f78a12 100644 --- a/src/addons/mod/forum/pages/search/search.ts +++ b/src/addons/mod/forum/pages/search/search.ts @@ -38,7 +38,7 @@ import { CorePromiseUtils } from '@singletons/promise-utils'; }) export class AddonModForumSearchPage implements OnInit { - loadMoreError: string | null = null; + loadMoreError = false; searchBanner: string | null = null; resultsSource = new CoreSearchGlobalSearchResultsSource('', {}); forum?: AddonModForumData; @@ -128,7 +128,7 @@ export class AddonModForumSearchPage implements OnInit { * Clear search results. */ clearSearch(): void { - this.loadMoreError = null; + this.loadMoreError = false; this.resultsSource.setQuery(''); this.resultsSource.reset(); @@ -152,7 +152,7 @@ export class AddonModForumSearchPage implements OnInit { try { await this.resultsSource?.load(); } catch (error) { - this.loadMoreError = CoreDomUtils.getErrorMessage(error); + this.loadMoreError = true; } finally { complete(); } diff --git a/src/core/classes/errors/error.ts b/src/core/classes/errors/error.ts index cccd985ba..44ed1a7d2 100644 --- a/src/core/classes/errors/error.ts +++ b/src/core/classes/errors/error.ts @@ -24,14 +24,26 @@ import { CoreErrorObject } from '@services/error-helper'; */ export class CoreError extends Error { - constructor(message?: string) { + debug?: CoreErrorDebug; + + constructor(message?: string, debug?: CoreErrorDebug) { super(message); // Fix prototype chain: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget this.name = new.target.name; Object.setPrototypeOf(this, new.target.prototype); + + this.debug = debug; } } +/** + * Debug information of the error. + */ +export type CoreErrorDebug = { + code?: string; // Technical error code useful for technical assistance. + details: string; // Technical error details useful for technical assistance. +}; + export type CoreAnyError = string | CoreError | CoreErrorObject | null | undefined; diff --git a/src/core/classes/errors/siteerror.ts b/src/core/classes/errors/siteerror.ts index 9e1f2f569..62dffed76 100644 --- a/src/core/classes/errors/siteerror.ts +++ b/src/core/classes/errors/siteerror.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { CoreError } from '@classes/errors/error'; +import { CoreError, CoreErrorDebug } from '@classes/errors/error'; import { CoreUserSupportConfig } from '@features/user/classes/support/support-config'; /** @@ -20,7 +20,7 @@ import { CoreUserSupportConfig } from '@features/user/classes/support/support-co */ export class CoreSiteError extends CoreError { - debug?: CoreSiteErrorDebug; + debug?: CoreErrorDebug; supportConfig?: CoreUserSupportConfig; constructor(options: CoreSiteErrorOptions) { @@ -43,16 +43,11 @@ export class CoreSiteError extends CoreError { } -export type CoreSiteErrorDebug = { - code: string; // Technical error code useful for technical assistance. - details: string; // Technical error details useful for technical assistance. -}; - export type CoreSiteErrorOptions = { message: string; // Debugging information. - debug?: CoreSiteErrorDebug; + debug?: CoreErrorDebug; // Configuration to use to contact site support. If this attribute is present, it means // that the error warrants contacting support. diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index 02d9cb4b5..02df4ee1d 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -25,7 +25,7 @@ import { CoreLoginSiteFinderSettings, CoreLoginSiteSelectorListMethod, } from '@features/login/services/login-helper'; -import { CoreError } from '@classes/errors/error'; +import { CoreError, CoreErrorDebug } from '@classes/errors/error'; import { CoreConstants } from '@/core/constants'; import { Translate } from '@singletons'; import { CoreUrl, CoreUrlPartNames } from '@singletons/url'; @@ -34,7 +34,7 @@ import { CoreCustomURLSchemes, CoreCustomURLSchemesHandleError } from '@services import { CoreErrorHelper } from '@services/error-helper'; import { CoreForms } from '@singletons/form'; import { AlertButton } from '@ionic/core'; -import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror'; +import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreUserSupport } from '@features/user/services/support'; import { CoreErrorAccordion } from '@services/error-accordion'; import { CoreUserSupportConfig } from '@features/user/classes/support/support-config'; @@ -419,7 +419,7 @@ export class CoreLoginSitePage implements OnInit { */ protected async showLoginIssue(url: string, error: CoreError): Promise { let errorMessage = CoreDomUtils.getErrorMessage(error); - let debug: CoreSiteErrorDebug | undefined; + let debug: CoreErrorDebug | undefined; let errorTitle: string | undefined; let site: CoreUnauthenticatedSite | undefined; let supportConfig: CoreUserSupportConfig | undefined; @@ -480,7 +480,7 @@ export class CoreLoginSitePage implements OnInit { const containerElement = alertElement.querySelector('.core-error-accordion-container'); if (containerElement) { - await CoreErrorAccordion.render(containerElement, debug.code, debug.details); + await CoreErrorAccordion.render(containerElement, debug.details, debug.code); } } } diff --git a/src/core/features/login/services/login-helper.ts b/src/core/features/login/services/login-helper.ts index 5b148bdd2..9be527c82 100644 --- a/src/core/features/login/services/login-helper.ts +++ b/src/core/features/login/services/login-helper.ts @@ -26,7 +26,7 @@ import { CoreText } from '@singletons/text'; import { CoreObject } from '@singletons/object'; import { CoreConstants } from '@/core/constants'; import { CoreSite } from '@classes/sites/site'; -import { CoreError } from '@classes/errors/error'; +import { CoreError, CoreErrorDebug } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; import { DomSanitizer, makeSingleton, Translate } from '@singletons'; import { CoreLogger } from '@singletons/logger'; @@ -57,7 +57,7 @@ import { IDENTITY_PROVIDER_FEATURE_NAME_PREFIX, } from '../constants'; import { LazyRoutesModule } from '@/app/app-routing.module'; -import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror'; +import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreQRScan } from '@services/qrscan'; import { CoreLoadings } from '@services/loadings'; import { CoreErrorHelper } from '@services/error-helper'; @@ -949,7 +949,7 @@ export class CoreLoginHelperProvider { * @param site Site instance. * @param debug Error debug information. */ - async showAppUnsupportedModal(siteUrl: string, site?: CoreUnauthenticatedSite, debug?: CoreSiteErrorDebug): Promise { + async showAppUnsupportedModal(siteUrl: string, site?: CoreUnauthenticatedSite, debug?: CoreErrorDebug): Promise { const siteName = await site?.getSiteName() ?? siteUrl; await CoreDomUtils.showAlertWithOptions({ @@ -974,7 +974,7 @@ export class CoreLoginHelperProvider { * @param siteUrl Site url. * @param debug Error debug information. */ - async openInBrowserFallback(siteUrl: string, debug?: CoreSiteErrorDebug): Promise { + async openInBrowserFallback(siteUrl: string, debug?: CoreErrorDebug): Promise { CoreEvents.trigger(APP_UNSUPPORTED_CHURN, { siteUrl, debug }); await CoreOpener.openInBrowser(siteUrl, { showBrowserWarning: false }); @@ -1677,7 +1677,7 @@ declare module '@singletons/events' { */ export interface CoreEventsData { [ALWAYS_SHOW_LOGIN_FORM_CHANGED]: { value: number }; - [APP_UNSUPPORTED_CHURN]: { siteUrl: string; debug?: CoreSiteErrorDebug }; + [APP_UNSUPPORTED_CHURN]: { siteUrl: string; debug?: CoreErrorDebug }; } } diff --git a/src/core/features/search/pages/global-search/global-search.ts b/src/core/features/search/pages/global-search/global-search.ts index 9e7091f8c..69f3205e9 100644 --- a/src/core/features/search/pages/global-search/global-search.ts +++ b/src/core/features/search/pages/global-search/global-search.ts @@ -39,7 +39,7 @@ import { CorePromiseUtils } from '@singletons/promise-utils'; export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewInit { courseId: number | null = null; - loadMoreError: string | null = null; + loadMoreError = false; searchBanner: string | null = null; resultsSource = new CoreSearchGlobalSearchResultsSource('', {}); private filtersObserver?: CoreEventObserver; @@ -128,7 +128,7 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI * Clear search results. */ clearSearch(): void { - this.loadMoreError = null; + this.loadMoreError = false; this.resultsSource.setQuery(''); this.resultsSource.reset(); @@ -172,7 +172,7 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI try { await this.resultsSource?.load(); } catch (error) { - this.loadMoreError = CoreDomUtils.getErrorMessage(error); + this.loadMoreError = true; } finally { complete(); } diff --git a/src/core/services/error-accordion.ts b/src/core/services/error-accordion.ts index b87a46aba..6394422e9 100644 --- a/src/core/services/error-accordion.ts +++ b/src/core/services/error-accordion.ts @@ -38,11 +38,11 @@ export class CoreErrorAccordionService { * Render an instance of the component into an HTML string. * * @param element Root element. - * @param errorCode Error code. * @param errorDetails Error details. + * @param errorCode Error code. */ - async render(element: Element, errorCode: string, errorDetails: string): Promise { - const html = this.html(errorCode, errorDetails); + async render(element: Element, errorDetails: string, errorCode?: string): Promise { + const html = this.html(errorDetails, errorCode); element.innerHTML = html; @@ -56,15 +56,15 @@ export class CoreErrorAccordionService { * @param errorDetails Error details. * @returns HTML. */ - private html(errorCode: string, errorDetails: string): string { + private html(errorDetails: string, errorCode?: string): string { const contentId = CoreForms.uniqueId('error-accordion-content'); - const errorCodeLabel = Translate.instant('core.errorcode', { errorCode }); + const errorCodeLabel = errorCode ? Translate.instant('core.errorcode', { errorCode }) : undefined; const hideDetailsLabel = Translate.instant('core.errordetailshide'); const showDetailsLabel = Translate.instant('core.errordetailsshow'); return `
-

${errorCodeLabel}

+ ${errorCodeLabel ? `

${errorCodeLabel}

` : ''} diff --git a/src/core/services/error-helper.ts b/src/core/services/error-helper.ts index 3d82a7672..8de5307b3 100644 --- a/src/core/services/error-helper.ts +++ b/src/core/services/error-helper.ts @@ -13,10 +13,11 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreAnyError, CoreError } from '@classes/errors/error'; +import { CoreAnyError, CoreError, CoreErrorDebug } from '@classes/errors/error'; import { makeSingleton, Translate } from '@singletons'; import { AlertButton } from '@ionic/angular'; import { CoreWSError } from '@classes/errors/wserror'; +import { CoreText } from '@singletons/text'; /** * Provider to provide some helper functions regarding files and packages. @@ -130,6 +131,39 @@ export class CoreErrorHelperService { return builtMessage; } + /** + * Get the debug info from an error object. + * + * @param error Error. + * @returns Error debug info, undefined if not found. + */ + getDebugInfoFromError(error?: CoreAnyError): CoreErrorDebug | undefined { + if (!error || typeof error === 'string') { + return; + } + + if ('debug' in error) { + return error.debug; + } + + // Escape the HTML of debug info so it is displayed as it is in the view. + const debugMessages: string[] = []; + if ('debuginfo' in error && error.debuginfo) { + debugMessages.push(CoreText.escapeHTML(error.debuginfo, false)); + } + if ('backtrace' in error && error.backtrace) { + debugMessages.push(CoreText.replaceNewLines( + CoreText.escapeHTML(error.backtrace, false), + '
', + )); + } + + const debugMessage = debugMessages.join('

'); + if (debugMessage) { + return { details: debugMessage }; + } + } + /** * Get the error message from an error object. * diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index b402491b3..0a6d676d5 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -27,7 +27,7 @@ import { CoreSiteConfig, } from '@classes/sites/site'; import { SQLiteDB, SQLiteDBRecordValues, SQLiteDBTableSchema } from '@classes/sqlitedb'; -import { CoreError } from '@classes/errors/error'; +import { CoreError, CoreErrorDebug } from '@classes/errors/error'; import { CoreLoginError, CoreLoginErrorOptions } from '@classes/errors/loginerror'; import { makeSingleton, Translate, Http } from '@singletons'; import { CoreLogger } from '@singletons/logger'; @@ -64,7 +64,6 @@ import { CoreSiteInfo, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { firstValueFrom } from 'rxjs'; import { CoreHTMLClasses } from '@singletons/html-classes'; -import { CoreSiteErrorDebug } from '@classes/errors/siteerror'; import { CoreErrorHelper } from './error-helper'; import { CoreQueueRunner } from '@classes/queue-runner'; import { CoreAppDB } from './app-db'; @@ -459,7 +458,7 @@ export class CoreSitesProvider { critical: true, title: Translate.instant('core.cannotconnect'), message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }), - supportConfig: error.supportConfig, + supportConfig: 'supportConfig' in error ? error.supportConfig : undefined, debug: error.debug, }; @@ -688,7 +687,7 @@ export class CoreSitesProvider { * @returns A promise rejected with the error info. */ protected async treatInvalidAppVersion(result: number, siteId?: string): Promise { - let debug: CoreSiteErrorDebug | undefined; + let debug: CoreErrorDebug | undefined; let errorKey: string | undefined; let translateParams = {}; diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 2881e40c6..bf759aa79 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -449,17 +449,6 @@ export class CoreDomUtilsProvider { if (typeof error === 'object') { if (this.debugDisplay) { - // Get the debug info. Escape the HTML so it is displayed as it is in the view. - if ('debuginfo' in error && error.debuginfo) { - extraInfo = '

' + CoreText.escapeHTML(error.debuginfo, false); - } - if ('backtrace' in error && error.backtrace) { - extraInfo += '

' + CoreText.replaceNewLines( - CoreText.escapeHTML(error.backtrace, false), - '
', - ); - } - // eslint-disable-next-line no-console console.error(error); } @@ -1061,36 +1050,35 @@ export class CoreDomUtilsProvider { if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') { alertOptions.buttons = error.buttons; - } else if (error instanceof CoreSiteError) { - if (error.debug) { - alertOptions.message = `

${alertOptions.message}

`; - } - - const supportConfig = error.supportConfig; - - alertOptions.buttons = [Translate.instant('core.ok')]; - - if (supportConfig?.canContactSupport()) { - alertOptions.buttons.push({ - text: Translate.instant('core.contactsupport'), - handler: () => CoreUserSupport.contact({ - supportConfig, - subject: alertOptions.header, - message: `${error.debug?.code}\n\n${error.debug?.details}`, - }), - }); - } } else { alertOptions.buttons = [Translate.instant('core.ok')]; } + // For site errors, always show debug info. + const showDebugInfo = this.debugDisplay || error instanceof CoreSiteError; + const debugInfo = showDebugInfo && CoreErrorHelper.getDebugInfoFromError(error); + if (debugInfo) { + alertOptions.message = `

${message}

`; + } + + if (error instanceof CoreSiteError && error.supportConfig?.canContactSupport()) { + alertOptions.buttons.push({ + text: Translate.instant('core.contactsupport'), + handler: () => CoreUserSupport.contact({ + supportConfig: error.supportConfig, + subject: alertOptions.header, + message: `${error.debug?.code}\n\n${error.debug?.details}`, + }), + }); + } + const alertElement = await this.showAlertWithOptions(alertOptions, autocloseTime); - if (error instanceof CoreSiteError && error.debug) { + if (debugInfo) { const containerElement = alertElement.querySelector('.core-error-accordion-container'); if (containerElement) { - await CoreErrorAccordion.render(containerElement, error.debug.code, error.debug.details); + await CoreErrorAccordion.render(containerElement, debugInfo.details, debugInfo.code); } } From c14646b7e2ff9292f1bfc01790ee483636d89c0b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 18 Nov 2024 08:17:09 +0100 Subject: [PATCH 2/2] MOBILE-4693 core: Add more debugging to invalid site errors --- .../login/pages/credentials/credentials.ts | 2 +- src/core/features/login/pages/site/site.ts | 6 +- src/core/services/sites.ts | 8 ++- src/core/services/urlschemes.ts | 55 +++++++++++++++---- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/core/features/login/pages/credentials/credentials.ts b/src/core/features/login/pages/credentials/credentials.ts index b8638cab5..9ee00529a 100644 --- a/src/core/features/login/pages/credentials/credentials.ts +++ b/src/core/features/login/pages/credentials/credentials.ts @@ -181,7 +181,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy { try { if (!this.siteCheck) { - this.siteCheck = await CoreSites.checkSite(this.site.siteUrl, protocol); + this.siteCheck = await CoreSites.checkSite(this.site.siteUrl, protocol, 'Credentials page'); this.siteCheck.config && this.site.setPublicConfig(this.siteCheck.config); } diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index 02df4ee1d..a454bd12e 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -333,14 +333,14 @@ export class CoreLoginSitePage implements OnInit { let checkResult: CoreSiteCheckResponse; try { - checkResult = await CoreSites.checkSite(url); + checkResult = await CoreSites.checkSite(url, undefined, 'Site URL page'); } catch (error) { // Attempt guessing the domain if the initial check failed const domain = CoreUrl.guessMoodleDomain(url); if (domain && domain != url) { try { - checkResult = await CoreSites.checkSite(domain); + checkResult = await CoreSites.checkSite(domain, undefined, 'Site URL page'); } catch (secondError) { // Try to use the first error. modal.dismiss(); @@ -608,7 +608,7 @@ export class CoreLoginSitePage implements OnInit { try { // Check if site uses SSO. - const siteCheck = await CoreSites.checkSite(siteUrl); + const siteCheck = await CoreSites.checkSite(siteUrl, undefined, 'Site URL page'); await CoreSites.checkApplication(siteCheck.config); diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index 0a6d676d5..1dfdd725e 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -286,14 +286,18 @@ export class CoreSitesProvider { * * @param siteUrl URL of the site to check. * @param protocol Protocol to use first. + * @param origin Origin of this check site call. * @returns A promise resolved when the site is checked. */ - async checkSite(siteUrl: string, protocol: string = 'https://'): Promise { + async checkSite(siteUrl: string, protocol: string = 'https://', origin = 'unknown'): Promise { // The formatURL function adds the protocol if is missing. siteUrl = CoreUrl.formatURL(siteUrl); if (!CoreUrl.isHttpURL(siteUrl)) { - throw new CoreError(Translate.instant('core.login.invalidsite')); + throw new CoreError(Translate.instant('core.login.invalidsite'), { + code: 'invalidprotocol', + details: `URL contains an invalid protocol when checking site.

Origin: ${origin}.

URL: ${siteUrl}.`, + }); } if (!CoreNetwork.isOnline()) { diff --git a/src/core/services/urlschemes.ts b/src/core/services/urlschemes.ts index f7131a788..65cd87bc4 100644 --- a/src/core/services/urlschemes.ts +++ b/src/core/services/urlschemes.ts @@ -44,6 +44,22 @@ export class CoreCustomURLSchemesProvider { this.logger = CoreLogger.getInstance('CoreCustomURLSchemesProvider'); } + /** + * Create a CoreCustomURLSchemesHandleError to be used when treating a URL that doesn't have a valid scheme. + * + * @param url URL that caused the error. + * @param data Data obtained from the URL (if any). + * @returns Error. + */ + protected createInvalidSchemeError(url: string, data?: CoreCustomURLSchemesParams): CoreCustomURLSchemesHandleError { + const defaultError = new CoreError(Translate.instant('core.login.invalidsite'), { + code: 'invalidurlscheme', + details: `Error when treating a URL scheme, it seems the URL is not valid.

URL: ${url}`, + }); + + return new CoreCustomURLSchemesHandleError(defaultError, data); + } + /** * Given some data of a custom URL with a token, create a site if it needs to be created. * @@ -62,7 +78,7 @@ export class CoreCustomURLSchemesProvider { if (!data.siteUrl.match(/^https?:\/\//)) { // URL doesn't have a protocol and it's required to be able to create the site. Check which one to use. - const result = await CoreSites.checkSite(data.siteUrl); + const result = await CoreSites.checkSite(data.siteUrl, undefined, 'URL scheme create site'); data.siteUrl = result.siteUrl; @@ -90,7 +106,13 @@ export class CoreCustomURLSchemesProvider { */ async handleCustomURL(url: string): Promise { if (!this.isCustomURL(url)) { - throw new CoreCustomURLSchemesHandleError(null); + throw this.createInvalidSchemeError(url); + } + + // Check if there is nothing valid after the URL scheme. + const urlWithoutScheme = this.removeCustomURLScheme(url).trim(); + if (!urlWithoutScheme || urlWithoutScheme.match(/^\/?(#.*)?\/?$/)) { + throw this.createInvalidSchemeError(url); } /* First check that this URL hasn't been treated a few seconds ago. The function that handles custom URL schemes already @@ -202,7 +224,7 @@ export class CoreCustomURLSchemesProvider { } else { // Site not stored. Try to add the site. - const result = await CoreSites.checkSite(data.siteUrl); + const result = await CoreSites.checkSite(data.siteUrl, undefined, `URL scheme redirect: ${url}`); // Site exists. We'll allow to add it. modal.dismiss(); // Dismiss modal so it doesn't collide with confirms. @@ -211,7 +233,12 @@ export class CoreCustomURLSchemesProvider { } } catch (error) { - throw new CoreCustomURLSchemesHandleError(error, data); + if (!error || !CoreErrorHelper.getErrorMessageFromError(error)) { + // Use a default error. + this.createInvalidSchemeError(url, data); + } else { + throw new CoreCustomURLSchemesHandleError(error, data); + } } finally { modal.dismiss(); @@ -230,7 +257,7 @@ export class CoreCustomURLSchemesProvider { */ protected async getCustomURLData(url: string): Promise { if (!this.isCustomURL(url)) { - throw new CoreCustomURLSchemesHandleError(null); + throw this.createInvalidSchemeError(url); } // App opened using custom URL scheme. @@ -283,7 +310,7 @@ export class CoreCustomURLSchemesProvider { */ protected async getCustomURLLinkData(url: string): Promise { if (!this.isCustomURLLink(url)) { - throw new CoreCustomURLSchemesHandleError(null); + throw this.createInvalidSchemeError(url); } // App opened using custom URL scheme. @@ -345,7 +372,7 @@ export class CoreCustomURLSchemesProvider { */ protected async getCustomURLTokenData(url: string): Promise { if (!this.isCustomURLToken(url)) { - throw new CoreCustomURLSchemesHandleError(null); + throw this.createInvalidSchemeError(url); } if (CoreSSO.isSSOAuthenticationOngoing()) { @@ -358,6 +385,7 @@ export class CoreCustomURLSchemesProvider { this.logger.debug('App launched by URL with an SSO'); // Delete the sso scheme from the URL. + const originalUrl = url; url = this.removeCustomURLTokenScheme(url); // Some platforms like Windows add a slash at the end. Remove it. @@ -371,7 +399,11 @@ export class CoreCustomURLSchemesProvider { // Error decoding the parameter. this.logger.error('Error decoding parameter received for login SSO'); - throw new CoreCustomURLSchemesHandleError(null); + throw new CoreCustomURLSchemesHandleError(new CoreError(Translate.instant('core.login.invalidsite'), { + code: 'errordecodingparameter', + details: `Error when trying to decode base 64 string.

URL: ${originalUrl}

Text to decode: ${url}` + + `

Error: ${CoreErrorHelper.getErrorMessageFromError(err)}`, + })); } const data: CoreCustomURLSchemesParams = await CoreLoginHelper.validateBrowserSSOLogin(url); @@ -491,14 +523,17 @@ export class CoreCustomURLSchemesProvider { * @param error Error data. */ treatHandleCustomURLError(error: CoreCustomURLSchemesHandleError): void { - if (error.error == 'Duplicated') { + if (error.error === 'Duplicated') { // Duplicated request } else if (CoreWSError.isWebServiceError(error.error) && error.data && error.data.isSSOToken) { // An error occurred, display the error and logout the user. CoreLoginHelper.treatUserTokenError(error.data.siteUrl, error.error); CoreSites.logout(); } else { - CoreDomUtils.showErrorModalDefault(error.error, Translate.instant('core.login.invalidsite')); + CoreDomUtils.showErrorModal(error.error ?? new CoreError(Translate.instant('core.login.invalidsite'), { + code: 'unknownerror', + details: 'Unknown error when treating a URL scheme.', + })); } }