MOBILE-3286 login: Improve guessing site domains
This commit is contained in:
		
							parent
							
								
									2e69497c13
								
							
						
					
					
						commit
						a476a773f1
					
				| @ -27,6 +27,11 @@ interface UrlParts { | |||||||
|      */ |      */ | ||||||
|     domain?: string; |     domain?: string; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Url port. | ||||||
|  |      */ | ||||||
|  |     port?: string; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Url path. |      * Url path. | ||||||
|      */ |      */ | ||||||
| @ -49,39 +54,69 @@ interface UrlParts { | |||||||
|  */ |  */ | ||||||
| export class CoreUrl { | export class CoreUrl { | ||||||
| 
 | 
 | ||||||
|     // Avoid creating singleton instances
 |     // Avoid creating singleton instances.
 | ||||||
|     private constructor() {} |     private constructor() {} | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Parse parts of a url, using an implicit protocol if it is missing from the url. |      * Parse parts of a url, using an implicit protocol if it is missing from the url. | ||||||
|      * |      * | ||||||
|      * @param url Url. |      * @param url Url. | ||||||
|      * @param implicitProtocol Protocol to be used if the url doesn't have any. |  | ||||||
|      * @return Url parts. |      * @return Url parts. | ||||||
|      */ |      */ | ||||||
|     static parse(url: string, implicitProtocol?: string): UrlParts | null { |     static parse(url: string): UrlParts | null { | ||||||
|         // Prepare url before parsing
 |         // Parse url with regular expression taken from RFC 3986: https://tools.ietf.org/html/rfc3986#appendix-B.
 | ||||||
|         url = url.trim(); |  | ||||||
| 
 |  | ||||||
|         if (implicitProtocol && !url.match(/^[a-zA-Z]+:\/\//)) { |  | ||||||
|             url = `${implicitProtocol}://${url}`; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Regular expression taken from RFC 3986: https://tools.ietf.org/html/rfc3986#appendix-B
 |  | ||||||
|         const match = url.trim().match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/); |         const match = url.trim().match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/); | ||||||
| 
 | 
 | ||||||
|         if (!match) { |         if (!match) { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Prepare parts replacing empty strings with undefined
 |         // Split host into domain and port.
 | ||||||
|  |         const host = match[4] || ''; | ||||||
|  |         const [domain, port]: string[] = host.indexOf(':') === -1 ? [host] : host.split(':'); | ||||||
|  | 
 | ||||||
|  |         // Prepare parts replacing empty strings with undefined.
 | ||||||
|         return { |         return { | ||||||
|             protocol: match[2] || undefined, |             protocol: match[2] || undefined, | ||||||
|             domain: match[4] || undefined, |             domain: domain || undefined, | ||||||
|  |             port: port || undefined, | ||||||
|             path: match[5] || undefined, |             path: match[5] || undefined, | ||||||
|             query: match[7] || undefined, |             query: match[7] || undefined, | ||||||
|             fragment: match[9] || undefined, |             fragment: match[9] || undefined, | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Guess the Moodle domain from a site url. | ||||||
|  |      * | ||||||
|  |      * @param url Site url. | ||||||
|  |      * @return Guessed Moodle domain. | ||||||
|  |      */ | ||||||
|  |     static guessMoodleDomain(url: string): string | null { | ||||||
|  |         // Add protocol if it was missing. Moodle can only be served through http or https, so this is a fair assumption to make.
 | ||||||
|  |         if (!url.match(/^https?:\/\//)) { | ||||||
|  |             url = `https://${url}`; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Match using common suffixes.
 | ||||||
|  |         const knownSuffixes = [ | ||||||
|  |             '\/my\/?', | ||||||
|  |             '\/\\\?redirect=0', | ||||||
|  |             '\/index\\\.php', | ||||||
|  |             '\/course\/view\\\.php', | ||||||
|  |             '\/login\/index\\\.php', | ||||||
|  |             '\/mod\/page\/view\\\.php', | ||||||
|  |         ]; | ||||||
|  |         const match = url.match(new RegExp(`^https?:\/\/(.*?)(${knownSuffixes.join('|')})`)); | ||||||
|  | 
 | ||||||
|  |         if (match) { | ||||||
|  |             return match[1]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // If nothing else worked, parse the domain.
 | ||||||
|  |         const urlParts = CoreUrl.parse(url); | ||||||
|  | 
 | ||||||
|  |         return urlParts && urlParts.domain ? urlParts.domain : null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -87,6 +87,8 @@ export class CoreLoginSitePage { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         url = url.trim(); | ||||||
|  | 
 | ||||||
|         const modal = this.domUtils.showModalLoading(), |         const modal = this.domUtils.showModalLoading(), | ||||||
|             siteData = this.sitesProvider.getDemoSiteData(url); |             siteData = this.sitesProvider.getDemoSiteData(url); | ||||||
| 
 | 
 | ||||||
| @ -113,18 +115,12 @@ export class CoreLoginSitePage { | |||||||
|         } else { |         } else { | ||||||
|             // Not a demo site.
 |             // Not a demo site.
 | ||||||
|             this.sitesProvider.checkSite(url) |             this.sitesProvider.checkSite(url) | ||||||
| 
 |  | ||||||
|                 // Attempt parsing the domain after initial check failed
 |  | ||||||
|                 .catch((error) => { |                 .catch((error) => { | ||||||
|                     const urlParts = CoreUrl.parse(url, 'http'); |                     // Attempt guessing the domain if the initial check failed
 | ||||||
|  |                     const domain = CoreUrl.guessMoodleDomain(url); | ||||||
| 
 | 
 | ||||||
|                     if (!urlParts || !urlParts.domain) { |                     return domain ? this.sitesProvider.checkSite(domain) : Promise.reject(error); | ||||||
|                         throw error; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     return this.sitesProvider.checkSite(urlParts.domain); |  | ||||||
|                 }) |                 }) | ||||||
| 
 |  | ||||||
|                 .then((result) => this.login(result)) |                 .then((result) => this.login(result)) | ||||||
|                 .catch((error) => this.showLoginIssue(url, error)) |                 .catch((error) => this.showLoginIssue(url, error)) | ||||||
|                 .finally(() => modal.dismiss()); |                 .finally(() => modal.dismiss()); | ||||||
| @ -177,7 +173,7 @@ export class CoreLoginSitePage { | |||||||
|      * |      * | ||||||
|      * @return Promise resolved after logging in. |      * @return Promise resolved after logging in. | ||||||
|      */ |      */ | ||||||
|     private async login(response: CoreSiteCheckResponse): Promise<void> { |     protected async login(response: CoreSiteCheckResponse): Promise<void> { | ||||||
|         return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => { |         return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => { | ||||||
|             if (response.warning) { |             if (response.warning) { | ||||||
|                 this.domUtils.showErrorModal(response.warning, true, 4000); |                 this.domUtils.showErrorModal(response.warning, true, 4000); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user