Browse Source

Add standalone webserver

standalone-webserver
Peter H. Jin 3 months ago
parent
commit
cc6e64d882
  1. 16
      .gitignore
  2. 2
      LICENSE
  3. 80
      _index.js
  4. 24
      config/example/config.js
  5. 118
      config/live-demo/config.js
  6. 5
      main/.gitignore
  7. 0
      main/examples/auxtext2.js
  8. 0
      main/examples/ipv6things_db.json
  9. 0
      main/examples/runtimeConfig.json
  10. 0
      main/index.js
  11. 0
      main/live-demo/auxtext2.js
  12. 0
      main/live-demo/runtimeConfig.json
  13. 0
      main/page.js
  14. 0
      main/scp-aliases.json
  15. 0
      main/webserver-tester.js
  16. 12
      main/webserver.js
  17. 3
      ssl_test/readme.txt

16
.gitignore

@ -1,11 +1,7 @@
node_modules/
*.pem
*.key
*.csr
*.crt
node_modules
package-lock.json
ipv6things_db.json
ipv6-things.json
auxtext2.js
randomBibleVerse.json
runtimeConfig.json
public/
!examples/ipv6things_db.json
!examples/randomBibleVerse.json
!examples/auxtext2.js
bible

2
LICENSE

@ -1,4 +1,4 @@
Copyright (c) 2020 Peter H. Jin and/or Peter Jin Technologies LLC
Copyright (c) 2020-2021 Peter H. Jin and/or Peter Jin Technologies LLC
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

80
_index.js

@ -0,0 +1,80 @@
const config = require("./config/config.js");
const mainAppF = require("./main/webserver.js");
const net = require("net");
const http = require("http");
const express = require("express");
var ipv6BibleApp = null;
function logRequest(req, res, next) {
console.log(`${req.ip} [${new Date().toISOString()}] - ${req.headers['host']}[${req.socket.localAddress}] "${req.method} ${req.url} HTTP/${req.httpVersion}" "${req.headers['referer']}" "${req.headers['user-agent']}"`);
if (next) next();
}
try {
let ipv6BibleApp_b = express();
let ipv6BibleApp_s = require("./bible/webserver.js");
ipv6BibleApp_b.use('/', logRequest);
ipv6BibleApp_b.use('/', (req, res, next) => {
res.set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
next();
});
ipv6BibleApp_b.use('/', ipv6BibleApp_s.middlewareFunc);
ipv6BibleApp_b.set('etag', false);
ipv6BibleApp = ipv6BibleApp_b;
} catch (e) {
console.log("warning: IPv6 Bible not available");
}
var mainApp = express();
mainApp.use('/', logRequest);
mainAppF.mountExpress(mainApp, 'newVersion');
mainApp.set('etag', false);
function makeDummyApp(msg) {
let e = express();
e.use('/', (req, res) => {
logRequest(req, res, null);
res.send(503, msg);
});
return e;
}
config.initServers({
main: mainApp,
ipv6bible: ipv6BibleApp || makeDummyApp("IPv6 Bible is currently unavailable"),
make_static: function(path) {
let app = express();
app.use('/', logRequest);
app.use('/', express.static(path));
return app;
}
});
var dummyApp = express();
var acme_challenge = express.static(String(config.acmeRoot || "/run/acme-challenge-webroot/root/"));
dummyApp.use('/', (req, res, next) => {
let path = String(req.path);
if (path.startsWith("/.well-known/acme-challenge/")) {
logRequest(req, res, null);
return acme_challenge(req, res, next);
}
let host = String(req.get("host"));
let match = host.match(/^(.*):\d+$/);
if (match) {
host = match[1];
}
for (let h of ["peterjin.org", "ipv6-things.com", "ipv6.bible"]) {
if ((host === h) || (host.endsWith("." + h))) {
logRequest(req, res, null);
res.redirect(301, 'https://' + host + '/' + String(req.originalUrl || "").substring(1));
return;
}
}
return config.findServerForIP(req.socket.localAddress, false)(req, res, next);
});
var http_server = http.createServer(dummyApp);
var https_server = net.createServer((s) => {
try {
config.findServerForIP(s.localAddress, true).emit("connection", s);
} catch (e) {
s.end();
}
});
http_server.listen({port: 80});
https_server.listen({port: 443});

24
config/example/config.js

