Project

General

Profile

« Previous | Next » 

Revision 53837634

Added by koszko about 2 years ago

enable whitelisting of `file://' protocol\n\nThis commit additionally also changes the semantics of triple asterisk wildcard in URL path.

View differences:

common/patterns.js
5 5
 * Redistribution terms are gathered in the `copyright' file.
6 6
 */
7 7

  
8
const proto_re = "[a-zA-Z]*:\/\/";
8
const proto_regex = /^(\w+):\/\/(.*)$/;
9

  
9 10
const domain_re = "[^/?#]+";
10
const segments_re = "/[^?#]*";
11
const query_re = "\\?[^#]*";
12

  
13
const url_regex = new RegExp(`\
14
^\
15
(${proto_re})\
16
(${domain_re})\
17
(${segments_re})?\
18
(${query_re})?\
19
#?.*\$\
20
`);
11
const path_re = "[^?#]*";
12
const query_re = "\\??[^#]*";
13

  
14
const http_regex = new RegExp(`^(${domain_re})(${path_re})(${query_re}).*`);
15

  
16
const file_regex = new RegExp(`^(${path_re}).*`);
21 17

  
22 18
function deconstruct_url(url)
23 19
{
24
    const regex_match = url_regex.exec(url);
25
    if (regex_match === null)
20
    const proto_match = proto_regex.exec(url);
21
    if (proto_match === null)
26 22
	return undefined;
27 23

  
28
    let [_, proto, domain, path, query] = regex_match;
24
    const deco = {proto: proto_match[1]};
29 25

  
30
    domain = domain.split(".");
31
    let path_trailing_dash =
32
	path && path[path.length - 1] === "/";
33
    path = (path || "").split("/").filter(s => s !== "");
34
    path.unshift("");
26
    if (deco.proto === "file") {
27
	deco.path = file_regex.exec(proto_match[2])[1];
28
    } else {
29
	const http_match = http_regex.exec(proto_match[2]);
30
	if (!http_match)
31
	    return undefined;
32
	[deco.domain, deco.path, deco.query] = http_match.slice(1, 4);
33
	deco.domain = deco.domain.split(".");
34
    }
35 35

  
36
    return {proto, domain, path, query, path_trailing_dash};
36
    const leading_dash = deco.path[0] === "/";
37
    deco.trailing_dash = deco.path[deco.path.length - 1] === "/";
38
    deco.path = deco.path.split("/").filter(s => s !== "");
39
    if (leading_dash || deco.path.length === 0)
40
	deco.path.unshift("");
41

  
42
    return deco;
37 43
}
38 44

  
39 45
/* Be sane: both arguments should be arrays of length >= 2 */
......
104 110
	return false
105 111
    }
106 112

  
107
    if (pattern_deco.proto !== url_deco.proto)
108
	return false;
109

  
110
    return domain_matches(url_deco.domain, pattern_deco.domain) &&
111
	path_matches(url_deco.path, url_deco.path_trailing_dash,
112
		     pattern_deco.path, pattern_deco.path_trailing_dash);
113
    return pattern_deco.proto === url_deco.proto &&
114
	!(pattern_deco.proto === "file" && pattern_deco.trailing_dash) &&
115
	!!url_deco.domain === !!pattern_deco.domain &&
116
	(!url_deco.domain ||
117
	 domain_matches(url_deco.domain, pattern_deco.domain)) &&
118
	path_matches(url_deco.path, url_deco.trailing_dash,
119
		     pattern_deco.path, pattern_deco.trailing_dash);
113 120
}
114 121

  
115
/*
116
 * Call callback for every possible pattern that matches url. Return when there
117
 * are no more patterns or callback returns false.
118
 */
