From e9506a106fd02dbd169202bccf179f300718d5c2 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 27 Aug 2021 10:14:49 +0200 Subject: [PATCH] MOBILE-3846 core: Don't allow using sites not present in config --- scripts/langindex.json | 1 + src/core/classes/errors/errors.ts | 2 + .../errors/errorwithtitle.ts} | 18 +++++- src/core/features/login/lang.json | 1 + src/core/features/login/pages/sites/sites.ts | 4 ++ .../features/login/services/login-helper.ts | 6 +- .../initializers/consume-storage-redirect.ts | 5 +- src/core/initializers/initialize-services.ts | 2 + src/core/initializers/restore-session.ts | 3 + src/core/services/sites.ts | 22 ++++++- src/core/services/update-manager.ts | 59 ++++++++++++++++++- src/core/services/utils/dom.ts | 3 + 12 files changed, 116 insertions(+), 10 deletions(-) rename src/core/{initializers/load-update-manager.ts => classes/errors/errorwithtitle.ts} (57%) diff --git a/scripts/langindex.json b/scripts/langindex.json index df750b6bf..135298c36 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1902,6 +1902,7 @@ "core.login.sitebadgedescription": "local_moodlemobileapp", "core.login.sitehasredirect": "local_moodlemobileapp", "core.login.siteinmaintenance": "local_moodlemobileapp", + "core.login.sitenotallowed": "local_moodlemobileapp", "core.login.sitepolicynotagreederror": "local_moodlemobileapp", "core.login.siteurl": "local_moodlemobileapp", "core.login.siteurlrequired": "local_moodlemobileapp", diff --git a/src/core/classes/errors/errors.ts b/src/core/classes/errors/errors.ts index 3f0923075..94b34a72f 100644 --- a/src/core/classes/errors/errors.ts +++ b/src/core/classes/errors/errors.ts @@ -23,6 +23,7 @@ import { CoreAjaxWSError } from './ajaxwserror'; import { CoreCaptureError } from './captureerror'; import { CoreNetworkError } from './network-error'; import { CoreSiteError } from './siteerror'; +import { CoreErrorWithTitle } from './errorwithtitle'; export const CORE_ERRORS_CLASSES: Type[] = [ CoreAjaxError, @@ -34,4 +35,5 @@ export const CORE_ERRORS_CLASSES: Type[] = [ CoreSilentError, CoreSiteError, CoreWSError, + CoreErrorWithTitle, ]; diff --git a/src/core/initializers/load-update-manager.ts b/src/core/classes/errors/errorwithtitle.ts similarity index 57% rename from src/core/initializers/load-update-manager.ts rename to src/core/classes/errors/errorwithtitle.ts index fdfc913f9..0ff83d3b7 100644 --- a/src/core/initializers/load-update-manager.ts +++ b/src/core/classes/errors/errorwithtitle.ts @@ -12,8 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { CoreUpdateManager } from '@services/update-manager'; +import { CoreError } from './error'; + +/** + * Error with an explicit title describing the problem (instead of just "Error" or a generic message). + * This title should be used to communicate the problem with users, and if it's undefined it should be omitted. + */ +export class CoreErrorWithTitle extends CoreError { + + title?: string; + + constructor(message?: string, title?: string) { + super(message); + + this.title = title; + } -export default async function(): Promise { - await CoreUpdateManager.load(); } diff --git a/src/core/features/login/lang.json b/src/core/features/login/lang.json index ecf4be149..74ae914e8 100644 --- a/src/core/features/login/lang.json +++ b/src/core/features/login/lang.json @@ -108,6 +108,7 @@ "sitebadgedescription": "There are {{count}} unread notifications.", "sitehasredirect": "Your site contains at least one HTTP redirect. The app cannot follow redirects, this could be the issue that's preventing the app from connecting to your site.", "siteinmaintenance": "Your site is in maintenance mode", + "sitenotallowed": "This site is no longer available.", "sitepolicynotagreederror": "Site policy not agreed.", "siteurl": "Site URL", "siteurlrequired": "Site URL required i.e http://www.yourmoodlesite.org", diff --git a/src/core/features/login/pages/sites/sites.ts b/src/core/features/login/pages/sites/sites.ts index e74ac1029..447d79f7d 100644 --- a/src/core/features/login/pages/sites/sites.ts +++ b/src/core/features/login/pages/sites/sites.ts @@ -49,6 +49,10 @@ export class CoreLoginSitesPage implements OnInit { * @return Promise resolved when done. */ async ngOnInit(): Promise { + if (CoreNavigator.getRouteBooleanParam('openAddSite')) { + this.add(); + } + const sites = await CoreUtils.ignoreErrors(CoreSites.getSortedSites(), [] as CoreSiteBasicInfo[]); // Remove protocol from the url to show more url text. diff --git a/src/core/features/login/services/login-helper.ts b/src/core/features/login/services/login-helper.ts index 68a8f63d4..afa90857d 100644 --- a/src/core/features/login/services/login-helper.ts +++ b/src/core/features/login/services/login-helper.ts @@ -573,9 +573,10 @@ export class CoreLoginHelperProvider { * Check if a site URL is "allowed". In case the app has fixed sites, only those will be allowed to connect to. * * @param siteUrl Site URL to check. + * @param checkSiteFinder Whether to check site finder if needed. Defaults to true. * @return Promise resolved with boolean: whether is one of the fixed sites. */ - async isSiteUrlAllowed(siteUrl: string): Promise { + async isSiteUrlAllowed(siteUrl: string, checkSiteFinder = true): Promise { if (this.isFixedUrlSet()) { // Only 1 site allowed. return CoreUrl.sameDomainAndPath(siteUrl, this.getFixedSites()); @@ -583,7 +584,8 @@ export class CoreLoginHelperProvider { const sites = this.getFixedSites(); return sites.some((site) => CoreUrl.sameDomainAndPath(siteUrl, site.url)); - } else if (CoreConstants.CONFIG.multisitesdisplay == 'sitefinder' && CoreConstants.CONFIG.onlyallowlistedsites) { + } else if (CoreConstants.CONFIG.multisitesdisplay == 'sitefinder' && CoreConstants.CONFIG.onlyallowlistedsites && + checkSiteFinder) { // Call the sites finder to validate the site. const result = await CoreSites.findSites(siteUrl.replace(/^https?:\/\/|\.\w{2,3}\/?$/g, '')); diff --git a/src/core/initializers/consume-storage-redirect.ts b/src/core/initializers/consume-storage-redirect.ts index 4a0f0efbc..990636a0c 100644 --- a/src/core/initializers/consume-storage-redirect.ts +++ b/src/core/initializers/consume-storage-redirect.ts @@ -13,7 +13,10 @@ // limitations under the License. import { CoreApp } from '@services/app'; +import { CoreUpdateManager } from '@services/update-manager'; + +export default async function(): Promise { + await CoreUpdateManager.donePromise; -export default function(): void { CoreApp.consumeStorageRedirect(); } diff --git a/src/core/initializers/initialize-services.ts b/src/core/initializers/initialize-services.ts index c07eeafff..bef39b3a1 100644 --- a/src/core/initializers/initialize-services.ts +++ b/src/core/initializers/initialize-services.ts @@ -15,11 +15,13 @@ import { CoreFilepool } from '@services/filepool'; import { CoreLang } from '@services/lang'; import { CoreLocalNotifications } from '@services/local-notifications'; +import { CoreUpdateManager } from '@services/update-manager'; export default async function(): Promise { await Promise.all([ CoreFilepool.initialize(), CoreLang.initialize(), CoreLocalNotifications.initialize(), + CoreUpdateManager.initialize(), ]); } diff --git a/src/core/initializers/restore-session.ts b/src/core/initializers/restore-session.ts index 73296a92b..41914ea02 100644 --- a/src/core/initializers/restore-session.ts +++ b/src/core/initializers/restore-session.ts @@ -13,7 +13,10 @@ // limitations under the License. import { CoreSites } from '@services/sites'; +import { CoreUpdateManager } from '@services/update-manager'; export default async function(): Promise { + await CoreUpdateManager.donePromise; + await CoreSites.restoreSession(); } diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index eb04d3fda..ac3a630a1 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -53,6 +53,8 @@ import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreNavigationOptions } from './navigator'; import { CoreSitesFactory } from './sites-factory'; import { CoreText } from '@singletons/text'; +import { CoreLoginHelper } from '@features/login/services/login-helper'; +import { CoreErrorWithTitle } from '@classes/errors/errorwithtitle'; export const CORE_SITE_SCHEMAS = new InjectionToken('CORE_SITE_SCHEMAS'); @@ -823,6 +825,11 @@ export class CoreSitesProvider { const site = await this.getSite(siteId); + const siteUrlAllowed = await CoreLoginHelper.isSiteUrlAllowed(site.getURL(), false); + if (!siteUrlAllowed) { + throw new CoreErrorWithTitle(Translate.instant('core.login.sitenotallowed')); + } + this.currentSite = site; if (site.isLoggedOut()) { @@ -1196,8 +1203,6 @@ export class CoreSitesProvider { return; } - const db = await this.appDB; - const promises: Promise[] = []; const siteConfig = this.currentSite.getStoredConfig(); const siteId = this.currentSite.getId(); @@ -1208,7 +1213,7 @@ export class CoreSitesProvider { promises.push(this.setSiteLoggedOut(siteId, true)); } - promises.push(db.deleteRecords(CURRENT_SITE_TABLE_NAME, { id: 1 })); + promises.push(this.removeStoredCurrentSite()); await CoreUtils.ignoreErrors(Promise.all(promises)); @@ -1449,6 +1454,17 @@ export class CoreSitesProvider { return currentSite.siteId; } + /** + * Remove current site stored in DB. + * + * @return Promise resolved when done. + */ + async removeStoredCurrentSite(): Promise { + const db = await this.appDB; + + await db.deleteRecords(CURRENT_SITE_TABLE_NAME, { id: 1 }); + } + /** * Get the public config of a certain site. * diff --git a/src/core/services/update-manager.ts b/src/core/services/update-manager.ts index ed030e4c4..38ad5d2b7 100644 --- a/src/core/services/update-manager.ts +++ b/src/core/services/update-manager.ts @@ -19,6 +19,10 @@ import { CoreConstants } from '@/core/constants'; import { CoreLogger } from '@singletons/logger'; import { makeSingleton } from '@singletons'; import { CoreH5P } from '@features/h5p/services/h5p'; +import { CoreLoginHelper } from '@features/login/services/login-helper'; +import { CoreSites } from './sites'; +import { CoreUtils, PromiseDefer } from './utils/utils'; +import { CoreApp } from './app'; const VERSION_APPLIED = 'version_applied'; @@ -31,9 +35,20 @@ const VERSION_APPLIED = 'version_applied'; export class CoreUpdateManagerProvider { protected logger: CoreLogger; + protected doneDeferred: PromiseDefer; constructor() { this.logger = CoreLogger.getInstance('CoreUpdateManagerProvider'); + this.doneDeferred = CoreUtils.promiseDefer(); + } + + /** + * Returns a promise resolved when the load function is done. + * + * @return Promise resolved when the load function is done. + */ + get donePromise(): Promise { + return this.doneDeferred.promise; } /** @@ -42,12 +57,16 @@ export class CoreUpdateManagerProvider { * * @return Promise resolved when the update process finishes. */ - async load(): Promise { + async initialize(): Promise { const promises: Promise[] = []; const versionCode = CoreConstants.CONFIG.versioncode; const versionApplied = await CoreConfig.get(VERSION_APPLIED, 0); + if (versionCode > versionApplied) { + promises.push(this.checkCurrentSiteAllowed()); + } + if (versionCode >= 3950 && versionApplied < 3950 && versionApplied > 0) { promises.push(CoreH5P.h5pPlayer.deleteAllContentIndexes()); } @@ -58,9 +77,47 @@ export class CoreUpdateManagerProvider { await CoreConfig.set(VERSION_APPLIED, versionCode); } catch (error) { this.logger.error(`Error applying update from ${versionApplied} to ${versionCode}`, error); + } finally { + this.doneDeferred.resolve(); } } + /** + * If there is a current site, check if it's still supported in the new app. + * + * @return Promise resolved when done. + */ + protected async checkCurrentSiteAllowed(): Promise { + if (!CoreLoginHelper.getFixedSites()) { + return; + } + + const currentSiteId = await CoreUtils.ignoreErrors(CoreSites.getStoredCurrentSiteId()); + if (!currentSiteId) { + return; + } + + const site = await CoreUtils.ignoreErrors(CoreSites.getSite(currentSiteId)); + if (!site) { + return; + } + + const isUrlAllowed = await CoreLoginHelper.isSiteUrlAllowed(site.getURL(), false); + if (isUrlAllowed) { + return; + } + + // Site no longer supported, remove it as current site. + await CoreSites.removeStoredCurrentSite(); + + // Tell the app to open add site so the user can add the new site. + CoreApp.storeRedirect(CoreConstants.NO_SITE_ID, '/login/sites', { + params: { + openAddSite: true, + }, + }); + } + } export const CoreUpdateManager = makeSingleton(CoreUpdateManagerProvider); diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 7a3d37e90..7ffe8ddfb 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -38,6 +38,7 @@ import { CoreViewerImageComponent } from '@features/viewer/components/image/imag import { CoreFormFields, CoreForms } from '../../singletons/form'; import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; import { CoreZoomLevel } from '@features/settings/services/settings-helper'; +import { CoreErrorWithTitle } from '@classes/errors/errorwithtitle'; /* * "Utils" service with helper functions for UI, DOM elements and HTML code. @@ -1376,6 +1377,8 @@ export class CoreDomUtilsProvider { if (this.isNetworkError(message, error)) { alertOptions.cssClass = 'core-alert-network-error'; + } else if (error instanceof CoreErrorWithTitle) { + alertOptions.header = error.title || undefined; } else { alertOptions.header = Translate.instant('core.error'); }