// @ts-ignore import DHT from "@hyperswarm/dht"; // @ts-ignore import {relay} from "@hyperswarm/dht-relay"; // @ts-ignore import Stream from "@hyperswarm/dht-relay/ws"; import express, {Express} from "express"; import path from "path"; import {fileURLToPath} from "url"; import config from "./config.js"; import * as http from "http"; import * as https from "https"; import * as tls from "tls"; import * as acme from "acme-client"; import {Buffer} from "buffer"; import {intervalToDuration} from "date-fns"; import cron from "node-cron"; import {get as getDHT} from "./dht.js"; import WS from "ws"; // @ts-ignore import DHT from "@hyperswarm/dht"; import {pack} from "msgpackr"; import {overwriteRegistryEntry} from "libskynetnode"; import {hashDataKey} from "./util.js"; let sslCtx: tls.SecureContext = tls.createSecureContext(); const sslParams: tls.SecureContextOptions = {}; const sslPrivateKey = await acme.forge.createPrivateKey(); const acmeClient = new acme.Client({ accountKey: sslPrivateKey, directoryUrl: acme.directory.letsencrypt.production, }); let app: Express; let router = express.Router(); export async function start() { const relayPort = config.str("relay-port"); app = express(); app.use(function (req, res, next) { router(req, res, next); }); let httpsServer = https.createServer({ SNICallback(servername, cb) { cb(null, sslCtx); }, }); let httpServer = http.createServer(app); cron.schedule("0 * * * *", createOrRenewSSl); await new Promise((resolve) => { httpServer.listen(80, "0.0.0.0", function () { console.info("HTTP Listening on ", httpServer.address()); resolve(null); }); }); const dht = await getDHT(); let wsServer = new WS.Server({server: httpsServer}); wsServer.on("connection", (socket: any) => { relay(dht, new Stream(false, socket)); }); await new Promise((resolve) => { httpsServer.listen(relayPort, "0.0.0.0", function () { console.info("Relay started on ", httpsServer.address()); resolve(null); }); }); await createOrRenewSSl(); } async function createOrRenewSSl() { if (sslParams.cert) { const expires = ( await acme.forge.readCertificateInfo(sslParams.cert as Buffer) ).notAfter; let duration = intervalToDuration({start: new Date(), end: expires}); let daysLeft = (duration.months as number) * 30 + (duration.days as number); if (daysLeft > 30) { return; } } const [certificateKey, certificateRequest] = await acme.forge.createCsr({ commonName: config.str("relay-domain"), }); sslParams.cert = await acmeClient.auto({ csr: certificateRequest, termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuthorization) => { router.get( `/.well-known/acme-challenge/${challenge.token}`, (req, res) => { res.send(keyAuthorization); } ); }, challengeRemoveFn: async () => { router = express.Router(); }, challengePriority: ["http-01"], }); sslParams.key = certificateKey; sslCtx = tls.createSecureContext(sslParams); console.log("SSL Certificate Updated"); }