@ -0,0 +1,24 @@
var servers = {};
const https = require("https");
const crypto = require("crypto");
const ip = require('ip');
const fs = require('fs');
function makeHTTPSOptions(key_name) {
return {
cert: fs.readFileSync(`ssl_test/${key_name}.crt`),
key: fs.readFileSync(`ssl_test/${key_name}.key`),
ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:HIGH:!aNULL:!MD5:!AESCCM',
secureOptions: crypto.constants.SSL_OP_NO_RENEGOTIATION,
maxVersion: 'TLSv1.2'
};
}
exports.initServers = function(my_apps) {
servers.singleton = {
http: my_apps.main,
https: https.createServer(makeHTTPSOptions("test"), my_apps.main)
};
};
exports.findServerForIP = function(_ip, use_https) {
let result = servers.singleton;
return use_https ? result.https : result.http;
};

118
config/live-demo/config.js

@ -0,0 +1,118 @@
var servers = {};
const https = require("https");
const ip = require('ip');
const crypto = require('crypto');
const fs = require('fs');
var mainSubnet = ip.cidrSubnet("2602:806:a003:40e::/64");
var traceSubnet = ip.cidrSubnet("2602:806:a003:40f::/64");
var bibleSubnet = ip.cidrSubnet("2602:806:a003:40e:b1be::/80");
var i6t_subnet = ip.cidrSubnet("2602:806:a003:40e::1:0/112");
var my_bonnie1_subnet = ip.cidrSubnet("2602:806:a003:40f::4:0/112");
var sbcrtm_subnet = ip.cidrSubnet("2602:806:a003:40f:0:1:1:0/112");
var my_bonnie2_subnet = ip.cidrSubnet("2602:806:a003:40f:0:1:2:0/112");
var do_ssl_test = !!process.env.IPV6THINGS_DO_SSL_TEST;
function makeHTTPSOptions(key_name) {
return {
cert: fs.readFileSync(`${do_ssl_test ? "ssl_test/test" : "/rw_disk/i6t-ssl/" + key_name}.crt`),
key: fs.readFileSync(`${do_ssl_test ? "ssl_test/test" : "/rw_disk/i6t-ssl/" + key_name}.key`),
ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:HIGH:!aNULL:!MD5:!AESCCM',
secureOptions: crypto.constants.SSL_OP_NO_RENEGOTIATION,
maxVersion: do_ssl_test ? "TLSv1.2" : 'TLSv1.3'
};
}
exports.initServers = function(my_apps) {
let mainOptions = makeHTTPSOptions("main");
servers["!fallback"] = {
http: my_apps.main,
https: https.createServer(mainOptions, my_apps.main)
};
servers["!ipv6-things-dotcom"] = {
http: my_apps.main,
https: https.createServer(makeHTTPSOptions("ipv6-things-dotcom"), my_apps.main)
};
servers["!ipv6-bible"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible"), my_apps.ipv6bible)
};
servers["!ipv6-bible-7700"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible-group1"), my_apps.ipv6bible)
};
servers["!ipv6-bible-7710"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible-group2"), my_apps.ipv6bible)
};
servers["!ipv6-bible-7720"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible-group3"), my_apps.ipv6bible)
};
servers["!ipv6-bible-7a00"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible-group4"), my_apps.ipv6bible)
};
servers["!ipv6-bible-7a10"] = {
http: my_apps.ipv6bible,
https: https.createServer(makeHTTPSOptions("ipv6-bible-group5"), my_apps.ipv6bible)
};
let my_bonnie = my_apps.make_static("/rw_disk/ttgen-videos/bonnie/");
let sbcrtm = my_apps.make_static("/rw_disk/ttgen-videos/mountain/");
servers["!traceroute-bonnie"] = {
http: my_bonnie,
https: https.createServer(mainOptions, my_bonnie)
};
servers["!traceroute-bonnie-line1"] = {
http: my_bonnie,
https: https.createServer(makeHTTPSOptions("mbloo"), my_bonnie)
};
servers["!traceroute-mountain"] = {
http: sbcrtm,
https: https.createServer(mainOptions, sbcrtm)
};
servers["!traceroute-mountain-line1"] = {
http: sbcrtm,
https: https.createServer(makeHTTPSOptions("sbcrtm-1"), sbcrtm)
};
};
function findServerForIP_p(_ip) {
if (_ip.indexOf(":") < 0) return '!fallback';
let canonicalIPBuf = ip.toBuffer(_ip);
if (!(canonicalIPBuf.length === 16)) return '!fallback';
let b = canonicalIPBuf;
let ipString = ip.toString(canonicalIPBuf);
if (ipString.startsWith("2602:806:a003:40e:")) {
if ((b[8] === 0xb1) && (b[9] === 0xbe)) {
let value = '!ipv6-bible-' + Number((canonicalIPBuf[10] << 8) + (canonicalIPBuf[11] & 0xf0)).toString(16);
if (servers.hasOwnProperty(value)) {
return value;
}
return '!ipv6-bible';
}
if ((b[8] === 0) && (b[9] === 0) && (b[10] === 0) && (b[11] === 0) && (b[12] === 0) && (b[13] === 1)) {
return '!ipv6-things-dotcom';
}
}
switch (ipString) {
case '2602:806:a003:40f::4:1':
case '2602:806:a003:40f::4:3':
case '2602:806:a003:40f:0:1:2:ff01':
return '!traceroute-bonnie-line1';
case '2602:806:a003:40f:0:1:1:ff10':
return '!traceroute-mountain-line1';
}
if (ipString.startsWith("2602:806:a003:40f:")) {
if ((b[8] === 0) && (b[9] === 0) && (b[10] === 0)) {
switch((b[11] << 16) + (b[12] << 8) + b[13]) {
case 0x4:
case 0x10002:
return '!traceroute-bonnie';
case 0x10001:
return '!traceroute-mountain';
}
}
}
return '!fallback';
}
exports.findServerForIP = function(_ip, use_https) {
let result = servers[findServerForIP_p(String(_ip))];
return use_https ? result.https : result.http;
};

