url-sanitizer 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/url-sanitizer.js +43 -43
- package/dist/url-sanitizer.js.map +3 -3
- package/dist/url-sanitizer.min.js +9 -3
- package/dist/url-sanitizer.min.js.map +4 -4
- package/package.json +11 -10
- package/src/index.js +11 -0
- package/src/mjs/uri-util.js +47 -56
- package/index.js +0 -8
- package/src/mjs/dompurify.esm.js +0 -5
package/README.md
CHANGED
|
@@ -82,11 +82,13 @@ const res4 = await sanitizeURL(`data:text/html;base64,${base64data4}`);
|
|
|
82
82
|
console.log(decodeURIComponent(res4));
|
|
83
83
|
// => 'data:text/html,<div></div>'
|
|
84
84
|
|
|
85
|
+
// Deny if the scheme matches the `deny` list
|
|
85
86
|
const res5 = await sanitizeURL('web+foo://example.com', {
|
|
86
87
|
deny: ['web+foo']
|
|
87
88
|
});
|
|
88
89
|
// => null
|
|
89
90
|
|
|
91
|
+
// Allow only if the scheme matches the `only` list
|
|
90
92
|
const res6 = await sanitizeURL('http://example.com', {
|
|
91
93
|
only: ['data', 'git', 'https']
|
|
92
94
|
});
|
|
@@ -100,7 +102,7 @@ const res7 = await sanitizeURL('https://example.com/"onmouseover="alert(1)"', {
|
|
|
100
102
|
console.log(decodeURIComponent(res7));
|
|
101
103
|
// => 'https://example.com/"onmouseover="alert(1)"'
|
|
102
104
|
|
|
103
|
-
// `only`
|
|
105
|
+
// `only` also allows combination of the schemes in the list
|
|
104
106
|
const res8 = await sanitizeURL('git+https://example.com/foo.git?<script>alert(1)</script>', {
|
|
105
107
|
only: ['data', 'git', 'https']
|
|
106
108
|
});
|
|
@@ -128,7 +130,7 @@ Returns **[Promise][5]<[ParsedURL](#parsedurl)>** Result.
|
|
|
128
130
|
|
|
129
131
|
### ParsedURL
|
|
130
132
|
|
|
131
|
-
Object with
|
|
133
|
+
Object with enhanced properties based on [URL](https://developer.mozilla.org/ja/docs/Web/API/URL) API.
|
|
132
134
|
|
|
133
135
|
Type: [object][3]
|
|
134
136
|
|
|
@@ -150,7 +152,6 @@ Type: [object][3]
|
|
|
150
152
|
* `port` **[string][1]** Port number of the sanitized URL.
|
|
151
153
|
* `pathname` **[string][1]** Path of the sanitized URL.
|
|
152
154
|
* `search` **[string][1]** Query string of the sanitized URL.
|
|
153
|
-
* `searchParams` **[object][3]** [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object.
|
|
154
155
|
* `hash` **[string][1]** Fragment identifier of the sanitized URL.
|
|
155
156
|
|
|
156
157
|
```javascript
|
|
@@ -218,7 +219,7 @@ Synchronous version of the [parseURL()](#parseURL).
|
|
|
218
219
|
|
|
219
220
|
## isURI(uri)
|
|
220
221
|
|
|
221
|
-
|
|
222
|
+
Verify if the given URI is valid.
|
|
222
223
|
|
|
223
224
|
### Parameters
|
|
224
225
|
|
package/dist/url-sanitizer.js
CHANGED
|
@@ -998,16 +998,16 @@ var require_purify = __commonJS({
|
|
|
998
998
|
}
|
|
999
999
|
});
|
|
1000
1000
|
|
|
1001
|
-
// bundle/
|
|
1001
|
+
// bundle/mjs/common.js
|
|
1002
1002
|
var TYPE_FROM = 8;
|
|
1003
1003
|
var TYPE_TO = -1;
|
|
1004
1004
|
var getType = (o) => Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
|
|
1005
1005
|
var isString = (o) => typeof o === "string" || o instanceof String;
|
|
1006
1006
|
|
|
1007
|
-
// bundle/
|
|
1007
|
+
// bundle/mjs/dompurify.js
|
|
1008
1008
|
var import_dompurify = __toESM(require_purify(), 1);
|
|
1009
1009
|
|
|
1010
|
-
// bundle/
|
|
1010
|
+
// bundle/lib/file/text-chars.json
|
|
1011
1011
|
var text_chars_default = [
|
|
1012
1012
|
7,
|
|
1013
1013
|
8,
|
|
@@ -1242,7 +1242,7 @@ var text_chars_default = [
|
|
|
1242
1242
|
255
|
|
1243
1243
|
];
|
|
1244
1244
|
|
|
1245
|
-
// bundle/
|
|
1245
|
+
// bundle/lib/iana/uri-schemes.json
|
|
1246
1246
|
var uri_schemes_default = [
|
|
1247
1247
|
"aaa",
|
|
1248
1248
|
"aaas",
|
|
@@ -1592,14 +1592,14 @@ var uri_schemes_default = [
|
|
|
1592
1592
|
"z39.50s"
|
|
1593
1593
|
];
|
|
1594
1594
|
|
|
1595
|
-
// bundle/
|
|
1595
|
+
// bundle/mjs/uri-util.js
|
|
1596
1596
|
var HEX = 16;
|
|
1597
1597
|
var REG_BASE64 = /^[\da-z+/\-_=]+$/i;
|
|
1598
1598
|
var REG_DATA_URL = /data:[^,]*,[^"]+/g;
|
|
1599
1599
|
var REG_DATA_URL_BASE64 = /data:[^,]*;?base64,[\da-z+/\-_=]+/i;
|
|
1600
|
-
var REG_MIME_DOM = /^(?:text\/(?:ht|x)ml|application\/(?:xhtml\+)?xml|image\/svg\+xml)/;
|
|
1601
1600
|
var REG_HTML_SP = /[<>"'\s]/g;
|
|
1602
1601
|
var REG_HTML_SP_URL_ENC = /%(?:2(?:2|7)|3(?:C|E))/g;
|
|
1602
|
+
var REG_MIME_DOM = /^(?:text\/(?:ht|x)ml|application\/(?:xhtml\+)?xml|image\/svg\+xml)/;
|
|
1603
1603
|
var REG_NUM_REF = /&#(x(?:00)?[\dA-F]{2}|0?\d{1,3});?/ig;
|
|
1604
1604
|
var REG_SCHEME = /^[a-z][\da-z+\-.]*$/;
|
|
1605
1605
|
var REG_SCHEME_CUSTOM = /^(?:ext|web)\+[a-z]+$/;
|
|
@@ -1607,7 +1607,7 @@ var REG_SCRIPT = /(?:java|vb)script/;
|
|
|
1607
1607
|
var REG_URL_ENC = /^%[\dA-F]{2}$/i;
|
|
1608
1608
|
var REG_URL_ENC_AMP = /%26/g;
|
|
1609
1609
|
var REG_URL_ENC_HTML_SP = /%26(?:(?:l|g|quo)t|%2339);?/g;
|
|
1610
|
-
var
|
|
1610
|
+
var getURLEncodedString = (str) => {
|
|
1611
1611
|
if (!isString(str)) {
|
|
1612
1612
|
throw new TypeError(`Expected String but got ${getType(str)}.`);
|
|
1613
1613
|
}
|
|
@@ -1617,17 +1617,11 @@ var getUrlEncodedString = (str) => {
|
|
|
1617
1617
|
}
|
|
1618
1618
|
return chars.join("");
|
|
1619
1619
|
};
|
|
1620
|
-
var
|
|
1621
|
-
if (isString(ch)) {
|
|
1622
|
-
|
|
1623
|
-
ch = ch.toUpperCase();
|
|
1624
|
-
} else {
|
|
1625
|
-
throw new Error(`Invalid URL encoded character: ${ch}`);
|
|
1626
|
-
}
|
|
1627
|
-
} else {
|
|
1628
|
-
throw new TypeError(`Expected String but got ${getType(ch)}.`);
|
|
1620
|
+
var escapeURLEncodedHTMLChars = (ch) => {
|
|
1621
|
+
if (isString(ch) && REG_URL_ENC.test(ch)) {
|
|
1622
|
+
ch = ch.toUpperCase();
|
|
1629
1623
|
}
|
|
1630
|
-
const [amp, num, lt, gt, quot, apos] = ["&", "#", "<", ">", '"', "'"].map(
|
|
1624
|
+
const [amp, num, lt, gt, quot, apos] = ["&", "#", "<", ">", '"', "'"].map(getURLEncodedString);
|
|
1631
1625
|
let escapedChar;
|
|
1632
1626
|
if (ch === amp) {
|
|
1633
1627
|
escapedChar = `${amp}amp;`;
|
|
@@ -1644,7 +1638,7 @@ var escapeUrlEncodedHtmlChars = (ch) => {
|
|
|
1644
1638
|
}
|
|
1645
1639
|
return escapedChar;
|
|
1646
1640
|
};
|
|
1647
|
-
var
|
|
1641
|
+
var unescapeURLEncodedHTMLChars = (ch) => {
|
|
1648
1642
|
let unescapedChar;
|
|
1649
1643
|
if (/%26lt;?/.test(ch)) {
|
|
1650
1644
|
unescapedChar = "<";
|
|
@@ -1670,13 +1664,13 @@ var parseBase64 = (data) => {
|
|
|
1670
1664
|
const textCharCodes = new Set(text_chars_default);
|
|
1671
1665
|
let parsedData;
|
|
1672
1666
|
if (uint8arr.every((c) => textCharCodes.has(c))) {
|
|
1673
|
-
parsedData = bin.replace(/\s/g,
|
|
1667
|
+
parsedData = bin.replace(/\s/g, getURLEncodedString);
|
|
1674
1668
|
} else {
|
|
1675
1669
|
parsedData = data;
|
|
1676
1670
|
}
|
|
1677
1671
|
return parsedData;
|
|
1678
1672
|
};
|
|
1679
|
-
var
|
|
1673
|
+
var parseURLEncodedNumCharRef = (str, nest = 0) => {
|
|
1680
1674
|
if (!isString(str)) {
|
|
1681
1675
|
throw new TypeError(`Expected String but got ${getType(str)}.`);
|
|
1682
1676
|
}
|
|
@@ -1706,7 +1700,7 @@ var parseUrlEncodedNumCharRef = (str, nest = 0) => {
|
|
|
1706
1700
|
if (textCharCodes.has(num)) {
|
|
1707
1701
|
res = `${preNum}${String.fromCharCode(num)}${postNum}`;
|
|
1708
1702
|
if (/#x?$/.test(preNum) || /^#(?:x(?:00)?[2-7]|\d)/.test(postNum)) {
|
|
1709
|
-
res =
|
|
1703
|
+
res = parseURLEncodedNumCharRef(res, ++nest);
|
|
1710
1704
|
}
|
|
1711
1705
|
} else if (num < HEX * HEX) {
|
|
1712
1706
|
res = `${preNum}${postNum}`;
|
|
@@ -1716,7 +1710,7 @@ var parseUrlEncodedNumCharRef = (str, nest = 0) => {
|
|
|
1716
1710
|
}
|
|
1717
1711
|
return res;
|
|
1718
1712
|
};
|
|
1719
|
-
var
|
|
1713
|
+
var purifyURLEncodedDOM = (dom) => {
|
|
1720
1714
|
if (!isString(dom)) {
|
|
1721
1715
|
throw new TypeError(`Expected String but got ${getType(dom)}.`);
|
|
1722
1716
|
}
|
|
@@ -1777,12 +1771,12 @@ var URISchemes = class {
|
|
|
1777
1771
|
return this.#schemes.delete(scheme);
|
|
1778
1772
|
}
|
|
1779
1773
|
/**
|
|
1780
|
-
*
|
|
1774
|
+
* verify URI
|
|
1781
1775
|
*
|
|
1782
1776
|
* @param {string} uri - URI input
|
|
1783
1777
|
* @returns {boolean} - result
|
|
1784
1778
|
*/
|
|
1785
|
-
|
|
1779
|
+
verify(uri) {
|
|
1786
1780
|
let res;
|
|
1787
1781
|
if (isString(uri)) {
|
|
1788
1782
|
try {
|
|
@@ -1896,7 +1890,7 @@ var URLSanitizer = class extends URISchemes {
|
|
|
1896
1890
|
}
|
|
1897
1891
|
}
|
|
1898
1892
|
let sanitizedUrl;
|
|
1899
|
-
if (super.
|
|
1893
|
+
if (super.verify(url)) {
|
|
1900
1894
|
const { hash, href, pathname, protocol, search } = new URL(url);
|
|
1901
1895
|
const scheme = protocol.replace(/:$/, "");
|
|
1902
1896
|
const schemeParts = scheme.split("+");
|
|
@@ -1924,7 +1918,7 @@ var URLSanitizer = class extends URISchemes {
|
|
|
1924
1918
|
parsedData = parseBase64(data);
|
|
1925
1919
|
} else {
|
|
1926
1920
|
try {
|
|
1927
|
-
const decodedData =
|
|
1921
|
+
const decodedData = parseURLEncodedNumCharRef(parsedData);
|
|
1928
1922
|
const { protocol: dataScheme } = new URL(decodedData.trim());
|
|
1929
1923
|
const dataSchemeParts = dataScheme.replace(/:$/, "").split("+");
|
|
1930
1924
|
if (dataSchemeParts.some((s) => REG_SCRIPT.test(s))) {
|
|
@@ -1977,9 +1971,9 @@ var URLSanitizer = class extends URISchemes {
|
|
|
1977
1971
|
escapeHtml = true;
|
|
1978
1972
|
}
|
|
1979
1973
|
if (urlToSanitize) {
|
|
1980
|
-
sanitizedUrl = urlToSanitize.replace(REG_HTML_SP,
|
|
1974
|
+
sanitizedUrl = urlToSanitize.replace(REG_HTML_SP, getURLEncodedString).replace(REG_URL_ENC_AMP, escapeURLEncodedHTMLChars);
|
|
1981
1975
|
if (escapeHtml) {
|
|
1982
|
-
sanitizedUrl = sanitizedUrl.replace(REG_HTML_SP_URL_ENC,
|
|
1976
|
+
sanitizedUrl = sanitizedUrl.replace(REG_HTML_SP_URL_ENC, escapeURLEncodedHTMLChars);
|
|
1983
1977
|
this.#nest = 0;
|
|
1984
1978
|
}
|
|
1985
1979
|
} else {
|
|
@@ -2018,7 +2012,7 @@ var URLSanitizer = class extends URISchemes {
|
|
|
2018
2012
|
*
|
|
2019
2013
|
* @param {string} url - URL input
|
|
2020
2014
|
* @param {object} opt - options
|
|
2021
|
-
* @returns {ParsedURL} - result with
|
|
2015
|
+
* @returns {ParsedURL} - result with enhanced props based on URL API
|
|
2022
2016
|
*/
|
|
2023
2017
|
parse(url, opt) {
|
|
2024
2018
|
if (!isString(url)) {
|
|
@@ -2058,10 +2052,10 @@ var URLSanitizer = class extends URISchemes {
|
|
|
2058
2052
|
parsedData.substring(0, index),
|
|
2059
2053
|
parsedData.substring(index + htmlChar.length)
|
|
2060
2054
|
];
|
|
2061
|
-
const unescapedHTMLChar =
|
|
2055
|
+
const unescapedHTMLChar = unescapeURLEncodedHTMLChars(htmlChar);
|
|
2062
2056
|
parsedData = `${preHtmlChar}${unescapedHTMLChar}${postHtmlChar}`;
|
|
2063
2057
|
}
|
|
2064
|
-
purifiedDom =
|
|
2058
|
+
purifiedDom = purifyURLEncodedDOM(parsedData);
|
|
2065
2059
|
dataUrl.set("data", purifiedDom);
|
|
2066
2060
|
} else {
|
|
2067
2061
|
dataUrl.set("data", data);
|
|
@@ -2100,12 +2094,17 @@ var URLSanitizer = class extends URISchemes {
|
|
|
2100
2094
|
}
|
|
2101
2095
|
};
|
|
2102
2096
|
var urlSanitizer = new URLSanitizer();
|
|
2103
|
-
var
|
|
2097
|
+
var isURISync = (uri) => urlSanitizer.verify(uri);
|
|
2104
2098
|
var isURI = async (uri) => {
|
|
2105
|
-
const res = await
|
|
2099
|
+
const res = await isURISync(uri);
|
|
2106
2100
|
return res;
|
|
2107
2101
|
};
|
|
2108
|
-
var
|
|
2102
|
+
var parseURLSync = (url) => urlSanitizer.parse(url);
|
|
2103
|
+
var parseURL = async (url) => {
|
|
2104
|
+
const res = await parseURLSync(url);
|
|
2105
|
+
return res;
|
|
2106
|
+
};
|
|
2107
|
+
var sanitizeURLSync = (url, opt) => {
|
|
2109
2108
|
const parsedUrl = urlSanitizer.parse(url, opt ?? {
|
|
2110
2109
|
allow: [],
|
|
2111
2110
|
deny: [],
|
|
@@ -2119,23 +2118,24 @@ var sanitizeUrl = (url, opt) => {
|
|
|
2119
2118
|
return res ?? null;
|
|
2120
2119
|
};
|
|
2121
2120
|
var sanitizeURL = async (url, opt) => {
|
|
2122
|
-
const res = await
|
|
2123
|
-
return res;
|
|
2124
|
-
};
|
|
2125
|
-
var parseUrl = (url) => urlSanitizer.parse(url);
|
|
2126
|
-
var parseURL = async (url) => {
|
|
2127
|
-
const res = await parseUrl(url);
|
|
2121
|
+
const res = await sanitizeURLSync(url, opt);
|
|
2128
2122
|
return res;
|
|
2129
2123
|
};
|
|
2130
2124
|
export {
|
|
2131
2125
|
urlSanitizer as default,
|
|
2132
2126
|
isURI,
|
|
2133
|
-
|
|
2127
|
+
isURISync,
|
|
2134
2128
|
parseURL,
|
|
2135
|
-
|
|
2129
|
+
parseURLSync,
|
|
2136
2130
|
sanitizeURL,
|
|
2137
|
-
|
|
2131
|
+
sanitizeURLSync
|
|
2138
2132
|
};
|
|
2133
|
+
/*!
|
|
2134
|
+
* URL Sanitizer
|
|
2135
|
+
* @license MIT
|
|
2136
|
+
* @copyright asamuzaK (Kazz)
|
|
2137
|
+
* @see {@link https://github.com/asamuzaK/urlSanitizer/blob/main/LICENSE}
|
|
2138
|
+
*/
|
|
2139
2139
|
/*! Bundled license information:
|
|
2140
2140
|
|
|
2141
2141
|
dompurify/dist/purify.js:
|