From 95afa040eee5623bd0167f98f7fdf1fb8a699a59 Mon Sep 17 00:00:00 2001 From: Ifeora Izunna Date: Wed, 3 Apr 2024 23:21:58 +0100 Subject: [PATCH 1/5] release(v0.1.4): ready for release. --- CHANGELOG.md | 10 ++++++++++ README.md | 4 ++-- dist/urisanity.js.map | 2 +- dist/urisanity.min.js | 2 +- dist/urisanity.min.js.map | 2 +- package.json | 3 ++- src/index.js | 33 ++++++++++++++++++++++++++------- tests/urisanity.test.js | 32 ++++++++++++++++++++++++++++++++ types/index.d.ts | 20 +++++++++++++------- 9 files changed, 88 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad76168..3cd3fa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +# 0.1.4 (2024-04-03) + +### Features Added +- None + +### Bug Fixes +- Fixed bugs around unsafe charcters in URIs +- Fixed issues with Typescript declarations file + # 0.1.3 (2024-03-05) diff --git a/README.md b/README.md index 1b4a2f1..9599941 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![@isocroft](https://img.shields.io/badge/@isocroft-CodeSplinta-blue) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Made in Nigeria](https://img.shields.io/badge/made%20in-nigeria-008751.svg?style=flat-square)](https://github.com/acekyd/made-in-nigeria) +![@isocroft](https://img.shields.io/badge/@isocroft-CodeSplinta-blue) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-cyan.svg?style=flat-square)](http://makeapullrequest.com) [![Made in Nigeria](https://img.shields.io/badge/made%20in-nigeria-008751.svg?style=flat-square)](https://github.com/acekyd/made-in-nigeria) # URI Sanity @@ -38,7 +38,7 @@ All you need to do is import the package appropriately depending on the environm > Using a `script` tag directly inside a web page ```html - + ``` > import as ES6 module - no setup required diff --git a/dist/urisanity.js.map b/dist/urisanity.js.map index fbcd643..e02d841 100644 --- a/dist/urisanity.js.map +++ b/dist/urisanity.js.map @@ -1 +1 @@ -{"version":3,"file":"urisanity.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/03/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////')\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/i.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/i.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","isStandardBrowserEnv","environ","navigator","product","match","origin","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","extractParamValueFromUri","uri","paramName","test","trim","regex","RegExp","params","exec","unescape","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","isSameOrigin","error","checkParamsOverWhiteList","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","length","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error","sanitizeUrl","options","includes","sanitizedUrl","replace","originalSanitized","startsWith","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","vet"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"urisanity.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/04/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","isStandardBrowserEnv","environ","navigator","product","match","origin","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","extractParamValueFromUri","uri","paramName","test","trim","regex","RegExp","params","exec","unescape","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","isSameOrigin","error","checkParamsOverWhiteList","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","length","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error","hasHTMLEntity","stringSample","sanitizeUrl","options","includes","sanitizedUrl","replace","originalSanitized","startsWith","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","matches","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","vet"],"mappings":"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"} \ No newline at end of file diff --git a/dist/urisanity.min.js b/dist/urisanity.min.js index e1f7faf..e7759bc 100644 --- a/dist/urisanity.min.js +++ b/dist/urisanity.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).urisanity=t()}(this,(function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=/^([^\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\-)?radar)/im,a=/^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im,r=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/?)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\)){0,}(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s\!()\[\]{};:\'\"\.\,<>?«»“”‘’]){0,})/i,o=/^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im,i=/^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im,s=/^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im,n=/^((?:jar:)?file|local|blob)/im,c=/^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im,d=["widgets.amung.us","v.zilionfast.in","js.blinkadr.com","www.superfish.com","nzj.divdriver.net","istatic.datafastguru.info","widgets.amung.us","xls.searchfun.in","static.image2play.com"],l=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,u=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\+xml)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\/+\n=]+)$/i,f=/^data:(?:text\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im,m=/^(?:vb|java)(?:\s*)?script/im,p=/^(?:(blob:)?https?|wss?|about)/im,v=[".","/"],h="undefined"==typeof self?global||{}:self,b=h.process||{versions:{node:"."},env:{}},w=parseInt(b.versions.node.split(".")[0]);w<=12&&(h.URL||(h.URL=function(e){var t=require("url"),a=w<=11?t.parse(e):t.URL(e);return Object.assign({},a,{hostname:a.host})}));var g,y=void 0!==(g=h.navigator)&&null===g.product.match(/^(ReactNative|NativeScript|NS)$/i)?h.location.origin:(h.constants||b.env).ORIGIN;function F(e){return"string"==typeof e&&v.indexOf(e.charAt(0))>-1}function A(e){var t=void 0,a=void 0,r=void 0,o=void 0,i=void 0;o={};var s=e instanceof h.FormData?e.entries():new h.FormData(e).entries();try{for(;null!==(a=s.next().value);)r=a[0],i=a[1],Object.prototype.hasOwnProperty.call(o,r)?(t=o[r],Array.isArray(t)||(t=o[r]=[t]),t.push(i)):o[r]=i}catch(e){o=Object.fromEntries(s)}return JSON.stringify(o)}function L(e){var f=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e||null!==e.match(/:\/\/(?:[#$@=*.!]|[/]){0,}$/)||e.includes("////////////"))return"about:blank";var v=e.replace(l,"").trim();if(F(v)){var b=v.startsWith("/")?y+v:y+"/"+v;v=r.test(b)?b:"//"}var w=v.match(a)||v.match(o)||v.match(i)||v.match(s)||v.match(c)||v.match(p),g=(w=null!==w?w:[])[0]||"";try{var A=new h.URL(v.toLowerCase()),L=A.hostname,j=A.pathname,x=A.search,C=A.hash;if(/^(?:((?:www|[a-z]{1,11})\.)(?!\1)(?:[a-z\-\d]{1,63})\.(?:[a-z.\-\d]{2,63}))$/i.test(L)||/^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(L)||/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(L)||/^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@)*)/i.test(j)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/i.test(x)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/i.test(C)){if(L.includes(".00")||-1!==d.indexOf(L))return"about:blank";if(j.toLowerCase().includes("'")||j.toLowerCase().includes("%29")||j.toLowerCase().includes("%28")||j.toLowerCase().includes("%20")||j.toLowerCase().includes("%22")||j.toLowerCase().includes(""")||j.toLowerCase().includes("(")||j.toLowerCase().includes(")")||j.toLowerCase().includes("%3e")||j.toLowerCase().includes("%3c")||j.toLowerCase().includes("><"))return"about:blank";if(null!==x.toLowerCase().match(/%3c(?=\/)?/g)||x.toLowerCase().includes("%3e")||x.toLowerCase().includes("%3f")||x.toLowerCase().includes("%3d")||x.toLowerCase().includes("%27")||x.toLowerCase().includes("%22")||x.toLowerCase().includes("'")||x.toLowerCase().includes(""")||null!==x.toLowerCase().match(/\.(?:jar|dmg|exe|bin|sh|sed|py)/g))return"about:blank"}}catch(e){if(e)return"about:blank"}if(!t.test(g)||r.test(v)){var O=!1;return f.allowScriptOrDataURI&&null!==g.match(/^(java|vb)script|data/)&&(u.test(v)||m.test(v))&&(O=!0),f.allowCommsAppURI&&o.test(v)&&(O=!0),f.allowDBConnectionStringURI&&i.test(v)&&(O=!0),f.allowServiceAPIURI&&c.test(v)&&(O=!0),f.allowBrowserSpecificURI&&s.test(v)&&(O=!0),f.allowWebTransportURI&&p.test(v)&&(O=!0),f.allowFileSystemURI&&n.test(v)&&(O=!0),""!==g&&O?v:"about:blank"}}var j={isSameOrigin:function(e){if(!e||f.test(e.trim())||u.test(e.trim()))return!1;try{var t=new h.URL(e.trim());return y===t.origin}catch(e){if(e)return!1}},extractParamValueFromUri:function(e,t){if(!e||f.test(e.trim())||u.test(e.trim()))return null;var a=new RegExp("[\\?&#]"+t+"=([^&#]*)").exec(e.trim());return null!=a?unescape(a[1]):void 0},checkParamsOverWhiteList:function(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";if(!t||f.test(t.trim())||u.test(t.trim()))return!1;if("object"!==(void 0===a?"undefined":e(a)))return!1;var o=new h.URL(t.trim()),i=[],s=[],n=null;try{var c="";if("FormData"in h&&r instanceof h.FormData)if("function"==typeof Object.fromEntries)c=A(r);else{var d={};r.forEach((function(e,t){d[t]=e})),c=JSON.stringify(d)}else c=r;"string"==typeof c&&(n=JSON.parse(c))}catch(e){n=r}if(""===n?o.searchParams.forEach((function(){for(var e=arguments.length,t=Array(e),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};return L(e,t||{})}};return j})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).urisanity=t()}(this,(function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=/^([^\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\-)?radar)/im,a=/^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im,r=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/?)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\)){0,}(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s\!()\[\]{};:\'\"\.\,<>?«»“”‘’]){0,})/i,o=/^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im,i=/^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im,s=/^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im,n=/^((?:jar:)?file|local|blob)/im,c=/^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im,l=["widgets.amung.us","v.zilionfast.in","js.blinkadr.com","www.superfish.com","nzj.divdriver.net","istatic.datafastguru.info","widgets.amung.us","xls.searchfun.in","static.image2play.com"],d=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,u=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\+xml)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\/+\n=]+)$/i,f=/^data:(?:text\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im,m=/^(?:vb|java)(?:\s*)?script/im,p=/^(?:(blob:)?https?|wss?|about|mailto|tel)/im,v=[".","/"],h="undefined"==typeof self?global||{}:self,b=h.process||{versions:{node:"."},env:{}},g=parseInt(b.versions.node.split(".")[0]);g<=12&&(h.URL||(h.URL=function(e){var t=require("url"),a=g<=11?t.parse(e):t.URL(e);return Object.assign({},a,{hostname:a.host})}));var w,y=void 0!==(w=h.navigator)&&null===w.product.match(/^(ReactNative|NativeScript|NS)$/i)?h.location.origin:(h.constants||b.env).ORIGIN;function F(e){return"string"==typeof e&&v.indexOf(e.charAt(0))>-1}function A(e){var t=void 0,a=void 0,r=void 0,o=void 0,i=void 0;o={};var s=e instanceof h.FormData?e.entries():new h.FormData(e).entries();try{for(;null!==(a=s.next().value);)r=a[0],i=a[1],Object.prototype.hasOwnProperty.call(o,r)?(t=o[r],Array.isArray(t)||(t=o[r]=[t]),t.push(i)):o[r]=i}catch(e){o=Object.fromEntries(s)}return JSON.stringify(o)}var L=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return"string"==typeof e&&/&(?:[a-z]+|#x?\d+);/gim.test(e)};function x(e){var f=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e||null!==e.match(/:\/\/(?:[#$@=*.!]|[/]){0,}$/)||e.includes("////////////")||L(e))return"about:blank";var v=e.replace(d,"").trim();if(F(v)){var b=v.startsWith("/")?y+v:y+"/"+v;v=r.test(b)?b:"//"}var g=v.match(a)||v.match(o)||v.match(i)||v.match(s)||v.match(c)||v.match(p),w=(g=null!==g?g:[])[0]||"";try{var A=new h.URL(v.toLowerCase()),x=A.hostname,j=A.pathname,C=A.search,k=A.hash,O=C.match(/\?/g)||[];if(O.length>1)return"about:blank";if(/^(?:((?:www|[a-z]{1,11})\.)(?!\1)(?:[a-z\-\d]{1,63})\.(?:[a-z.\-\d]{2,63}))$/i.test(x)||/^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(x)||/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(x)||/^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@)*)/i.test(j)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(C)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(k)){if(x.includes(".00")||-1!==l.indexOf(x))return"about:blank";if(j.toLowerCase().includes("'")||j.toLowerCase().includes("%29")||j.toLowerCase().includes("%28")||j.toLowerCase().includes("%20")||j.toLowerCase().includes("%22")||j.toLowerCase().includes(""")||j.toLowerCase().includes("(")||j.toLowerCase().includes(")")||j.toLowerCase().includes("%3e")||j.toLowerCase().includes("%3c")||j.toLowerCase().includes("><"))return"about:blank";if(null!==C.toLowerCase().match(/%3c(?=\/)?/g)||C.toLowerCase().includes("%3e")||C.toLowerCase().includes("%3f")||C.toLowerCase().includes("%3d")||C.toLowerCase().includes("%27")||C.toLowerCase().includes("%22")||C.toLowerCase().includes("'")||C.toLowerCase().includes(""")||null!==C.toLowerCase().match(/\.(?:jar|dmg|exe|bin|sh|sed|py)/g))return"about:blank"}}catch(e){if(e)return"about:blank"}if(!t.test(w)||r.test(v)){var R=!1;return f.allowScriptOrDataURI&&null!==w.match(/^(java|vb)script|data/)&&(u.test(v)||m.test(v))&&(R=!0),f.allowCommsAppURI&&o.test(v)&&(R=!0),f.allowDBConnectionStringURI&&i.test(v)&&(R=!0),f.allowServiceAPIURI&&c.test(v)&&(R=!0),f.allowBrowserSpecificURI&&s.test(v)&&(R=!0),f.allowWebTransportURI&&p.test(v)&&(R=!0),f.allowFileSystemURI&&n.test(v)&&(R=!0),""!==w&&R?v:"about:blank"}}var j={isSameOrigin:function(e){if(!e||f.test(e.trim())||u.test(e.trim()))return!1;try{var t=new h.URL(e.trim());return y===t.origin}catch(e){if(e)return!1}},extractParamValueFromUri:function(e,t){if(!e||f.test(e.trim())||u.test(e.trim()))return null;var a=new RegExp("[\\?&#]"+t+"=([^&#]*)").exec(e.trim());return null!=a?unescape(a[1]):void 0},checkParamsOverWhiteList:function(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";if(!t||f.test(t.trim())||u.test(t.trim()))return!1;if("object"!==(void 0===a?"undefined":e(a)))return!1;var o=new h.URL(t.trim()),i=[],s=[],n=null;try{var c="";if("FormData"in h&&r instanceof h.FormData)if("function"==typeof Object.fromEntries)c=A(r);else{var l={};r.forEach((function(e,t){l[t]=e})),c=JSON.stringify(l)}else c=r;"string"==typeof c&&(n=JSON.parse(c))}catch(e){n=r}if(""===n?o.searchParams.forEach((function(){for(var e=arguments.length,t=Array(e),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};return x(e,t||{})}};return j})); //# sourceMappingURL=urisanity.min.js.map diff --git a/dist/urisanity.min.js.map b/dist/urisanity.min.js.map index f04623c..ea67238 100644 --- a/dist/urisanity.min.js.map +++ b/dist/urisanity.min.js.map @@ -1 +1 @@ -{"version":3,"file":"urisanity.min.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/03/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////')\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/i.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/i.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","environ","origin","navigator","product","match","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","sanitizeUrl","options","includes","sanitizedUrl","replace","trim","originalSanitized","startsWith","test","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","error","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","uri","paramName","params","RegExp","exec","unescape","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","length","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"urisanity.min.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/04/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","environ","origin","navigator","product","match","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","hasHTMLEntity","stringSample","test","sanitizeUrl","options","includes","sanitizedUrl","replace","trim","originalSanitized","startsWith","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","matches","length","error","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","uri","paramName","params","RegExp","exec","unescape","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 3f4d0a1..b11f225 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "urisanity", "description": "vet URIs in web and web-like applications with confidence", - "version": "0.1.3", + "version": "0.1.4", "main": "dist/urisanity.cjs.js", "module": "dist/urisanity.es.js", "browser": "dist/urisanity.js", + "typings": "./types/index.d.ts", "files": [ "dist", "examples", diff --git a/src/index.js b/src/index.js index abab900..224a25b 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ * See: https://en.wikipedia.org/wiki/List_of_URI_schemes * * @created: 23/06/2021 - * @last-updated: 05/03/2024 + * @last-updated: 05/04/2024 */ /* eslint-disable no-useless-escape */ @@ -57,7 +57,7 @@ const dataURIBINRegex = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\+xml)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\/+\n=]+)$/i const dataURITEXTRegex = /^data:(?:text\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im const scriptURIRegex = /^(?:vb|java)(?:\s*)?script/im -const webTransportURIRegex = /^(?:(blob:)?https?|wss?|about)/im +const webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im const relativeFirstCharacters = ['.', '/'] /* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */ @@ -248,11 +248,26 @@ function checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') { return false } +/** + * @source: https://stackoverflow.com/a/13763250 + * + * @param {String} stringSample + * @returns + */ +const hasHTMLEntity = (stringSample = '') => { + if (typeof stringSample !== 'string') { + return false + } + return /&(?:[a-z]+|#x?\d+);/gim.test(stringSample) +} + function sanitizeUrl (url, options = {}) { if ( !url || url.match(/:\/\/(?:[#$@=*.!]|[/]){0,}$/) !== null || - url.includes('////////////') + url.includes('////////////') || + /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */ + hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */ ) { return 'about:blank' } @@ -285,6 +300,12 @@ function sanitizeUrl (url, options = {}) { sanitizedUrl.toLowerCase() ) + const matches = search.match(/\?/g) || [] + + if (matches.length > 1) { + return 'about:blank' + } + /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */ /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */ if ( @@ -300,10 +321,10 @@ function sanitizeUrl (url, options = {}) { /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@)*)/i.test( pathname ) || - /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/i.test( + /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test( search ) || - /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/i.test( + /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test( hash ) ) { @@ -343,7 +364,6 @@ function sanitizeUrl (url, options = {}) { } } catch (error) { if (error) { - /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */ return 'about:blank' } } @@ -404,7 +424,6 @@ function sanitizeUrl (url, options = {}) { if (urlScheme !== '' && pass) { return sanitizedUrl } else { - /* console.warn(`WARNING: unsafe URL > ${sanitizedUrl} (see https://g.co/ng/security#xss)`) */ return 'about:blank' } } diff --git a/tests/urisanity.test.js b/tests/urisanity.test.js index 242f46a..0a1d02c 100644 --- a/tests/urisanity.test.js +++ b/tests/urisanity.test.js @@ -69,6 +69,14 @@ describe('check well-formed URIs', () => { expect(sanitizedUrl).toEqual('blob:https://www.good.foo.com/9f368042-bf23-42b6-b07c-54189d3b0e01') }); + + test('mailto URI passes flag option', () => { + const sanitizedUrl = URISanity.vet('mailto:hello@example.com', { + allowWebTransportURI: true + }) + + expect(sanitizedUrl).toEqual('mailto:hello@example.com') + }) }) describe('check badly formed or suspicious URIs', () => { @@ -80,6 +88,30 @@ describe('check badly formed or suspicious URIs', () => { expect(sanitizedUrl).toEqual('about:blank') }) + test('http URI with malicious JS code fails flag option', () => { + const sanitizedUrl = URISanity.vet('http://example.com/?', { + allowWebTransportURI: true + }) + + expect(sanitizedUrl).toEqual('about:blank') + }) + + test('http URI with malicious markup script disguised as query string fails flag option', () => { + const sanitizedUrl = URISanity.vet('http://example.com/"onmouseover="alert(1)"', { + allowWebTransportURI: true + }) + + expect(sanitizedUrl).toEqual('about:blank') + }) + + test('http URI with multiple question mark characters in query string fails flag option', () => { + const sanitizedUrl = URISanity.vet('https://wordcrest.com/api/intent/lock/?t=9204949949?t=9595005005?t=096989549983', { + allowWebTransportURI: true + }) + + expect(sanitizedUrl).toEqual('about:blank') + }) + test('blob URI fails flag option', () => { const sanitizedUrl = URISanity.vet('blob:https://www.foo-.evil.com/undefined', { allowWebTransportURI: false diff --git a/types/index.d.ts b/types/index.d.ts index 93bfd6c..b763490 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,8 +1,8 @@ -// Type definitions for URI Sanity 0.1.x +// Type definitions for urisanity v0.1.4 // Project: https://github.com/codesplinta/URISanity declare module 'urisanity' { - declare type Options = { + export type Options = { allowScriptOrDataURI?: boolean, allowFileSystemURI?: boolean, allowCommsAppURI?: boolean, @@ -11,10 +11,16 @@ declare module 'urisanity' { allowWebTransportURI?: boolean, allowServiceAPIURI?: boolean }; - declare type Params = string | Record; + export type Params = string | Record; - export const vet = (url: string, options?: Options) => string; - export const isSameOrigin = (uri: string) => boolean; - export const extractParamValueFromUri = (uri: string, queryParamName: string) => string; - export const checkParamsOverWhiteList = (uri: string, paramsWhiteList?: string[], params?: Params) => boolean; + const URISanity: { + vet(url: string, options?: Options): string; + isSameOrigin(uri: string): boolean; + extractParamValueFromUri(uri: string, queryParamName: string): string; + checkParamsOverWhiteList(uri: string, paramsWhiteList?: string[] | Record, params?: Params): boolean; + }; + + export type URISanityAPI = typeof URISanity; + + export default URISanity; } From fd0004ef7ae5f65117d4ec9768e71d11f19f871c Mon Sep 17 00:00:00 2001 From: Ifeora Okechukwu Date: Wed, 3 Apr 2024 23:54:37 +0100 Subject: [PATCH 2/5] chore: updated README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9599941..daefbc5 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ const isSame = URISanity.isSameOrigin(window.location.href) console.log(isSame) // true ``` -### NodeJS environment +### NodeJS (commonjs) environment > Setup an env file in your NodeJS app and include an `ORIGIN` From 09da95b098c08b1961bb1501e592da88893f41c1 Mon Sep 17 00:00:00 2001 From: Ifeora Izunna Date: Fri, 5 Apr 2024 02:43:16 +0100 Subject: [PATCH 3/5] chore: setting up for next version --- CHANGELOG.md | 9 +++++++++ README.md | 2 +- package.json | 2 +- types/index.d.ts | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cd3fa5..ededc26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ + +# 0.1.5 (2024-04-08) + +### Features Added +- None + +### Bug Fixes +- None + # 0.1.4 (2024-04-03) diff --git a/README.md b/README.md index daefbc5..ce0def2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ All you need to do is import the package appropriately depending on the environm > Using a `script` tag directly inside a web page ```html - + ``` > import as ES6 module - no setup required diff --git a/package.json b/package.json index b11f225..df9c9d0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "urisanity", "description": "vet URIs in web and web-like applications with confidence", - "version": "0.1.4", + "version": "0.1.5", "main": "dist/urisanity.cjs.js", "module": "dist/urisanity.es.js", "browser": "dist/urisanity.js", diff --git a/types/index.d.ts b/types/index.d.ts index b763490..37dc8ee 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for urisanity v0.1.4 +// Type definitions for urisanity v0.1.5 // Project: https://github.com/codesplinta/URISanity declare module 'urisanity' { From 94735858a78bd09e4b65678a9901a51a1e82d78b Mon Sep 17 00:00:00 2001 From: Okechukwu Ifeora Patrick Date: Thu, 19 Sep 2024 02:15:51 +0100 Subject: [PATCH 4/5] release(v0.1.6): ready to publish --- CHANGELOG.md | 12 +++++++++++- README.md | 4 ++-- dist/urisanity.js.map | 2 +- dist/urisanity.min.js | 2 +- dist/urisanity.min.js.map | 2 +- src/index.js | 10 +++++++--- tests/urisanity.test.js | 14 ++++++++++++++ types/index.d.ts | 2 +- 8 files changed, 38 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ededc26..eea0b71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,18 @@ + +# 0.1.6 (2024-09-20) + +### Features Added +- None + +### Bug Fixes +- Fixed [Issue 1](https://github.com/codesplinta/URISanity/issues/1) reported by [@ccrawford4](https://github.com/ccrawford4) + # 0.1.5 (2024-04-08) ### Features Added -- None +- Refactored `checkParamsOverWhiteList(...)` function to allow second argument (`paramsWhiteList`) take +not only arrays but objects { key: value } pair too ### Bug Fixes - None diff --git a/README.md b/README.md index ce0def2..6f97268 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ All you need to do is import the package appropriately depending on the environm > Using a `script` tag directly inside a web page ```html - + ``` > import as ES6 module - no setup required @@ -380,7 +380,7 @@ if ('toSource' in NativeSendBeacon) { } ``` -Finally, the code above in the event handler get triggered whenever `navigator.sendBeacon()` is called and the URLs are using **URISanity**. +Finally, the code above in the event handler get triggered whenever `navigator.sendBeacon()` is called and the URLs are using **URISanity**. The [zhorn](https://www.npmjs.com/package/zhorn) package provides all of this functionality and depends on **URISanity**. ## Documentation diff --git a/dist/urisanity.js.map b/dist/urisanity.js.map index e02d841..5b3374e 100644 --- a/dist/urisanity.js.map +++ b/dist/urisanity.js.map @@ -1 +1 @@ -{"version":3,"file":"urisanity.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/04/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","isStandardBrowserEnv","environ","navigator","product","match","origin","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","extractParamValueFromUri","uri","paramName","test","trim","regex","RegExp","params","exec","unescape","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","isSameOrigin","error","checkParamsOverWhiteList","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","length","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error","hasHTMLEntity","stringSample","sanitizeUrl","options","includes","sanitizedUrl","replace","originalSanitized","startsWith","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","matches","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","vet"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"urisanity.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 21/09/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><') ||\n pathname.toLowerCase().includes(']+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\)){0,}(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s\!()\[\]{};:\'\"\.\,<>?«»“”‘’]){0,})/i,o=/^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im,i=/^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im,s=/^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im,n=/^((?:jar:)?file|local|blob)/im,c=/^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im,l=["widgets.amung.us","v.zilionfast.in","js.blinkadr.com","www.superfish.com","nzj.divdriver.net","istatic.datafastguru.info","widgets.amung.us","xls.searchfun.in","static.image2play.com"],d=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,u=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\+xml)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\/+\n=]+)$/i,f=/^data:(?:text\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im,m=/^(?:vb|java)(?:\s*)?script/im,p=/^(?:(blob:)?https?|wss?|about|mailto|tel)/im,v=[".","/"],h="undefined"==typeof self?global||{}:self,b=h.process||{versions:{node:"."},env:{}},g=parseInt(b.versions.node.split(".")[0]);g<=12&&(h.URL||(h.URL=function(e){var t=require("url"),a=g<=11?t.parse(e):t.URL(e);return Object.assign({},a,{hostname:a.host})}));var w,y=void 0!==(w=h.navigator)&&null===w.product.match(/^(ReactNative|NativeScript|NS)$/i)?h.location.origin:(h.constants||b.env).ORIGIN;function F(e){return"string"==typeof e&&v.indexOf(e.charAt(0))>-1}function A(e){var t=void 0,a=void 0,r=void 0,o=void 0,i=void 0;o={};var s=e instanceof h.FormData?e.entries():new h.FormData(e).entries();try{for(;null!==(a=s.next().value);)r=a[0],i=a[1],Object.prototype.hasOwnProperty.call(o,r)?(t=o[r],Array.isArray(t)||(t=o[r]=[t]),t.push(i)):o[r]=i}catch(e){o=Object.fromEntries(s)}return JSON.stringify(o)}var L=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return"string"==typeof e&&/&(?:[a-z]+|#x?\d+);/gim.test(e)};function x(e){var f=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e||null!==e.match(/:\/\/(?:[#$@=*.!]|[/]){0,}$/)||e.includes("////////////")||L(e))return"about:blank";var v=e.replace(d,"").trim();if(F(v)){var b=v.startsWith("/")?y+v:y+"/"+v;v=r.test(b)?b:"//"}var g=v.match(a)||v.match(o)||v.match(i)||v.match(s)||v.match(c)||v.match(p),w=(g=null!==g?g:[])[0]||"";try{var A=new h.URL(v.toLowerCase()),x=A.hostname,j=A.pathname,C=A.search,k=A.hash,O=C.match(/\?/g)||[];if(O.length>1)return"about:blank";if(/^(?:((?:www|[a-z]{1,11})\.)(?!\1)(?:[a-z\-\d]{1,63})\.(?:[a-z.\-\d]{2,63}))$/i.test(x)||/^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(x)||/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(x)||/^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@)*)/i.test(j)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(C)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(k)){if(x.includes(".00")||-1!==l.indexOf(x))return"about:blank";if(j.toLowerCase().includes("'")||j.toLowerCase().includes("%29")||j.toLowerCase().includes("%28")||j.toLowerCase().includes("%20")||j.toLowerCase().includes("%22")||j.toLowerCase().includes(""")||j.toLowerCase().includes("(")||j.toLowerCase().includes(")")||j.toLowerCase().includes("%3e")||j.toLowerCase().includes("%3c")||j.toLowerCase().includes("><"))return"about:blank";if(null!==C.toLowerCase().match(/%3c(?=\/)?/g)||C.toLowerCase().includes("%3e")||C.toLowerCase().includes("%3f")||C.toLowerCase().includes("%3d")||C.toLowerCase().includes("%27")||C.toLowerCase().includes("%22")||C.toLowerCase().includes("'")||C.toLowerCase().includes(""")||null!==C.toLowerCase().match(/\.(?:jar|dmg|exe|bin|sh|sed|py)/g))return"about:blank"}}catch(e){if(e)return"about:blank"}if(!t.test(w)||r.test(v)){var R=!1;return f.allowScriptOrDataURI&&null!==w.match(/^(java|vb)script|data/)&&(u.test(v)||m.test(v))&&(R=!0),f.allowCommsAppURI&&o.test(v)&&(R=!0),f.allowDBConnectionStringURI&&i.test(v)&&(R=!0),f.allowServiceAPIURI&&c.test(v)&&(R=!0),f.allowBrowserSpecificURI&&s.test(v)&&(R=!0),f.allowWebTransportURI&&p.test(v)&&(R=!0),f.allowFileSystemURI&&n.test(v)&&(R=!0),""!==w&&R?v:"about:blank"}}var j={isSameOrigin:function(e){if(!e||f.test(e.trim())||u.test(e.trim()))return!1;try{var t=new h.URL(e.trim());return y===t.origin}catch(e){if(e)return!1}},extractParamValueFromUri:function(e,t){if(!e||f.test(e.trim())||u.test(e.trim()))return null;var a=new RegExp("[\\?&#]"+t+"=([^&#]*)").exec(e.trim());return null!=a?unescape(a[1]):void 0},checkParamsOverWhiteList:function(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";if(!t||f.test(t.trim())||u.test(t.trim()))return!1;if("object"!==(void 0===a?"undefined":e(a)))return!1;var o=new h.URL(t.trim()),i=[],s=[],n=null;try{var c="";if("FormData"in h&&r instanceof h.FormData)if("function"==typeof Object.fromEntries)c=A(r);else{var l={};r.forEach((function(e,t){l[t]=e})),c=JSON.stringify(l)}else c=r;"string"==typeof c&&(n=JSON.parse(c))}catch(e){n=r}if(""===n?o.searchParams.forEach((function(){for(var e=arguments.length,t=Array(e),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};return x(e,t||{})}};return j})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).urisanity=t()}(this,(function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=/^([^\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\-)?radar)/im,a=/^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im,r=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/?)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\)){0,}(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s\!()\[\]{};:\'\"\.\,<>?«»“”‘’]){0,})/i,o=/^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im,i=/^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im,s=/^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im,n=/^((?:jar:)?file|local|blob)/im,c=/^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im,l=["widgets.amung.us","v.zilionfast.in","js.blinkadr.com","www.superfish.com","nzj.divdriver.net","istatic.datafastguru.info","widgets.amung.us","xls.searchfun.in","static.image2play.com"],d=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,u=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\+xml)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\/+\n=]+)$/i,f=/^data:(?:text\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im,m=/^(?:vb|java)(?:\s*)?script/im,p=/^(?:(blob:)?https?|wss?|about|mailto|tel)/im,h=[".","/"],v="undefined"==typeof self?global||{}:self,b=v.process||{versions:{node:"."},env:{}},g=parseInt(b.versions.node.split(".")[0]);g<=12&&(v.URL||(v.URL=function(e){var t=require("url"),a=g<=11?t.parse(e):t.URL(e);return Object.assign({},a,{hostname:a.host})}));var w,y=void 0!==(w=v.navigator)&&null===w.product.match(/^(ReactNative|NativeScript|NS)$/i)?v.location.origin:(v.constants||b.env).ORIGIN;function F(e){return"string"==typeof e&&h.indexOf(e.charAt(0))>-1}function L(e){var t=void 0,a=void 0,r=void 0,o=void 0,i=void 0;o={};var s=e instanceof v.FormData?e.entries():new v.FormData(e).entries();try{for(;null!==(a=s.next().value);)r=a[0],i=a[1],Object.prototype.hasOwnProperty.call(o,r)?(t=o[r],Array.isArray(t)||(t=o[r]=[t]),t.push(i)):o[r]=i}catch(e){o=Object.fromEntries(s)}return JSON.stringify(o)}var A=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return"string"==typeof e&&/&(?:[a-z]+|#x?\d+);/gim.test(e)};function C(e){var f=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e||null!==e.match(/:\/\/(?:[#$@=*.!]|[/]){0,}$/)||e.includes("////////////")||A(e))return"about:blank";var h=e.replace(d,"").trim();if(F(h)){var b=h.startsWith("/")?y+h:y+"/"+h;h=r.test(b)?b:"//"}var g=h.match(a)||h.match(o)||h.match(i)||h.match(s)||h.match(c)||h.match(p),w=(g=null!==g?g:[])[0]||"";try{var L=new v.URL(h.toLowerCase()),C=L.hostname,x=L.pathname,j=L.search,k=L.hash,O=j.match(/\?/g)||[];if(O.length>1)return"about:blank";if(/^(?:((?:www|[a-z]{1,11})\.)(?!\1)(?:[a-z\-\d]{1,63})\.(?:[a-z.\-\d]{2,63}))$/i.test(C)||/^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(C)||/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(C)||/^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@)*)/i.test(x)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(j)||/^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\:|\@|\/|\?)*$/gi.test(k)){if(C.includes(".00")||-1!==l.indexOf(C))return"about:blank";if(x.toLowerCase().includes("'")||x.toLowerCase().includes("%29")||x.toLowerCase().includes("%28")||x.toLowerCase().includes("%22")||x.toLowerCase().includes(""")||x.toLowerCase().includes("'")||x.toLowerCase().includes("(")||x.toLowerCase().includes(")")||x.toLowerCase().includes("%3e")||x.toLowerCase().includes("%3c")||x.toLowerCase().includes("><")||x.toLowerCase().includes("1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";if(!t||f.test(t.trim())||u.test(t.trim()))return!1;if("object"!==(void 0===a?"undefined":e(a)))return!1;var o=new v.URL(t.trim()),i=[],s=[],n=null;try{var c="";if("FormData"in v&&r instanceof v.FormData)if("function"==typeof Object.fromEntries)c=L(r);else{var l={};r.forEach((function(e,t){l[t]=e})),c=JSON.stringify(l)}else c=r;"string"==typeof c&&(n=JSON.parse(c))}catch(e){n=r}if(""===n?o.searchParams.forEach((function(){for(var e=arguments.length,t=Array(e),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};return C(e,t||{})}};return x})); //# sourceMappingURL=urisanity.min.js.map diff --git a/dist/urisanity.min.js.map b/dist/urisanity.min.js.map index ea67238..ff9b015 100644 --- a/dist/urisanity.min.js.map +++ b/dist/urisanity.min.js.map @@ -1 +1 @@ -{"version":3,"file":"urisanity.min.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 05/04/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%20') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><')\n ) {\n return 'about:blank'\n }\n\n if (\n search.toLowerCase().match(/%3c(?=\\/)?/g) !== null ||\n search.toLowerCase().includes('%3e') ||\n search.toLowerCase().includes('%3f') ||\n search.toLowerCase().includes('%3d') ||\n search.toLowerCase().includes('%27') ||\n search.toLowerCase().includes('%22') ||\n search.toLowerCase().includes(''') ||\n search.toLowerCase().includes('"') ||\n search.toLowerCase().match(/\\.(?:jar|dmg|exe|bin|sh|sed|py)/g) !== null\n ) {\n return 'about:blank'\n }\n }\n } catch (error) {\n if (error) {\n return 'about:blank'\n }\n }\n\n if (\n !unsafeURISchemeRegex.test(urlScheme) ||\n safeURIRegex.test(sanitizedUrl)\n ) {\n let pass = false\n\n if (\n options.allowScriptOrDataURI &&\n urlScheme.match(/^(java|vb)script|data/) !== null &&\n (dataURIBINRegex.test(sanitizedUrl) || scriptURIRegex.test(sanitizedUrl))\n ) {\n pass = true\n }\n\n if (options.allowCommsAppURI && commsAppURISchemeRegex.test(sanitizedUrl)) {\n pass = true\n }\n\n if (\n options.allowDBConnectionStringURI &&\n databaseConnectionStringURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowServiceAPIURI &&\n serviceAPIURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowBrowserSpecificURI &&\n browserURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowWebTransportURI &&\n webTransportURIRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (\n options.allowFileSystemURI &&\n fileSystemURISchemeRegex.test(sanitizedUrl)\n ) {\n pass = true\n }\n\n if (urlScheme !== '' && pass) {\n return sanitizedUrl\n } else {\n return 'about:blank'\n }\n }\n}\n\nconst URISanity = {\n isSameOrigin,\n extractParamValueFromUri,\n checkParamsOverWhiteList,\n vet (url, options = {}) {\n return sanitizeUrl(url, options || {})\n }\n}\n\nexport default URISanity\n"],"names":["unsafeURISchemeRegex","safeInternetURISchemeRegex","safeURIRegex","commsAppURISchemeRegex","databaseConnectionStringURISchemeRegex","browserURISchemeRegex","fileSystemURISchemeRegex","serviceAPIURISchemeRegex","blockedHosts","ctrlCharactersRegex","dataURIBINRegex","dataURITEXTRegex","scriptURIRegex","webTransportURIRegex","relativeFirstCharacters","$globals","self","global","nodeJSProcess","process","versions","node","env","NODE_MAJOR_VERSION","parseInt","split","URL","urlString","urlParser","require","parsedUrl","parse","Object","assign","hostname","host","environ","origin","navigator","product","match","location","constants","ORIGIN","isRelativeUrlWithoutProtocol","url","indexOf","charAt","formDataToJSON","elem","current","item","key","output","value","entries","FormData","next","prototype","hasOwnProperty","call","Array","isArray","push","_","fromEntries","JSON","stringify","hasHTMLEntity","stringSample","test","sanitizeUrl","options","includes","sanitizedUrl","replace","trim","originalSanitized","startsWith","urlSchemeParseResults","urlScheme","toLowerCase","pathname","search","hash","matches","length","error","pass","allowScriptOrDataURI","allowCommsAppURI","allowDBConnectionStringURI","allowServiceAPIURI","allowBrowserSpecificURI","allowWebTransportURI","allowFileSystemURI","URISanity","uri","paramName","params","RegExp","exec","unescape","paramsWhiteList","data","paramKeys","paramValues","preparedData","json","object","forEach","searchParams","args","concat","values","slice","sort","join","paramsCounter","paramKey","paramValue","paramRegex","Error"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"urisanity.min.js","sources":["../src/index.js"],"sourcesContent":["/** !\n * @author: https://twitter.com/isocroft\n * @owner: https://twitter.com/codesplinta\n *\n * @Copyright (c) 2021 - 2024\n *\n * @sourced: [first-party] https://github.com/braintree/sanitize-url\n *\n * Based on the well known URI schemes;\n * See: https://en.wikipedia.org/wiki/List_of_URI_schemes\n *\n * @created: 23/06/2021\n * @last-updated: 21/09/2024\n */\n\n/* eslint-disable no-useless-escape */\n\n/* @HINT: all URI schemes that are mostly unsafe for web browsers to launch */\nconst unsafeURISchemeRegex =\n /^([^\\w]*)(unsafe|javascript|vbscript|app|admin|icloud-sharing|icloud-vetting|help|aim|facetime-audio|applefeedback|ibooks|macappstore|udoc|ts|st|jar|x-apple-helpbasic|(?:x\\-)?radar)/im\n/* @HINT: all URI schemes that are mostly safe for web browsers to launch */\nconst safeInternetURISchemeRegex =\n /^(?:(?:f|ht)tps?|cid|xmpp|mms|webcal|aaa|acap|bolo|data|blob|file|local|wss?|irc|udp)/im\n/* @CHECK: https://gist.github.com/gruber/249502/61cbb59f099fdf90316c4e409c7523b6d5124f80 */\nconst safeURIRegex =\n /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)){0,}(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s\\!()\\[\\]{};:\\'\\\"\\.\\,<>?«»“”‘’]){0,})/i\n/* @HINT: */\nconst commsAppURISchemeRegex =\n /^(whatsapp|zoommtg|slack|mailto|tel|callto|sms|skype)/im\nconst databaseConnectionStringURISchemeRegex =\n /^(jdbc(:sqlserver|:mysql|:mariadb|:sqlite)?|odbc|postgres(ql)?|mongodb)/im\nconst browserURISchemeRegex = /^(view-source|moz-extension|resource|res|symres|(?:filesystem:|blob:)?chrome-extension|safari|chrome|mxaddon-pkg|mx|mxwebcore|mxjscall|mbinit|safari-resource|opera|webviewprogressproxy|chromenull|chromeinvoke|chromeinvokeimmediate)/im\n/* @CHECK: - FILE URI */\n/* @CHECK: https://www.w3.org/TR/FileAPI/#blob-url - BLOB URL */\nconst fileSystemURISchemeRegex = /^((?:jar:)?file|local|blob)/im\nconst serviceAPIURISchemeRegex = /^(cloudinary|obsidian|gs|s3|grpc|pptr|tmtbff)/im\n\n/* @HINT: */\nconst blockedHosts = [\n 'widgets.amung.us',\n 'v.zilionfast.in',\n 'js.blinkadr.com',\n 'www.superfish.com',\n 'nzj.divdriver.net',\n 'istatic.datafastguru.info',\n 'widgets.amung.us',\n 'xls.searchfun.in',\n 'static.image2play.com'\n]\n\n/* @HINT: All control characters */\nconst ctrlCharactersRegex =\n /[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]/gim; /* eslint-disable-line */\n// const urlSchemeRegex = /^([^:]+):/gm\n/* @CHECK: https://datatracker.ietf.org/doc/html/rfc2397 - DATA URI */\nconst dataURIBINRegex =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|svg\\+xml)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,(?:[a-zA-Z0-9\\/+\\n=]+)$/i\nconst dataURITEXTRegex = /^data:(?:text\\/(?:javascript|html|css|plain))(?:;charset=(UTF-8|iso-8859-7))?,(?:.*)$/im\nconst scriptURIRegex = /^(?:vb|java)(?:\\s*)?script/im\nconst webTransportURIRegex = /^(?:(blob:)?https?|wss?|about|mailto|tel)/im\nconst relativeFirstCharacters = ['.', '/']\n\n/* @HINT: Global Stub for the Browser, ReactNative, NativeScript, NodeJS */\nconst $globals = typeof self === 'undefined' ? global || {} : self\n/* @HINT: Conditionally access the NodeJS process global */\nconst nodeJSProcess = $globals.process || { versions: { node: '.' }, env: {} }\nconst NODE_MAJOR_VERSION = parseInt(nodeJSProcess.versions.node.split('.')[0])\n\n/* @CHECK: https://developer.mozilla.org/en-US/docs/Web/API/URL#browser_compatibility */\nif (NODE_MAJOR_VERSION <= 12) {\n if (!$globals.URL) {\n $globals.URL = function (urlString) {\n const urlParser = require('url')\n /* urlParser.parse(): deprecarted in NodeJS v11.x */\n const parsedUrl =\n NODE_MAJOR_VERSION <= 11\n ? urlParser.parse(urlString) /* eslint-disable-line */\n : urlParser.URL(urlString)\n return Object.assign({}, parsedUrl, { hostname: parsedUrl.host })\n }\n }\n}\n\nfunction isStandardBrowserEnv () {\n const environ = $globals.navigator\n return (\n typeof environ !== 'undefined' &&\n environ.product.match(/^(ReactNative|NativeScript|NS)$/i) === null\n )\n}\n\nconst origin = isStandardBrowserEnv()\n ? $globals.location.origin\n : ($globals.constants || nodeJSProcess.env).ORIGIN\n\nfunction isRelativeUrlWithoutProtocol (url) {\n if (typeof url === 'string') {\n return relativeFirstCharacters.indexOf(url.charAt(0)) > -1\n }\n return false\n}\n\n/* @CHECK: https://gist.github.com/blafrance/4053759 */\nfunction extractParamValueFromUri (uri, paramName) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return null\n }\n\n const regex = new RegExp('[\\\\?&#]' + paramName + '=([^&#]*)')\n const params = regex.exec(uri.trim())\n if (params != null) {\n return unescape(params[1])\n }\n}\n\nfunction formDataToJSON (elem) {\n let current, item, key, output, value\n output = {}\n\n const entries =\n elem instanceof $globals.FormData\n ? elem.entries()\n : new $globals.FormData(elem).entries()\n\n try {\n // Iterate over values, and assign to item.\n while ((item = entries.next().value) !== null) {\n // assign to variables to make the code more readable.\n key = item[0]\n value = item[1]\n // Check if key already exist\n if (Object.prototype.hasOwnProperty.call(output, key)) {\n current = output[key]\n if (!Array.isArray(current)) {\n // If it's not an array, convert it to an array.\n current = output[key] = [current]\n }\n current.push(value) // Add the new value to the array.\n } else {\n output[key] = value\n }\n }\n } catch (_) {\n output = Object.fromEntries(entries)\n }\n\n return JSON.stringify(output)\n}\n\nfunction isSameOrigin (uri) {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n try {\n const parsedUrl = new $globals.URL(uri.trim())\n return origin === parsedUrl.origin\n } catch (error) {\n if (error) {\n return false\n }\n }\n}\n\nfunction checkParamsOverWhiteList (uri, paramsWhiteList = [], data = '') {\n if (!uri || dataURITEXTRegex.test(uri.trim()) || dataURIBINRegex.test(uri.trim())) {\n return false\n }\n\n if (typeof paramsWhiteList !== 'object') {\n return false\n }\n\n const parsedUrl = new $globals.URL(uri.trim())\n const paramKeys = []\n const paramValues = []\n\n let preparedData = null\n\n try {\n let json = ''\n if ('FormData' in $globals && data instanceof $globals.FormData) {\n if (typeof Object.fromEntries === 'function') {\n json = formDataToJSON(data)\n } else {\n const object = {}\n\n data.forEach(function (value, key) {\n object[key] = value\n })\n\n json = JSON.stringify(object)\n }\n } else {\n json = data\n }\n\n if (typeof json === 'string') {\n preparedData = JSON.parse(json)\n }\n } catch (_) {\n preparedData = data\n }\n\n if (preparedData === '') {\n parsedUrl.searchParams.forEach(function (...args) {\n const [value, key] = args\n\n paramValues.push(unescape(value))\n paramKeys.push(key)\n })\n } else {\n if (preparedData instanceof Object) {\n paramValues.concat(Object.values(preparedData))\n paramKeys.concat(Object.keys(preparedData))\n }\n }\n\n if (paramKeys.length === paramValues.length) {\n if (paramsWhiteList instanceof Array) {\n /* @HINT: Check that only the request params we need are attached */\n /* @HINT: Any other extra params should not be allowed */\n if (paramKeys.length === paramsWhiteList.length &&\n paramKeys.slice(0).sort().join('|') === paramsWhiteList.slice(0).sort().join('|')) {\n return true\n }\n } else if (paramsWhiteList instanceof Object) {\n let paramsCounter = 0\n for (; paramsCounter < paramKeys.length; paramsCounter++) {\n const paramKey = paramKeys[paramsCounter]\n const paramValue = paramValues[paramsCounter]\n const paramRegex = paramsWhiteList[paramKey]\n\n if (paramRegex instanceof RegExp) {\n if (!paramRegex.test(paramValue)) {\n break\n }\n } else {\n throw new Error(`\"${paramKey}\" does not have a matching regex pattern to match \"${paramValue}\"`)\n }\n }\n if (paramsCounter === paramValues.length) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * @source: https://stackoverflow.com/a/13763250\n *\n * @param {String} stringSample\n * @returns\n */\nconst hasHTMLEntity = (stringSample = '') => {\n if (typeof stringSample !== 'string') {\n return false\n }\n return /&(?:[a-z]+|#x?\\d+);/gim.test(stringSample)\n}\n\nfunction sanitizeUrl (url, options = {}) {\n if (\n !url ||\n url.match(/:\\/\\/(?:[#$@=*.!]|[/]){0,}$/) !== null ||\n url.includes('////////////') ||\n /* @TODO: URIs that contain HTML entities should be allowed and processed by decoding them in a later release (v0.0.8) of URISanity */\n hasHTMLEntity(url) /* @NOTE: This line will need to be excluded from this `if` condition */\n ) {\n return 'about:blank'\n }\n\n let sanitizedUrl = url.replace(ctrlCharactersRegex, '').trim()\n\n if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {\n const originalSanitized = sanitizedUrl.startsWith('/')\n ? origin + sanitizedUrl\n : origin + '/' + sanitizedUrl\n sanitizedUrl = safeURIRegex.test(originalSanitized)\n ? originalSanitized\n : '//'\n }\n\n let urlSchemeParseResults =\n sanitizedUrl.match(safeInternetURISchemeRegex) ||\n sanitizedUrl.match(commsAppURISchemeRegex) ||\n sanitizedUrl.match(databaseConnectionStringURISchemeRegex) ||\n sanitizedUrl.match(browserURISchemeRegex) ||\n sanitizedUrl.match(serviceAPIURISchemeRegex) ||\n sanitizedUrl.match(webTransportURIRegex)\n\n urlSchemeParseResults =\n urlSchemeParseResults !== null ? urlSchemeParseResults : []\n const urlScheme = urlSchemeParseResults[0] || ''\n\n try {\n const { hostname, pathname, search, hash } = new $globals.URL(\n sanitizedUrl.toLowerCase()\n )\n\n const matches = search.match(/\\?/g) || []\n\n if (matches.length > 1) {\n return 'about:blank'\n }\n\n /* @CHECK: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names */\n /* CHECK: https://datatracker.ietf.org/doc/html/rfc3986 */\n if (\n /^(?:((?:www|[a-z]{1,11})\\.)(?!\\1)(?:[a-z\\-\\d]{1,63})\\.(?:[a-z.\\-\\d]{2,63}))$/i.test(\n hostname\n ) ||\n /^(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(\n hostname\n ) ||\n /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/.test(\n hostname\n ) ||\n /^(?:((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@)*)/i.test(\n pathname\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n search\n ) ||\n /^((?:[a-z0-9-._~]{0,}|%[1-9a-f]?[0-9a-f]|[!$&'()*+,;=])|\\:|\\@|\\/|\\?)*$/gi.test(\n hash\n )\n ) {\n if (hostname.includes('.00') || blockedHosts.indexOf(hostname) !== -1) {\n return 'about:blank'\n }\n\n if (\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('%29') ||\n pathname.toLowerCase().includes('%28') ||\n pathname.toLowerCase().includes('%22') ||\n pathname.toLowerCase().includes('"') ||\n pathname.toLowerCase().includes(''') ||\n pathname.toLowerCase().includes('(') ||\n pathname.toLowerCase().includes(')') ||\n pathname.toLowerCase().includes('%3e') ||\n pathname.toLowerCase().includes('%3c') ||\n pathname.toLowerCase().includes('><') ||\n pathname.toLowerCase().includes('<') + pathname.toLowerCase().includes('><') || + pathname.toLowerCase().includes(' { expect(sanitizedUrl).toEqual('blob:https://www.good.foo.com/9f368042-bf23-42b6-b07c-54189d3b0e01') }); + test('PDF file path URI passes flag option', () => { + const sanitizedUrl = URISanity.vet('https://www.business-site.com/housefs/3.%20User%20Documents/0Benefits%20Guide.pdf', { + allowScriptOrDataURI: true, + allowFileSystemURI: true, + allowCommsAppURI: true, + allowDBConnectionStringURI: true, + allowBrowserSpecificURI: true, + allowWebTransportURI: true, + allowServiceAPIURI: true, + }) + + expect(sanitizedUrl).toBe('https://www.business-site.com/housefs/3.%20User%20Documents/0Benefits%20Guide.pdf') + }) + test('mailto URI passes flag option', () => { const sanitizedUrl = URISanity.vet('mailto:hello@example.com', { allowWebTransportURI: true diff --git a/types/index.d.ts b/types/index.d.ts index 37dc8ee..f2bb35a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for urisanity v0.1.5 +// Type definitions for urisanity v0.1.6 // Project: https://github.com/codesplinta/URISanity declare module 'urisanity' { From 9144b68ffdc8baddfd811cbad41b744d20d604b4 Mon Sep 17 00:00:00 2001 From: Okechukwu Ifeora Patrick Date: Thu, 19 Sep 2024 02:18:02 +0100 Subject: [PATCH 5/5] fix: release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df9c9d0..b6db049 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "urisanity", "description": "vet URIs in web and web-like applications with confidence", - "version": "0.1.5", + "version": "0.1.6", "main": "dist/urisanity.cjs.js", "module": "dist/urisanity.es.js", "browser": "dist/urisanity.js",