119
function for_each_possible_pattern(url, callback)
122
function* each_domain_pattern(domain_segments)
120 123
{
121
    const deco = deconstruct_url(url);
122

  
123
    if (deco === undefined) {
124
	console.log("bad url format", url);
125
	return;
124
    for (let slice = 0; slice < domain_segments.length; slice++) {
125
	const domain_part = domain_segments.slice(slice).join(".");
126
	const domain_wildcards = [];
127
	if (slice === 0)
128
	    yield domain_part;
129
	if (slice === 1)
130
	    yield "*." + domain_part;
131
	if (slice > 1)
132
	    yield "**." + domain_part;
133
	yield "***." + domain_part;
126 134
    }
135
}
127 136

  
128
    for (let d_slice = 0; d_slice < deco.domain.length; d_slice++) {
129
	const domain_part = deco.domain.slice(d_slice).join(".");
130
	const domain_wildcards = [];
131
	if (d_slice === 0)
132
	    domain_wildcards.push("");
133
	if (d_slice === 1)
134
	    domain_wildcards.push("*.");
135
	if (d_slice > 0)
136
	    domain_wildcards.push("**.");
137
	domain_wildcards.push("***.");
138

  
139
	for (const domain_wildcard of domain_wildcards) {
140
	    const domain_pattern = domain_wildcard + domain_part;
141

  
142
	    for (let s_slice = deco.path.length; s_slice > 0; s_slice--) {
143
		const path_part = deco.path.slice(0, s_slice).join("/");
144
		const path_wildcards = [];
145
		if (s_slice === deco.path.length) {
146
		    if (deco.path_trailing_dash)
147
			path_wildcards.push("/");
148
		    path_wildcards.push("");
149
		}
150
		if (s_slice === deco.path.length - 1 &&
151
		    deco.path[s_slice] !== "*")
152
		    path_wildcards.push("/*");
153
		if (s_slice < deco.path.length &&
154
		    (deco.path[s_slice] !== "**" ||
155
		     s_slice < deco.path.length - 1))
156
		    path_wildcards.push("/**");
157
		if (deco.path[s_slice] !== "***" || s_slice < deco.path.length)
158
		    path_wildcards.push("/***");
159

  
160
		for (const path_wildcard of path_wildcards) {
161
		    const path_pattern = path_part + path_wildcard;
162

  
163
		    const pattern = deco.proto + domain_pattern + path_pattern;
164

  
165
		    if (callback(pattern) === false)
166
			return;
167
		}
168
	    }
137
function* each_path_pattern(path_segments, trailing_dash)
138
{
139
    for (let slice = path_segments.length; slice > 0; slice--) {
140
	const path_part = path_segments.slice(0, slice).join("/");
141
	const path_wildcards = [];
142
	if (slice === path_segments.length) {
143
	    if (trailing_dash)
144
		yield path_part + "/";
145
	    yield path_part;
169 146
	}
147
	if (slice === path_segments.length - 1 && path_segments[slice] !== "*")
148
	    yield path_part + "/*";
149
	if (slice < path_segments.length - 1)
150
	    yield path_part + "/**";
151
	if (slice < path_segments.length - 1 ||
152
	    path_segments[path_segments.length - 1] !== "***")
153
	    yield path_part + "/***";
170 154
    }
171 155
}
172 156

  
173
function possible_patterns(url)
157
/* Generate every possible pattern that matches url. */
158
function* each_url_pattern(url)
174 159
{
175
    const patterns = [];
176
    for_each_possible_pattern(url, patterns.push);
160
    const deco = deconstruct_url(url);
177 161

  
178
    return patterns;
162
    if (deco === undefined) {
163
	console.log("bad url format", url);
164
	return false;
165
    }
166

  
167
    const all_domains = deco.domain ? each_domain_pattern(deco.domain) : [""];
168
    for (const domain of all_domains) {
169
	for (const path of each_path_pattern(deco.path, deco.trailing_dash))
170
	    yield `${deco.proto}://${domain}${path}`;
171
    }
179 172
}
180 173

  
181 174
/*
182 175
 * EXPORTS_START
183 176
 * EXPORT url_matches
184
 * EXPORT for_each_possible_pattern
185
 * EXPORT possible_patterns
177
 * EXPORT each_url_pattern
186 178
 * EXPORTS_END
187 179
 */

Also available in: Unified diff