forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			71 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Validator } from "../Validator"
 | |
| 
 | |
| export default class UrlValidator extends Validator {
 | |
|     constructor() {
 | |
|         super(
 | |
|             "url",
 | |
|             "The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed",
 | |
|             "url"
 | |
|         )
 | |
|     }
 | |
|     reformat(str: string): string {
 | |
|         try {
 | |
|             let url: URL
 | |
|             // str = str.toLowerCase() // URLS are case sensitive. Lowercasing them might break some URLS. See #763
 | |
|             if (
 | |
|                 !str.startsWith("http://") &&
 | |
|                 !str.startsWith("https://") &&
 | |
|                 !str.startsWith("http:")
 | |
|             ) {
 | |
|                 url = new URL("https://" + str)
 | |
|             } else {
 | |
|                 url = new URL(str)
 | |
|             }
 | |
|             const blacklistedTrackingParams = [
 | |
|                 "fbclid", // Oh god, how I hate the fbclid. Let it burn, burn in hell!
 | |
|                 "gclid",
 | |
|                 "cmpid",
 | |
|                 "agid",
 | |
|                 "utm",
 | |
|                 "utm_source",
 | |
|                 "utm_medium",
 | |
|                 "campaignid",
 | |
|                 "campaign",
 | |
|                 "AdGroupId",
 | |
|                 "AdGroup",
 | |
|                 "TargetId",
 | |
|                 "msclkid",
 | |
|             ]
 | |
|             for (const dontLike of blacklistedTrackingParams) {
 | |
|                 url.searchParams.delete(dontLike.toLowerCase())
 | |
|             }
 | |
|             let cleaned = url.toString()
 | |
|             if (cleaned.endsWith("/") && !str.endsWith("/")) {
 | |
|                 // Do not add a trailing '/' if it wasn't typed originally
 | |
|                 cleaned = cleaned.substr(0, cleaned.length - 1)
 | |
|             }
 | |
| 
 | |
|             return cleaned
 | |
|         } catch (e) {
 | |
|             console.error(e)
 | |
|             return undefined
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     isValid(str: string): boolean {
 | |
|         try {
 | |
|             if (
 | |
|                 !str.startsWith("http://") &&
 | |
|                 !str.startsWith("https://") &&
 | |
|                 !str.startsWith("http:")
 | |
|             ) {
 | |
|                 str = "https://" + str
 | |
|             }
 | |
|             const url = new URL(str)
 | |
|             const dotIndex = url.host.indexOf(".")
 | |
|             return dotIndex > 0 && url.host[url.host.length - 1] !== "."
 | |
|         } catch (e) {
 | |
|             return false
 | |
|         }
 | |
|     }
 | |
| }
 |