aboutsummaryrefslogtreecommitdiff
path: root/background/settings_query.js
blob: d2140013317b2fbcf188ec2bad2f28158043c830 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * Myext querying page settings with regard to wildcard records
 *
 * Copyright (C) 2021 Wojtek Kosior
 *
 * This code is dual-licensed under:
 * - Asshole license 1.0,
 * - GPLv3 or (at your option) any later version
 *
 * "dual-licensed" means you can choose the license you prefer.
 *
 * This code is released under a permissive license because I disapprove of
 * copyright and wouldn't be willing to sue a violator. Despite not putting
 * this code under copyleft (which is also kind of copyright), I do not want
 * it to be made proprietary. Hence, the permissive alternative to GPL is the
 * Asshole license 1.0 that allows me to call you an asshole if you use it.
 * This means you're legally ok regardless of how you utilize this code but if
 * you make it into something nonfree, you're an asshole.
 *
 * You should have received a copy of both GPLv3 and Asshole license 1.0
 * together with this code. If not, please see:
 * - https://www.gnu.org/licenses/gpl-3.0.en.html
 * - https://koszko.org/asshole-license.txt
 */

"use strict";

(() => {
    const make_once = window.make_once;
    const get_storage = window.get_storage;

    var storage;

    var exports = {};

    async function init(fun)
    {
	storage = await get_storage();

	return fun;
    }

    // TODO: also support urls with specified ports as well as `data:' urls
    function query(url, multiple)
    {
	let proto_re = "[a-zA-Z]*:\/\/";
	let domain_re = "[^/?#]+";
	let segments_re = "/[^?#]*";
	let query_re = "\\?[^#]*";

	let url_regex = new RegExp(`\
^\
(${proto_re})\
(${domain_re})\
(${segments_re})?\
(${query_re})?\
#?.*\$\
`);

	let regex_match = url_regex.exec(url);
	if (regex_match === null) {
	    console.log("bad url format", url);
	    return multiple ? [] : [undefined, undefined];
	}

	let [_, proto, domain, segments, query] = regex_match;

	domain = domain.split(".");
	let segments_trailing_dash =
	    segments && segments[segments.length - 1] === "/";
	segments = (segments || "").split("/").filter(s => s !== "");
	segments.unshift("");

	let matched = [];

	for (let d_slice = 0; d_slice < domain.length; d_slice++) {
	    let domain_part = domain.slice(d_slice).join(".");
	    let domain_wildcards = [];
	    if (d_slice === 0)
		domain_wildcards.push("");
	    if (d_slice === 1)
		domain_wildcards.push("*.");
	    if (d_slice > 0)
		domain_wildcards.push("**.");
	    domain_wildcards.push("***.");

	    for (let domain_wildcard of domain_wildcards) {
		let domain_pattern = domain_wildcard + domain_part;

		for (let s_slice = segments.length; s_slice > 0; s_slice--) {
		    let segments_part = segments.slice(0, s_slice).join("/");
		    let segments_wildcards = [];
		    if (s_slice === segments.length) {
			if (segments_trailing_dash)
			    segments_wildcards.push("/");
			segments_wildcards.push("");
		    }
		    if (s_slice === segments.length - 1) {
			if (segments[s_slice] !== "*")
			    segments_wildcards.push("/*");
		    }
		    if (s_slice < segments.length &&
			(segments[s_slice] !== "**" ||
			 s_slice < segments.length - 1))
			segments_wildcards.push("/**");
		    if (segments[s_slice] !== "***" ||
			s_slice < segments.length)
			segments_wildcards.push("/***");

		    for (let segments_wildcard of segments_wildcards) {
			let segments_pattern =
			    segments_part + segments_wildcard;

			let pattern = proto + domain_pattern + segments_pattern;
			console.log("trying", pattern);
			let settings = storage.get(TYPE_PREFIX.PAGE, pattern);

			if (settings === undefined)
			    continue;

			if (!multiple)
			    return [pattern, settings];

			matched.push([pattern, settings]);
		    }
		}
	    }
	}

	return multiple ?  matched : [undefined, undefined];
    }

    function query_best(url)
    {
	return query(url, false);
    }

    function query_all(url)
    {
	return query(url, true);
    }

    window.get_query_best = make_once(() => init(query_best));
    window.get_query_all = make_once(() => init(query_all));
})();