[DRVWEB-4373] Add Suggestion Mode spotlight onboarding modal for docs on drive
[ProtonMail-WebClient.git] / packages / pass / utils / url / sanitize.spec.ts
blobfb928466fe7cd82978dca3d7386a1e081696a55c
1 import { sanitizeURL } from './sanitize';
2 import { MAX_HOSTNAME_LENGTH, UNSUPPORTED_SCHEMES, intoCleanHostname, intoDomainImageHostname } from './utils';
4 const VALID_SCHEMES = ['http:', 'https:', 'ftp:', 'ssh:', 'telnet:', 'irc:', 'magnet:'];
6 describe('URL validation', () => {
7     describe('`isValidURL`', () => {
8         test('should try to append `https://` when scheme is missing', () => {
9             const { valid, url } = sanitizeURL('google.com');
10             expect(valid).toBe(true);
11             expect(url).toEqual('https://google.com/');
12         });
14         test('should auto-fix scheme through URL constructor', () => {
15             const { valid, url } = sanitizeURL('https:/proton.me');
16             expect(valid).toBe(true);
17             expect(url).toEqual('https://proton.me/');
18         });
20         test('should invalidate unsupported schemes', () => {
21             UNSUPPORTED_SCHEMES.forEach((scheme) => {
22                 expect(sanitizeURL(`${scheme}someurl`).valid).toBe(false);
23                 expect(sanitizeURL(`${scheme}/someurl`).valid).toBe(false);
24                 expect(sanitizeURL(`${scheme}//someurl`).valid).toBe(false);
25                 expect(sanitizeURL('someurl', scheme).valid).toBe(false);
26                 expect(sanitizeURL('someurl', `${scheme}/`).valid).toBe(false);
27                 expect(sanitizeURL('someurl', `${scheme}//`).valid).toBe(false);
28             });
29         });
31         test('should invalidate URLs over `MAX_HOSTNAME_LENGTH`', () => {
32             const url = `https://${'a'.repeat(MAX_HOSTNAME_LENGTH + 1)}.com`;
33             expect(sanitizeURL(url).valid).toBe(false);
34         });
36         test('should accept any valid scheme', () => {
37             VALID_SCHEMES.forEach((scheme) => {
38                 expect(sanitizeURL(`${scheme}someurl`).valid).toBe(true);
39                 expect(sanitizeURL(`${scheme}//someurl`).valid).toBe(true);
40                 expect(sanitizeURL('someurl', scheme).valid).toBe(true);
41                 expect(sanitizeURL('someurl', scheme).valid).toBe(true);
42             });
43         });
45         test('should keep `www` in URL if present', () => {
46             expect(sanitizeURL('www.proton.me').url).toEqual('https://www.proton.me/');
47             expect(sanitizeURL('https://www.proton.me').url).toEqual('https://www.proton.me/');
48             expect(sanitizeURL('https://www.proton.me/').url).toEqual('https://www.proton.me/');
49             expect(sanitizeURL('www.proton.me/login').url).toEqual('https://www.proton.me/login');
50         });
52         test('should preserve query strings and full path', () => {
53             expect(sanitizeURL('proton.me/login/?foo=bar').url).toEqual('https://proton.me/login/?foo=bar');
54             expect(sanitizeURL('proton.me/login/?foo=bar', 'wss:').url).toEqual('wss://proton.me/login/?foo=bar');
55             expect(sanitizeURL('https://proton.me/login/?foo=bar').url).toEqual('https://proton.me/login/?foo=bar');
56         });
58         test('should preserve ports', () => {
59             expect(sanitizeURL('http://localhost:3000').url).toEqual('http://localhost:3000/');
60             expect(sanitizeURL('https://localhost:3001?foo=bar').url).toEqual('https://localhost:3001/?foo=bar');
61         });
63         test('should invalidate URLs containing internal white-spaces', () => {
64             expect(sanitizeURL('https://www.proton    .me').valid).toBe(false);
65             expect(sanitizeURL('proton.me  /').valid).toBe(false);
66             expect(sanitizeURL('www.proton.me/foo/   ?bar=10').valid).toBe(false);
68             expect(sanitizeURL('proton.me  ').valid).toBe(true);
69             expect(sanitizeURL('www.proton.me/foo/   ').valid).toBe(true);
70         });
71     });
73     describe('`intoCleanHostname', () => {
74         test('should return null for invalid URLs', () => {
75             expect(intoCleanHostname('https://www.proton    .me')).toBe(null);
76             expect(intoCleanHostname('www.proton.me/foo/   ?bar=10')).toBe(null);
77             expect(intoCleanHostname('//')).toBe(null);
78         });
80         test('should remove leading `www.`', () => {
81             expect(intoCleanHostname('proton.me')).toEqual('proton.me');
82             expect(intoCleanHostname('www.proton.me')).toEqual('proton.me');
83             expect(intoCleanHostname('www.proton.me/')).toEqual('proton.me');
84             expect(intoCleanHostname('foo.www.proton.me/')).toEqual('foo.www.proton.me');
85         });
86     });
88     describe('`intoDomainImageHostname`', () => {
89         test('should remove leading `www.`', () => {
90             expect(intoDomainImageHostname('proton.me')).toEqual('proton.me');
91             expect(intoDomainImageHostname('www.proton.me')).toEqual('proton.me');
92             expect(intoDomainImageHostname('www.proton.me/')).toEqual('proton.me');
93             expect(intoDomainImageHostname('foo.www.proton.me/')).toEqual('foo.www.proton.me');
94         });
96         test('should return null for invalid URLs', () => {
97             expect(intoDomainImageHostname('https://www.proton    .me')).toBe(null);
98             expect(intoDomainImageHostname('www.proton.me/foo/   ?bar=10')).toBe(null);
99             expect(intoDomainImageHostname('//')).toBe(null);
100         });
102         test.each([
103             'alt',
104             'invalid',
105             'intranet',
106             'internal',
107             'private',
108             'corp',
109             'home',
110             'lan',
111             'local',
112             'localhost',
113             'example',
114         ])('`%s` should return null [reserved]', (hostname) => {
115             expect(intoDomainImageHostname(hostname)).toBe(null);
116         });
118         test.each([
119             '6tisch.arpa',
120             '10.in-addr.arpa',
121             '16.172.in-addr.arpa',
122             '17.172.in-addr.arpa',
123             'proton.onion',
124             'example.com',
125             'localhost.local',
126         ])('`%s` should return null [non-ICANN]', (hostname) => {
127             expect(intoDomainImageHostname(hostname)).toBe(null);
128             expect(intoDomainImageHostname(`${hostname}:3000`)).toBe(null);
129         });
131         test.each([
132             '6tisch.arpa',
133             '10.in-addr.arpa',
134             '16.172.in-addr.arpa',
135             '17.172.in-addr.arpa',
136             'proton.onion',
137             'example.com',
138             'localhost.local',
139             'xn--bcher-kva.example',
140         ])('`%s` should return null [non-ICANN]', (hostname) => {
141             expect(intoDomainImageHostname(hostname)).toBe(null);
142             expect(intoDomainImageHostname(`${hostname}:3000`)).toBe(null);
143             expect(intoDomainImageHostname(`sub.${hostname}`)).toBe(null);
144             expect(intoDomainImageHostname(`sub.${hostname}:3000`)).toBe(null);
145         });
147         test.each([
148             '192.168.23.145',
149             '10.45.178.209',
150             '172.16.87.231',
151             '203.0.113.42',
152             '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
153             'fe80:0000:0000:0000:0202:b3ff:fe1e:8329',
154             '0.0.0',
155             '0.0',
156             '0',
157         ])('`%s` should return null [IP]', (hostname) => {
158             expect(intoDomainImageHostname(hostname)).toBe(null);
159         });
160     });