diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd3e298..65db5d1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Version 2.0.0 ============= +- Fixed sslCert and sslPrivKey entries being ignored in the config. +- Changed ssl key creation to be done at startup instead of on npm install. + Breaking Changes ---------------- - Node.js versions below 10 are no longer supported. diff --git a/lib/generateSSLcert.js b/lib/generateSSLcert.js index 7731b2f7..4fbafd1b 100644 --- a/lib/generateSSLcert.js +++ b/lib/generateSSLcert.js @@ -1,49 +1,44 @@ -var forge = require("node-forge"); -forge.options.usePureJavaScript = true; -var fs = require("fs"); -var mkdirp = require("mkdirp"); +const forge = require("node-forge"); +const fs = require("fs-extra"); +const util = require("util"); -var pki = forge.pki; -var rsa = forge.pki.rsa; -var startTime, endTime; +const hrtime = process.hrtime.bigint; - -module.exports = function({ +module.exports = async function({ bits = 2048, - certificatePath = "database/certificate", + sslCertPath, + sslPrivKeyPath, doLogging = false, } = {}){ - function log(t){ + function log(t) { if(doLogging) console.log("lib/generateSSLcert.js | "+t); } - log("Generating SSL certificate with "+bits+" bits at "+certificatePath); + log("Generating SSL certificate with "+bits+" bits at "+sslCertPath); - startTime = Date.now(); - var keypair = rsa.generateKeyPair({bits: bits, e: 0x10001}); - endTime = Date.now(); - log("Generated 2048bit keypair in: "+(endTime-startTime)+" ms"); + let startNs = hrtime(); + let keypair = await util.promisify(forge.pki.rsa.generateKeyPair)({bits: bits, e: 0x10001}); + log("Generated 2048bit keypair in: "+(Number(hrtime()-startNs) / 1e6)+" ms"); - startTime = Date.now(); - var cert = pki.createCertificate(); + startNs = hrtime(); + let cert = forge.pki.createCertificate(); cert.publicKey = keypair.publicKey; cert.serialNumber = "01"; cert.validity.notBefore = new Date(); cert.validity.notAfter = new Date(Date.now()+(1000*60*60*24*365)); // valid for one year + // XXX This should probably be limited to the actual hostname + let attrs = [{ name: "commonName", value: "*" }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + // self-sign certificate cert.sign(keypair.privateKey); - // Convert certificate to pem type and write it to a file - if(certificatePath[certificatePath.length-1] != "/") certificatePath += "/"; - if(!fs.existsSync(certificatePath)) { - mkdirp.sync(certificatePath); - console.log("Created directory: "+certificatePath); - } - fs.writeFileSync(certificatePath+ "cert.key", pki.privateKeyToPem(keypair.privateKey)); - fs.writeFileSync(certificatePath+ "cert.crt", pki.certificateToPem(cert)); + // Write certificate and private key to pem files + await fs.outputFile(sslPrivKeyPath, forge.pki.privateKeyToPem(keypair.privateKey)); + await fs.outputFile(sslCertPath, forge.pki.certificateToPem(cert)); - endTime = Date.now(); - log("Generated certificate in: "+(endTime-startTime)+" ms"); + log("Generated certificate in: "+(Number(hrtime()-startNs) / 1e6)+" ms"); } diff --git a/lib/generateSSLcert.spec.js b/lib/generateSSLcert.spec.js index d65a35ee..b8e9306d 100644 --- a/lib/generateSSLcert.spec.js +++ b/lib/generateSSLcert.spec.js @@ -1,25 +1,26 @@ var assert = require("assert"); -var fs = require("fs"); +var fs = require("fs-extra"); var fileOps = require("lib/fileOps"); -var generateSSLcert = require("./generateSSLcert.js") +var generateSSLcert = require("lib/generateSSLcert.js") describe("generateSSLcert.js(options)", ()=>{ - it("Creates a folder with a .crt and .key file in it", ()=>{ - let certPath = "lib/certTestPlsDelete"; - assert(!fs.existsSync(certPath)); // if it already exsits, the test might pass because of leftover data (which is bad) + it("Creates a folder with a .crt and .key file in it", async function() { + let certPath = "lib/certTestPlsDelete/cert.crt"; + let privKeyPath = "lib/certTestPlsDelete/cert.key"; + assert(!await fs.exists(certPath)); // if it already exsits, the test might pass because of leftover data (which is bad) - generateSSLcert({ + await generateSSLcert({ // bits:512, // supported, but I just use the default of 2048 for this test - certificatePath:certPath, + sslCertPath: certPath, + sslPrivKeyPath: privKeyPath, doLogging: false, }); - assert(fs.existsSync(certPath)); - assert(fs.existsSync(certPath+"/cert.key")); // private key - assert(fs.existsSync(certPath+"/cert.crt")); // certificate file + assert(await fs.exists(certPath)); // private key + assert(await fs.exists(privKeyPath)); // certificate file // remove certificates and data from the test - fileOps.deleteFolderRecursiveSync(certPath); + fileOps.deleteFolderRecursiveSync("lib/certTestPlsDelete"); }).timeout(10000); -}); \ No newline at end of file +}); diff --git a/lib/npmPostinstall.js b/lib/npmPostinstall.js index 70ee1417..04300505 100644 --- a/lib/npmPostinstall.js +++ b/lib/npmPostinstall.js @@ -123,13 +123,3 @@ function processDownloadRecursive(callback){ } }); } - -// generate SSL certificates if they are missing -if(!fs.existsSync("database/certificates") || !fs.existsSync("database/certificates/cert.crt") || !fs.existsSync("database/certificates/cert.key")){ - var generateSSLcert = require("./generateSSLcert.js"); - - generateSSLcert({ - certificatePath: "database/certificates", - doLogging: true, - }); -} \ No newline at end of file diff --git a/master.js b/master.js index 6111539f..858d0843 100644 --- a/master.js +++ b/master.js @@ -41,6 +41,7 @@ mkdirp.sync(config.databaseDirectory); mkdirp.sync(masterModFolder); // homebrew modules +const generateSSLcert = require("lib/generateSSLcert"); const getFactorioLocale = require("lib/getFactorioLocale"); // homemade express middleware for token auth @@ -1005,6 +1006,15 @@ async function startServer() { process.exit(1); } + // Create a self signed certificate if the certificate files doesn't exist + if (httpsPort && !await fs.exists(config.sslCert) && !await fs.exists(config.sslPrivKey)) { + await generateSSLcert({ + sslCertPath: config.sslCert, + sslPrivKeyPath: config.sslPrivKey, + doLogging: true, + }); + } + // Load plugins await pluginManagement(); @@ -1016,8 +1026,15 @@ async function startServer() { } if (httpsPort) { - var certificate = fs.readFileSync(config.sslCert); - var privateKey = fs.readFileSync(config.sslPrivKey); + let certificate, privateKey; + try { + certificate = await fs.readFile(config.sslCert); + privateKey = await fs.readFile(config.sslPrivKey); + + } catch (err) { + console.error(`Error loading ssl certificate: ${err.message}`); + await shutdown() + } let httpsServer = require("https").createServer({ key: privateKey,