source: node_modules/@braintree/sanitize-url/src/__tests__/index.test.ts@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/* eslint-disable no-script-url */
2import { sanitizeUrl } from "..";
3import { BLANK_URL } from "../constants";
4
5describe("sanitizeUrl", () => {
6 it("does not alter http URLs with alphanumeric characters", () => {
7 expect(sanitizeUrl("http://example.com/path/to:something")).toBe(
8 "http://example.com/path/to:something"
9 );
10 });
11
12 it("does not alter http URLs with ports with alphanumeric characters", () => {
13 expect(sanitizeUrl("http://example.com:4567/path/to:something")).toBe(
14 "http://example.com:4567/path/to:something"
15 );
16 });
17
18 it("does not alter https URLs with alphanumeric characters", () => {
19 expect(sanitizeUrl("https://example.com")).toBe("https://example.com");
20 });
21
22 it("does not alter https URLs with ports with alphanumeric characters", () => {
23 expect(sanitizeUrl("https://example.com:4567/path/to:something")).toBe(
24 "https://example.com:4567/path/to:something"
25 );
26 });
27
28 it("does not alter relative-path reference URLs with alphanumeric characters", () => {
29 expect(sanitizeUrl("./path/to/my.json")).toBe("./path/to/my.json");
30 });
31
32 it("does not alter absolute-path reference URLs with alphanumeric characters", () => {
33 expect(sanitizeUrl("/path/to/my.json")).toBe("/path/to/my.json");
34 });
35
36 it("does not alter protocol-less network-path URLs with alphanumeric characters", () => {
37 expect(sanitizeUrl("//google.com/robots.txt")).toBe(
38 "//google.com/robots.txt"
39 );
40 });
41
42 it("does not alter protocol-less URLs with alphanumeric characters", () => {
43 expect(sanitizeUrl("www.example.com")).toBe("www.example.com");
44 });
45
46 it("does not alter deep-link urls with alphanumeric characters", () => {
47 expect(sanitizeUrl("com.braintreepayments.demo://example")).toBe(
48 "com.braintreepayments.demo://example"
49 );
50 });
51
52 it("does not alter mailto urls with alphanumeric characters", () => {
53 expect(sanitizeUrl("mailto:test@example.com?subject=hello+world")).toBe(
54 "mailto:test@example.com?subject=hello+world"
55 );
56 });
57
58 it("does not alter urls with accented characters", () => {
59 expect(sanitizeUrl("www.example.com/with-áccêntš")).toBe(
60 "www.example.com/with-áccêntš"
61 );
62 });
63
64 it("does not strip harmless unicode characters", () => {
65 expect(sanitizeUrl("www.example.com/лот.рфшишкиü–")).toBe(
66 "www.example.com/лот.рфшишкиü–"
67 );
68 });
69
70 it("strips out ctrl chars", () => {
71 expect(
72 sanitizeUrl("www.example.com/\u200D\u0000\u001F\x00\x1F\uFEFFfoo")
73 ).toBe("www.example.com/foo");
74 });
75
76 it(`replaces blank urls with ${BLANK_URL}`, () => {
77 expect(sanitizeUrl("")).toBe(BLANK_URL);
78 });
79
80 it(`replaces null values with ${BLANK_URL}`, () => {
81 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
82 // @ts-ignore
83 expect(sanitizeUrl(null)).toBe(BLANK_URL);
84 });
85
86 it(`replaces undefined values with ${BLANK_URL}`, () => {
87 expect(sanitizeUrl()).toBe(BLANK_URL);
88 });
89
90 it("removes whitespace from urls", () => {
91 expect(sanitizeUrl(" http://example.com/path/to:something ")).toBe(
92 "http://example.com/path/to:something"
93 );
94 });
95
96 it("removes newline entities from urls", () => {
97 expect(sanitizeUrl("https://example.com&NewLine;&NewLine;/something")).toBe(
98 "https://example.com/something"
99 );
100 });
101
102 it("decodes html entities", () => {
103 // all these decode to javascript:alert('xss');
104 const attackVectors = [
105 "&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041",
106 "&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;",
107 "&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29",
108 "jav&#x09;ascript:alert('XSS');",
109 " &#14; javascript:alert('XSS');",
110 "javasc&Tab;ript: alert('XSS');",
111 "javasc&#\u0000x09;ript:alert(1)",
112 ];
113
114 attackVectors.forEach((vector) => {
115 expect(sanitizeUrl(vector)).toBe(BLANK_URL);
116 });
117
118 // https://example.com/javascript:alert('XSS')
119 // since the javascript is the url path, and not the protocol,
120 // this url is technically sanitized
121 expect(
122 sanitizeUrl(
123 "&#104;&#116;&#116;&#112;&#115;&#0000058//&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;/&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041"
124 )
125 ).toBe("https://example.com/javascript:alert('XSS')");
126 });
127
128 describe("invalid protocols", () => {
129 describe.each(["javascript", "data", "vbscript"])("%s", (protocol) => {
130 it(`replaces ${protocol} urls with ${BLANK_URL}`, () => {
131 expect(sanitizeUrl(`${protocol}:alert(document.domain)`)).toBe(
132 BLANK_URL
133 );
134 });
135
136 it(`allows ${protocol} urls that start with a letter prefix`, () => {
137 expect(sanitizeUrl(`not_${protocol}:alert(document.domain)`)).toBe(
138 `not_${protocol}:alert(document.domain)`
139 );
140 });
141
142 it(`disallows ${protocol} urls that start with non-\w characters as a suffix for the protocol`, () => {
143 expect(sanitizeUrl(`&!*${protocol}:alert(document.domain)`)).toBe(
144 BLANK_URL
145 );
146 });
147
148 it(`disallows ${protocol} urls that use &colon; for the colon portion of the url`, () => {
149 expect(sanitizeUrl(`${protocol}&colon;alert(document.domain)`)).toBe(
150 BLANK_URL
151 );
152 expect(sanitizeUrl(`${protocol}&COLON;alert(document.domain)`)).toBe(
153 BLANK_URL
154 );
155 });
156
157 it(`disregards capitalization for ${protocol} urls`, () => {
158 // upper case every other letter in protocol name
159 const mixedCapitalizationProtocol = protocol
160 .split("")
161 .map((character, index) => {
162 if (index % 2 === 0) {
163 return character.toUpperCase();
164 }
165 return character;
166 })
167 .join("");
168
169 expect(
170 sanitizeUrl(`${mixedCapitalizationProtocol}:alert(document.domain)`)
171 ).toBe(BLANK_URL);
172 });
173
174 it(`ignores invisible ctrl characters in ${protocol} urls`, () => {
175 const protocolWithControlCharacters = protocol
176 .split("")
177 .map((character, index) => {
178 if (index === 1) {
179 return character + "%EF%BB%BF%EF%BB%BF";
180 } else if (index === 2) {
181 return character + "%e2%80%8b";
182 }
183 return character;
184 })
185 .join("");
186
187 expect(
188 sanitizeUrl(
189 decodeURIComponent(
190 `${protocolWithControlCharacters}:alert(document.domain)`
191 )
192 )
193 ).toBe(BLANK_URL);
194 });
195
196 it(`replaces ${protocol} urls with ${BLANK_URL} when url begins with %20`, () => {
197 expect(
198 sanitizeUrl(
199 decodeURIComponent(`%20%20%20%20${protocol}:alert(document.domain)`)
200 )
201 ).toBe(BLANK_URL);
202 });
203
204 it(`replaces ${protocol} urls with ${BLANK_URL} when ${protocol} url begins with spaces`, () => {
205 expect(sanitizeUrl(` ${protocol}:alert(document.domain)`)).toBe(
206 BLANK_URL
207 );
208 });
209
210 it(`does not replace ${protocol}: if it is not in the scheme of the URL`, () => {
211 expect(sanitizeUrl(`http://example.com#${protocol}:foo`)).toBe(
212 `http://example.com#${protocol}:foo`
213 );
214 });
215 });
216 });
217});
Note: See TracBrowser for help on using the repository browser.