5
main/.gitignore

@ -0,0 +1,5 @@
node_modules/
package-lock.json
ipv6-things.json
public/
live-demo/ipv6things_db.json

0
examples/auxtext2.js → main/examples/auxtext2.js

0
examples/ipv6things_db.json → main/examples/ipv6things_db.json

0
examples/runtimeConfig.json → main/examples/runtimeConfig.json

0
index.js → main/index.js

0
live-demo/auxtext2.js → main/live-demo/auxtext2.js

0
live-demo/runtimeConfig.json → main/live-demo/runtimeConfig.json

0
page.js → main/page.js

0
scp-aliases.json → main/scp-aliases.json

0
webserver-tester.js → main/webserver-tester.js

12
webserver.js → main/webserver.js

@ -1,9 +1,13 @@
var i6tlib = require("./page.js");
var ip = require("ip");
function mountExpress(app, isTesting) {
app.use("/", (req, res, next) => {
res.set("Strict-Transport-Security", "max-age=31536000");
next();
});
app.get("/", function(req, res) {
let l_ip = String(req.get("X-Ipv6things-LocalIP") || (isTesting ? req.query.localIP : "unknown"));
let r_ip = String(req.get("X-Ipv6things-RemoteIP") || (isTesting ? "2001:db8::1" : "unknown"));
let l_ip = isTesting === 'newVersion' ? String(req.socket.localAddress) : String(req.get("X-Ipv6things-LocalIP") || (isTesting ? req.query.localIP : "unknown"));
let r_ip = isTesting === 'newVersion' ? String(req.ip) : String(req.get("X-Ipv6things-RemoteIP") || (isTesting ? "2001:db8::1" : "unknown"));
let xff_ip = req.get("CF-Connecting-IP") || req.get("X-Forwarded-For") || null;
if (!l_ip.match(/^[0-9a-f:.]*$/)) {
res.sendStatus(500);
@ -32,5 +36,9 @@ function mountExpress(app, isTesting) {
let t = String(req.query.type);
res.redirect(302, i6tlib.generateRandom(t));
});
app.get('/ipv6_check.css', function(req, res) {
res.set("Content-Type", "text/css");
res.status(200).send('.__pjo_ipv6_banner {display: block} .__pjo_no_ipv6_banner {display: none}');
});
}
exports.mountExpress = mountExpress;

3
ssl_test/readme.txt

@ -0,0 +1,3 @@
Generate testing key with:
openssl req -new -x509 -out test.crt -keyout test.key -nodes -subj /
Loading…
Cancel
Save