Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
QuiteAFancyEmerald
GitHub Repository: QuiteAFancyEmerald/Holy-Unblocker
Path: blob/master/proxyServiceValidator.js
5154 views
1
// This file is solely used for the automatically run GitHub job, which checks to
2
// see if all HU LTS code is working properly (at least on an Ubuntu machine).
3
4
const axios = require('axios');
5
const puppeteer = require('puppeteer');
6
7
const testEndpoint = async (url) => {
8
try {
9
const response = await axios.get(url);
10
return response.status === 200;
11
} catch (error) {
12
console.error(`Error ${error.code} while testing ${url}:`, error.message);
13
return false;
14
}
15
};
16
17
const generateUrl = async (omniboxId, urlPath, errorPrefix = 'failure') => {
18
// Wait for the document to load before getting the omnibox.
19
await new Promise((resolve) => {
20
const waitLonger = () => setTimeout(resolve, 5000);
21
if (document.readyState === 'complete') waitLonger();
22
else window.addEventListener('load', waitLonger);
23
});
24
25
let omnibox = document.getElementById(omniboxId);
26
omnibox = omnibox && omnibox.querySelector('input[type=text]');
27
28
if (omnibox) {
29
try {
30
// Send an artificial input to the omnibox. The omnibox will create
31
// a proxy URL and leave it as the input value in response.
32
omnibox.value = urlPath;
33
const generateInput = async () => {
34
await omnibox.dispatchEvent(
35
new KeyboardEvent('keydown', { code: 'Validator Test' })
36
);
37
};
38
/* Keep trying to send an input signal every second until it works.
39
* Implemented to account for a condition where the document has
40
* finished loading, but the event handler for DOMContentLoaded has
41
* not finished executing its script to listen for artificial inputs.
42
*/
43
await generateInput();
44
const inputInterval = setInterval(generateInput, 1000),
45
resolveHandler = (resolve) => () => {
46
clearInterval(inputInterval);
47
resolve(omnibox.value);
48
},
49
// Wait up to 40 seconds for the omnibox to finish updating.
50
loadUrl = new Promise((resolve) => {
51
if (omnibox.value !== urlPath) resolveHandler(resolve)();
52
else omnibox.addEventListener('change', resolveHandler(resolve));
53
}),
54
timeout = new Promise((resolve) => {
55
setTimeout(resolveHandler(resolve), 40000);
56
}),
57
// Return the proxy URL that the omnibox left here.
58
generatedUrl = await Promise.race([loadUrl, timeout]);
59
return generatedUrl !== urlPath ? generatedUrl : errorPrefix;
60
} catch (e) {
61
return errorPrefix + ': ' + e.message;
62
}
63
} else {
64
return errorPrefix + ': omnibox not defined';
65
}
66
};
67
68
const testGeneratedUrl = async (url, headers) => {
69
try {
70
console.log('Testing generated URL:', url);
71
72
const response = await axios.get(url, { headers });
73
console.log(`Response status for ${url}:`, response.status);
74
return response.status === 200;
75
} catch (error) {
76
console.error(`Error while testing generated URL ${url}:`, error.message);
77
return false;
78
}
79
};
80
81
const testServerResponse = async () => {
82
const endpoints = [
83
'http://localhost:8080/',
84
'http://localhost:8080/test-404',
85
'http://localhost:8080/browsing',
86
'http://localhost:8080/physics',
87
'http://localhost:8080/networking',
88
'http://localhost:8080/documentation',
89
'http://localhost:8080/questions',
90
'http://localhost:8080/s',
91
'http://localhost:8080/credits',
92
'http://localhost:8080/terms',
93
'http://localhost:8080/books',
94
'http://localhost:8080/dictionary',
95
'http://localhost:8080/catalogue',
96
'http://localhost:8080/textbook',
97
'http://localhost:8080/math',
98
'http://localhost:8080/wiki',
99
'http://localhost:8080/software',
100
'http://localhost:8080/whiteboard',
101
'http://localhost:8080/notebook',
102
'http://localhost:8080/assets/js/card.js',
103
'http://localhost:8080/assets/js/common-1735118314.js',
104
'http://localhost:8080/assets/js/csel.js',
105
'http://localhost:8080/assets/js/register-sw.js',
106
'http://localhost:8080/assets/json/emu-nav.json',
107
'http://localhost:8080/assets/json/blacklist.json',
108
'http://localhost:8080/assets/json/emulib-nav.json',
109
'http://localhost:8080/assets/json/flash-nav.json',
110
'http://localhost:8080/assets/json/h5-nav.json',
111
'http://localhost:8080/assets/json/links.json',
112
'http://localhost:8080/gmt/index.js',
113
'http://localhost:8080/gmt/worker.js',
114
'http://localhost:8080/epoch/index.mjs',
115
'http://localhost:8080/worker/working.all.js',
116
'http://localhost:8080/worker/working.sw.js',
117
'http://localhost:8080/worker/working.sw-blacklist.js',
118
'http://localhost:8080/network/networking.bundle.js',
119
'http://localhost:8080/network/networking.sw.js',
120
'http://localhost:8080/network/networking.config.js',
121
'http://localhost:8080/network/workerware.js',
122
'http://localhost:8080/network/WWError.js',
123
];
124
125
126
const results = await Promise.all(endpoints.map(testEndpoint));
127
const allPassed = results.every((result) => result);
128
129
if (allPassed) {
130
console.log('All endpoints responded with status code 200. Test passed.');
131
await testCommonJSOnPage();
132
} else {
133
console.error(
134
'One or more endpoints failed to respond with status code 200. Test failed.'
135
);
136
process.exitCode = 1;
137
}
138
};
139
140
const testCommonJSOnPage = async () => {
141
const browser = await puppeteer.launch({
142
args: [
143
'--enable-features=NetworkService',
144
'--enable-features=ServiceWorker',
145
'--enable-features=InsecureOrigins',
146
],
147
headless: true,
148
ignoreHTTPSErrors: true,
149
});
150
const page = await browser.newPage();
151
152
try {
153
const getHeaders = async () => {
154
const headers = {};
155
156
headers['User-Agent'] = await page.evaluate(() => navigator.userAgent);
157
headers['Referer'] = await page.evaluate(() => window.location.href);
158
159
return headers;
160
};
161
162
const testRammerhead = async () => {
163
const omniboxId = 'pr-rh',
164
urlPath = 'example.com';
165
await page.goto('http://localhost:8080/physics');
166
const generatedUrl = await page.evaluate(generateUrl, omniboxId, urlPath);
167
const testResults = {};
168
testResults.rammerhead = generatedUrl;
169
170
console.log('Rammerhead test results:', testResults);
171
172
const headers = await getHeaders();
173
const rammerheadTestPassed =
174
testResults.rammerhead !== 'failure' &&
175
(await testGeneratedUrl(testResults.rammerhead, headers));
176
177
console.log(
178
`Rammerhead test result: ${
179
rammerheadTestPassed ? 'success' : 'failure'
180
}`
181
);
182
183
return rammerheadTestPassed;
184
};
185
186
/*
187
188
xx
189
xx xx
190
xxx xx
191
xxx xx
192
xxx xx
193
xxx xx
194
xx xx
195
xx xx
196
xx
197
xx
198
199
200
201
202
x x
203
204
205
206
207
208
209
xxxxxxxxxxxxxxx
210
xxxxxxxxxxxx xxxxx
211
xxxx xxx
212
xxx xxx
213
xxx xx
214
xx xx
215
xx xx
216
xxx x
217
xx x
218
xx xx
219
220
*/
221
222
const testUltraviolet = async () => {
223
const omniboxId = 'pr-uv',
224
errorPrefix = 'failure',
225
// For the hacky URL test further below, use the URL page's EXACT title.
226
website = Object.freeze({
227
path: 'example.com',
228
title: 'Example Domain',
229
});
230
await page.goto('http://localhost:8080/networking');
231
const generatedUrl = await page.evaluate(
232
generateUrl,
233
omniboxId,
234
website.path,
235
errorPrefix
236
);
237
238
const testResults = await page.evaluate(
239
async (generatedUrl, pageTitle) => {
240
const results = [{}, {}];
241
242
await new Promise((resolve) => {
243
const waitForDocument = () => {
244
const waitLonger = () => setTimeout(resolve, 5000);
245
if (document.readyState === 'complete') waitLonger();
246
else window.addEventListener('load', waitLonger);
247
},
248
// Wait until a service worker is registered before continuing.
249
// Also check again to make sure the document is loaded.
250
waitForWorker = async () => {
251
setTimeout(async () => {
252
(await navigator.serviceWorker.getRegistrations()).length > 0
253
? waitForDocument()
254
: waitForWorker();
255
}, 1000);
256
};
257
258
waitForWorker();
259
});
260
261
try {
262
results[0].ultraviolet = generatedUrl;
263
264
// Test to see if the document title for example.com has loaded,
265
// by appending an IFrame to the document and grabbing its content.
266
const testGeneratedUrlHacky = async (url) => {
267
const exampleIFrame = document.createElement('iframe');
268
const waitForDocument = new Promise((resolve) => {
269
document.documentElement.appendChild(exampleIFrame);
270
exampleIFrame.addEventListener('load', () => {
271
resolve(
272
exampleIFrame.contentWindow.document.title === pageTitle
273
);
274
});
275
});
276
277
// Give 10 seconds for the IFrame to load before manually checking.
278
const timeout = new Promise((resolve) => {
279
setTimeout(() => {
280
resolve(
281
exampleIFrame.contentWindow.document.title === pageTitle
282
);
283
}, 10000);
284
});
285
286
exampleIFrame.src = url;
287
exampleIFrame.style.display = 'none';
288
return await Promise.race([waitForDocument, timeout]);
289
};
290
291
results[1].uvTestPassed =
292
!!results[0].ultraviolet.indexOf(errorPrefix) &&
293
(await testGeneratedUrlHacky(results[0].ultraviolet));
294
} catch (e) {
295
results[0].ultraviolet = errorPrefix + ': ' + e.message;
296
}
297
298
return results;
299
},
300
generatedUrl,
301
website.title,
302
errorPrefix
303
);
304
305
console.log('Ultraviolet test results:', testResults[0]);
306
const uvTestPassed =
307
testResults[0].ultraviolet &&
308
testResults[0].ultraviolet !== 'failure' &&
309
testResults[1].uvTestPassed;
310
console.log(
311
'Ultraviolet test result:',
312
uvTestPassed ? 'success' : 'failure'
313
);
314
return uvTestPassed;
315
};
316
317
// Run tests for Rammerhead and Ultraviolet.
318
await page.goto('http://localhost:8080/');
319
const rammerheadPassed = await testRammerhead();
320
const ultravioletPassed = await testUltraviolet();
321
322
if (rammerheadPassed && ultravioletPassed) {
323
console.log('Both tests passed.');
324
process.exitCode = 0;
325
} else {
326
console.error('Tests failed.');
327
process.exitCode = 1;
328
}
329
} catch (error) {
330
console.error('Error in testCommonJSOnPage:', error.message);
331
process.exitCode = 1;
332
} finally {
333
await browser.close();
334
}
335
};
336
337
testServerResponse();
338
339