1 |
5b2a7a61
|
Wojtek Kosior
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
2 |
|
|
|
3 |
|
|
"""
|
4 |
|
|
Our helpful little stand-in for the Internet
|
5 |
|
|
"""
|
6 |
|
|
|
7 |
|
|
# This file is part of Haketilo.
|
8 |
|
|
#
|
9 |
|
|
# Copyright (C) 2021 jahoti <jahoti@tilde.team>
|
10 |
|
|
# Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
|
11 |
|
|
#
|
12 |
|
|
# This program is free software: you can redistribute it and/or modify
|
13 |
|
|
# it under the terms of the GNU Affero General Public License as
|
14 |
|
|
# published by the Free Software Foundation, either version 3 of the
|
15 |
|
|
# License, or (at your option) any later version.
|
16 |
|
|
#
|
17 |
|
|
# This program is distributed in the hope that it will be useful,
|
18 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20 |
|
|
# GNU Affero General Public License for more details.
|
21 |
|
|
#
|
22 |
|
|
# You should have received a copy of the GNU Affero General Public License
|
23 |
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
24 |
|
|
#
|
25 |
|
|
#
|
26 |
|
|
# I, Wojtek Kosior, thereby promise not to sue for violation of this
|
27 |
372d24ea
|
Wojtek Kosior
|
# file's license. Although I request that you do not make use of this code
|
28 |
5b2a7a61
|
Wojtek Kosior
|
# in a proprietary program, I am not going to enforce this in court.
|
29 |
|
|
|
30 |
702eefd2
|
Wojtek Kosior
|
from hashlib import sha256
|
31 |
|
|
from pathlib import Path
|
32 |
|
|
from shutil import rmtree
|
33 |
|
|
from threading import Lock
|
34 |
7218849a
|
Wojtek Kosior
|
from uuid import uuid4
|
35 |
046b8a7b
|
Wojtek Kosior
|
import json
|
36 |
702eefd2
|
Wojtek Kosior
|
|
37 |
5b2a7a61
|
Wojtek Kosior
|
from .misc_constants import here
|
38 |
7218849a
|
Wojtek Kosior
|
from .unit.utils import * # sample repo data
|
39 |
|
|
|
40 |
|
|
# TODO: instead of having the entire catalog defined here, make it possible to
|
41 |
|
|
# add catalog items from within individual test files.
|
42 |
5b2a7a61
|
Wojtek Kosior
|
|
43 |
702eefd2
|
Wojtek Kosior
|
served_scripts = {}
|
44 |
|
|
served_scripts_lock = Lock()
|
45 |
|
|
|
46 |
|
|
def start_serving_script(script_text):
|
47 |
|
|
"""
|
48 |
|
|
Register given script so that it is served at
|
49 |
|
|
https://serve.scrip.ts/?sha256=<script's_sha256_sum>
|
50 |
|
|
|
51 |
|
|
Returns the URL at which script will be served.
|
52 |
|
|
|
53 |
|
|
This function lacks thread safety. Might moght consider fixing this if it
|
54 |
|
|
turns
|
55 |
|
|
"""
|
56 |
|
|
sha256sum = sha256(script_text.encode()).digest().hex()
|
57 |
|
|
served_scripts_lock.acquire()
|
58 |
|
|
served_scripts[sha256sum] = script_text
|
59 |
|
|
served_scripts_lock.release()
|
60 |
|
|
|
61 |
|
|
return f'https://serve.scrip.ts/?sha256={sha256sum}'
|
62 |
|
|
|
63 |
|
|
def serve_script(command, get_params, post_params):
|
64 |
|
|
"""
|
65 |
|
|
info() callback to pass to request-handling code in server.py. Facilitates
|
66 |
|
|
serving scripts that have been registered with start_serving_script().
|
67 |
|
|
"""
|
68 |
|
|
served_scripts_lock.acquire()
|
69 |
|
|
try:
|
70 |
|
|
script = served_scripts.get(get_params['sha256'][0])
|
71 |
|
|
finally:
|
72 |
|
|
served_scripts_lock.release()
|
73 |
|
|
if script is None:
|
74 |
|
|
return 404, {}, b''
|
75 |
|
|
|
76 |
|
|
return 200, {'Content-Type': 'application/javascript'}, script
|
77 |
|
|
|
78 |
fd9f2fc4
|
Wojtek Kosior
|
def dump_scripts(directory=(Path.cwd() / 'injected_scripts')):
|
79 |
702eefd2
|
Wojtek Kosior
|
"""
|
80 |
|
|
Write all scripts that have been registered with start_serving_script()
|
81 |
|
|
under the provided directory. If the directory already exists, it is wiped
|
82 |
|
|
beforehand. If it doesn't exist, it is created.
|
83 |
|
|
"""
|
84 |
|
|
directory = Path(directory)
|
85 |
|
|
rmtree(directory, ignore_errors=True)
|
86 |
|
|
directory.mkdir(parents=True)
|
87 |
|
|
|
88 |
|
|
served_scripts_lock.acquire()
|
89 |
|
|
for sha256, script in served_scripts.items():
|
90 |
|
|
with open(directory / sha256, 'wt') as file:
|
91 |
|
|
file.write(script)
|
92 |
|
|
served_scripts_lock.release()
|
93 |
|
|
|
94 |
17614206
|
Wojtek Kosior
|
some_data = '{"some": "data"}'
|
95 |
|
|
|
96 |
046b8a7b
|
Wojtek Kosior
|
# used by handler function of https://counterdoma.in
|
97 |
|
|
request_counter = 0
|
98 |
|
|
|
99 |
|
|
def serve_counter(command, get_params, post_params):
|
100 |
|
|
global request_counter
|
101 |
|
|
request_counter += 1
|
102 |
|
|
return (
|
103 |
|
|
200,
|
104 |
|
|
{'Cache-Control': 'private, max-age=0, no-store'},
|
105 |
|
|
json.dumps({'counter': request_counter})
|
106 |
|
|
)
|
107 |
|
|
|
108 |
7218849a
|
Wojtek Kosior
|
# Mock a Hydrilla repository.
|
109 |
|
|
|
110 |
b75a5717
|
Wojtek Kosior
|
make_handler = lambda txt: lambda c, g, p: (200, {}, txt)
|
111 |
|
|
|
112 |
7218849a
|
Wojtek Kosior
|
# Mock files in the repository.
|
113 |
|
|
sample_contents = [f'Mi povas manĝi vitron, ĝi ne damaĝas min {i}'
|
114 |
|
|
for i in range(9)]
|
115 |
b75a5717
|
Wojtek Kosior
|
sample_hashes = [sha256(c.encode()).digest().hex() for c in sample_contents]
|
116 |
7218849a
|
Wojtek Kosior
|
|
117 |
1c65dd5c
|
Wojtek Kosior
|
file_url = lambda hashed: f'https://hydril.la/file/sha256/{hashed}'
|
118 |
7218849a
|
Wojtek Kosior
|
|
119 |
b75a5717
|
Wojtek Kosior
|
sample_files_catalog = dict([(file_url(h), make_handler(c))
|
120 |
7218849a
|
Wojtek Kosior
|
for h, c in zip(sample_hashes, sample_contents)])
|
121 |
|
|
|
122 |
|
|
# Mock resources and mappings in the repository.
|
123 |
|
|
sample_resource_templates = []
|
124 |
|
|
|
125 |
|
|
for deps in [(0, 1, 2, 3), (3, 4, 5, 6), (6, 7, 8, 9)]:
|
126 |
|
|
letters = [chr(ord('a') + i) for i in deps]
|
127 |
|
|
sample_resource_templates.append({
|
128 |
|
|
'id_suffix': ''.join(letters),
|
129 |
|
|
'files_count': deps[0],
|
130 |
57ce414c
|
Wojtek Kosior
|
'dependencies': [{'identifier': f'resource-{l}'} for l in letters]
|
131 |
7218849a
|
Wojtek Kosior
|
})
|
132 |
|
|
|
133 |
|
|
suffixes = [srt['id_suffix'] for srt in sample_resource_templates]
|
134 |
|
|
sample_resource_templates.append({
|
135 |
|
|
'id_suffix': '-'.join(suffixes),
|
136 |
|
|
'files_count': 2,
|
137 |
57ce414c
|
Wojtek Kosior
|
'dependencies': [{'identifier': f'resource-{suf}'} for suf in suffixes]
|
138 |
7218849a
|
Wojtek Kosior
|
})
|
139 |
|
|
|
140 |
|
|
for i in range(10):
|
141 |
|
|
sample_resource_templates.append({
|
142 |
|
|
'id_suffix': chr(ord('a') + i),
|
143 |
|
|
'files_count': i,
|
144 |
|
|
'dependencies': []
|
145 |
|
|
})
|
146 |
|
|
|
147 |
|
|
sample_resources_catalog = {}
|
148 |
|
|
sample_mappings_catalog = {}
|
149 |
b75a5717
|
Wojtek Kosior
|
sample_queries = {}
|
150 |
7218849a
|
Wojtek Kosior
|
|
151 |
|
|
for srt in sample_resource_templates:
|
152 |
|
|
resource = make_sample_resource()
|
153 |
57ce414c
|
Wojtek Kosior
|
resource['identifier'] = f'resource-{srt["id_suffix"]}'
|
154 |
7218849a
|
Wojtek Kosior
|
resource['long_name'] = resource['identifier'].upper()
|
155 |
|
|
resource['uuid'] = str(uuid4())
|
156 |
|
|
resource['dependencies'] = srt['dependencies']
|
157 |
|
|
resource['source_copyright'] = []
|
158 |
|
|
resource['scripts'] = []
|
159 |
|
|
for i in range(srt['files_count']):
|
160 |
|
|
file_ref = {'file': f'file_{i}', 'sha256': sample_hashes[i]}
|
161 |
|
|
resource[('source_copyright', 'scripts')[i & 1]].append(file_ref)
|
162 |
|
|
|
163 |
b75a5717
|
Wojtek Kosior
|
resource_versions = [resource['version'], resource['version'].copy()]
|
164 |
|
|
resource_versions[1][-1] += 1
|
165 |
7218849a
|
Wojtek Kosior
|
|
166 |
|
|
mapping = make_sample_mapping()
|
167 |
57ce414c
|
Wojtek Kosior
|
mapping['identifier'] = f'mapping-{srt["id_suffix"]}'
|
168 |
7218849a
|
Wojtek Kosior
|
mapping['long_name'] = mapping['identifier'].upper()
|
169 |
|
|
mapping['uuid'] = str(uuid4())
|
170 |
|
|
mapping['source_copyright'] = resource['source_copyright']
|
171 |
|
|
|
172 |
b75a5717
|
Wojtek Kosior
|
mapping_versions = [mapping['version'], mapping['version'].copy()]
|
173 |
|
|
mapping_versions[1][-1] += 1
|
174 |
|
|
|
175 |
|
|
sufs = [srt["id_suffix"], *[l for l in srt["id_suffix"] if l.isalpha()]]
|
176 |
|
|
patterns = [f'https://example_{suf}.com/*' for suf in set(sufs)]
|
177 |
|
|
payloads = {}
|
178 |
|
|
|
179 |
|
|
for pat in patterns:
|
180 |
|
|
payloads[pat] = {'identifier': resource['identifier']}
|
181 |
|
|
|
182 |
|
|
queryable_url = pat.replace('*', 'something')
|
183 |
|
|
if queryable_url not in sample_queries:
|
184 |
|
|
sample_queries[queryable_url] = []
|
185 |
|
|
|
186 |
|
|
sample_queries[queryable_url].append({
|
187 |
|
|
'identifier': mapping['identifier'],
|
188 |
|
|
'long_name': mapping['long_name'],
|
189 |
|
|
'version': mapping_versions[1]
|
190 |
|
|
})
|
191 |
7218849a
|
Wojtek Kosior
|
|
192 |
b75a5717
|
Wojtek Kosior
|
mapping['payloads'] = payloads
|
193 |
|
|
|
194 |
|
|
for item, versions, catalog in [
|
195 |
|
|
(resource, resource_versions, sample_resources_catalog),
|
196 |
|
|
(mapping, mapping_versions, sample_mappings_catalog)
|
197 |
7218849a
|
Wojtek Kosior
|
]:
|
198 |
8477d0cf
|
Wojtek Kosior
|
fmt = f'https://hydril.la/{item["type"]}/{item["identifier"]}%s'
|
199 |
7218849a
|
Wojtek Kosior
|
# Make 2 versions of each item so that we can test updates.
|
200 |
b75a5717
|
Wojtek Kosior
|
for ver in versions:
|
201 |
|
|
item['version'] = ver
|
202 |
8477d0cf
|
Wojtek Kosior
|
for fmt_arg in ('.json', '/' + item_version_string(item)):
|
203 |
7218849a
|
Wojtek Kosior
|
catalog[fmt % fmt_arg] = make_handler(json.dumps(item))
|
204 |
b75a5717
|
Wojtek Kosior
|
|
205 |
|
|
def serve_query(command, get_params, post_params):
|
206 |
|
|
response = {
|
207 |
72553a2d
|
Wojtek Kosior
|
'$schema': 'https://hydrilla.koszko.org/schemas/api_query_result-1.schema.json',
|
208 |
|
|
'generated_by': {
|
209 |
|
|
'name': 'human',
|
210 |
|
|
'version': 'sapiens-0.8.15'
|
211 |
|
|
},
|
212 |
|
|
'mappings': sample_queries[get_params['url'][0]]
|
213 |
b75a5717
|
Wojtek Kosior
|
}
|
214 |
|
|
|
215 |
|
|
return (200, {}, json.dumps(response))
|
216 |
|
|
|
217 |
|
|
sample_queries_catalog = dict([(f'https://hydril.la/{suf}query', serve_query)
|
218 |
|
|
for suf in ('', '1/', '2/', '3/', '4/')])
|
219 |
7218849a
|
Wojtek Kosior
|
|
220 |
5b2a7a61
|
Wojtek Kosior
|
catalog = {
|
221 |
702eefd2
|
Wojtek Kosior
|
'http://gotmyowndoma.in':
|
222 |
|
|
(302, {'location': 'http://gotmyowndoma.in/index.html'}, None),
|
223 |
|
|
'http://gotmyowndoma.in/':
|
224 |
|
|
(302, {'location': 'http://gotmyowndoma.in/index.html'}, None),
|
225 |
|
|
'http://gotmyowndoma.in/index.html':
|
226 |
|
|
(200, {}, here / 'data' / 'pages' / 'gotmyowndomain.html'),
|
227 |
|
|
|
228 |
|
|
'https://gotmyowndoma.in':
|
229 |
|
|
(302, {'location': 'https://gotmyowndoma.in/index.html'}, None),
|
230 |
|
|
'https://gotmyowndoma.in/':
|
231 |
|
|
(302, {'location': 'https://gotmyowndoma.in/index.html'}, None),
|
232 |
|
|
'https://gotmyowndoma.in/index.html':
|
233 |
|
|
(200, {}, here / 'data' / 'pages' / 'gotmyowndomain_https.html'),
|
234 |
|
|
|
235 |
7bedbcbd
|
Wojtek Kosior
|
'https://gotmyowndoma.in/scripts_to_block_1.html':
|
236 |
|
|
(200, {}, here / 'data' / 'pages' / 'scripts_to_block_1.html'),
|
237 |
|
|
|
238 |
17614206
|
Wojtek Kosior
|
'https://anotherdoma.in/resource/blocked/by/CORS.json':
|
239 |
|
|
lambda command, get_params, post_params: (200, {}, some_data),
|
240 |
|
|
|
241 |
046b8a7b
|
Wojtek Kosior
|
'https://counterdoma.in/': serve_counter,
|
242 |
|
|
|
243 |
702eefd2
|
Wojtek Kosior
|
'https://serve.scrip.ts/': serve_script,
|
244 |
|
|
|
245 |
|
|
'https://site.with.scripts.block.ed':
|
246 |
|
|
(302, {'location': 'https://site.with.scripts.block.ed/index.html'}, None),
|
247 |
|
|
'https://site.with.scripts.block.ed/':
|
248 |
|
|
(302, {'location': 'https://site.with.scripts.block.ed/index.html'}, None),
|
249 |
|
|
'https://site.with.scripts.block.ed/index.html':
|
250 |
|
|
(200, {}, here / 'data' / 'pages' / 'gotmyowndomain_https.html'),
|
251 |
|
|
|
252 |
|
|
'https://site.with.scripts.allow.ed':
|
253 |
|
|
(302, {'location': 'https://site.with.scripts.allow.ed/index.html'}, None),
|
254 |
|
|
'https://site.with.scripts.allow.ed/':
|
255 |
|
|
(302, {'location': 'https://site.with.scripts.allow.ed/index.html'}, None),
|
256 |
|
|
'https://site.with.scripts.allow.ed/index.html':
|
257 |
|
|
(200, {}, here / 'data' / 'pages' / 'gotmyowndomain_https.html'),
|
258 |
|
|
|
259 |
|
|
'https://site.with.paylo.ad':
|
260 |
|
|
(302, {'location': 'https://site.with.paylo.ad/index.html'}, None),
|
261 |
|
|
'https://site.with.paylo.ad/':
|
262 |
|
|
(302, {'location': 'https://site.with.paylo.ad/index.html'}, None),
|
263 |
|
|
'https://site.with.paylo.ad/index.html':
|
264 |
7218849a
|
Wojtek Kosior
|
(200, {}, here / 'data' / 'pages' / 'gotmyowndomain_https.html'),
|
265 |
|
|
|
266 |
|
|
**sample_files_catalog,
|
267 |
|
|
**sample_resources_catalog,
|
268 |
b75a5717
|
Wojtek Kosior
|
**sample_mappings_catalog,
|
269 |
|
|
**sample_queries_catalog
|
270 |
5b2a7a61
|
Wojtek Kosior
|
}
|