-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathredirector.js
executable file
·143 lines (117 loc) · 3.24 KB
/
redirector.js
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
#!/usr/bin/env node
'use strict';
/* == BEGIN CONFIGURATION SECTION */
const DEBUG = false;
// Only handles one port at a time (currently).
// Only ports 80 and 443 are valid.
//
// If PORT = 443, a suitable trusted certificate its private key must be
// supplied (which can be done below).
//
// Note that this will include requiring the 'subject alternative names'
// extension in the certificate to be valid for the domains being redirected.
const HOSTNAME = '127.0.0.1';
const PORT = 443;
// Ensures POSTs are also redirected.
const STATUS_CODE = 307;
const mappings = [
[
// E.g. for domains of the form
// https://github12321.com/project/repo.git[/tail]
'^(https?)://(github12321.com)/([^/]+)/([^/]+.git/?)(.+)?$',
(protocol, domain, project, repo, tail) => {
return `${protocol}://github.com/${project}/${repo}${tail || ''}`;
}
],
[
// Simple redirection for all non-repo URLs
'^(https?)://(github12321.com)/(.+)$',
(protocol, domain, path) => {
return `${protocol}://github.com/${path}`;
// return `${protocol}://${domain}/${project}/${repo}`;
},
],
];
// These should be in PEM format.
// Only needed when using HTTPS.
// The certificate must be trusted and sign for the intended domain(s).
const KEY_PATH = null;
const CERT_PATH = null;
/* == END CONFIGURATION SECTION */
const fs = require('fs');
const http = require('http');
const https = require('https');
const protocol = {
80: 'http',
443: 'https',
}[PORT];
const create_server = {
http: http.createServer,
https: callback_fn => https.createServer({
key: fs.readFileSync(KEY_PATH),
cert: fs.readFileSync(CERT_PATH)
}, callback_fn)
}[protocol];
function debug_log(msg) {
if (DEBUG)
{
console.log(msg);
}
}
function get_redirection_url(target) {
for ( let [regex, map_fn] of mappings )
{
const match = target.match(regex);
if ( !match )
{
debug_log(`Did not match regex of form ${regex}.`);
continue;
}
match.shift();
debug_log(`Matched regex of form ${regex}.`);
debug_log(`Matches: ${match}`);
return map_fn(...match);
}
debug_log('Did not match any regexes');
return null;
}
function get_full_url(req)
{
const host = req.headers.host;
const initial_url = req.url;
const full_url = `${protocol}://${host}${initial_url}`;
return full_url;
}
const server = create_server(function (req, res)
{
const full_url = get_full_url(req);
console.log(`Intercepted request to URL ${full_url}.`);
const new_url = get_redirection_url(full_url);
if ( new_url !== null )
{
console.log(`Redirecting URL with ${STATUS_CODE} status code.`);
console.log(`Old URL: ${full_url}`);
console.log(`New URL: ${new_url}`);
res.writeHead(STATUS_CODE, {
location: new_url,
});
}
else
{
console.log('Failed to redirect as URL not handled.');
console.log('Returning response with 404 status code.');
res.writeHead(404);
}
res.end();
});
console.log(`Listening for specific HTTP requests on ${HOSTNAME}:${PORT}.`);
console.log('(Don\'t forget to redirect such domains via /etc/hosts if needed.)');
console.log('');
console.log('Hostname regular expressions being redirected:');
for (let [index, [regex, _]] of mappings.entries())
{
console.log(`\t${index + 1}. '${regex}'`);
}
console.log('');
console.log('Listening...');
server.listen(PORT, HOSTNAME);