diff --git a/.gitignore b/.gitignore index d9f5d89..7568b27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,15 @@ +# MacOS +.DS_STORE + +# IDEs .idea *.iml -.DS_STORE + +# Node node_modules + +# Other coverage +cert/CA.* +cert/localhost.* +cert/server.csr diff --git a/README.md b/README.md index b8f9bd2..756ad1d 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,6 @@ Serve static files or import as module in your project. [![npm version](https://img.shields.io/npm/v/https-localhost.svg)](https://www.npmjs.com/package/https-localhost?activeTab=versions) -### Install and trust the certificate -Add the [rootCA.pem](rootCA.pem) certificate to your list of trusted certificates. -This step depends on the operating system you're running: - -- Mac OS: open Keychain Access, choose System from the left navigation bar, choose "Import items..." from the File app -menu and select the file. Then double-click on the certificate and select always-trust in the Trust panel. - -- Linux: Depending on your Linux distribution, you can use `trust`, `update-ca-certificates` or another command to mark -the generated root certificate as trusted. - - ### Use standalone From terminal navigate into the folder and run `sudo npm install -g` to install this tool globally. @@ -51,5 +40,27 @@ To redirect the http traffic to https use `app.redirect()`. You can also serve static files with `app.serve(path)` +### [Optional/Linux] Install and trust the certificate +After `npm install` will run a script that tries to install and validate automatically the certificate. +**Actually works only on MacOS.** + +However, this script is in beta and provided as-is, so there isn't any guarantee that will work. +For that reason you can also install the certificate manually, as follows. + +If you decide to not install it, it's fine, the package still work. +However, visiting localhost there will be a invalid certificate issue. + +To trust the certificate just add the [cert/defaultCA.pem](cert/defaultCA.pem) certificate +to your list of trusted certificates. + +This step depends on the operating system you're running: +- Mac OS: + open Keychain Access, choose System from the left navigation bar, choose "Import items..." from the File app +menu and select the file. Then double-click on the certificate and select always-trust in the Trust panel. +- Linux: + Depending on your Linux distribution, you can use `trust`, `update-ca-certificates` +or another command to mark the generated root certificate as trusted. + + ### License [AGPL-3.0](LICENSE) diff --git a/cert/server.crt b/cert/default.crt similarity index 100% rename from cert/server.crt rename to cert/default.crt diff --git a/cert/server.key b/cert/default.key similarity index 100% rename from cert/server.key rename to cert/default.key diff --git a/rootCA.pem b/cert/defaultCA.pem similarity index 100% rename from rootCA.pem rename to cert/defaultCA.pem diff --git a/cert/generate.js b/cert/generate.js new file mode 100644 index 0000000..6c4348d --- /dev/null +++ b/cert/generate.js @@ -0,0 +1,34 @@ +const exec = require("child_process").exec + +// noinspection FallThroughInSwitchStatementJS +switch (process.platform) { + case "darwin": // MacOS + console.log("\n----------------------------------------------\n" + + "Please input your sudo password when required.\n" + + "----------------------------------------------\n") + exec("bash cert/generate.sh", (error, stdout, stderr) => { + console.log(stdout) + console.error(stderr) + if (error !== null) console.error(`exec error: ${error}`) + }) + break + case "linux": + console.warn("Cannot generate the localhost certificate on linux yet. " + + "Coming soon.") + process.exit(0) + case "win32": + console.warn("Cannot generate the localhost certificate on Windows.") + process.exit(0) + case "freebsd": + console.warn("Cannot generate the localhost certificate on freebsd. " + + "Help wanted.") + process.exit(0) + case "sunos": + console.warn("Cannot generate the localhost certificate on sunos. " + + "Help wanted.") + process.exit(0) + default: + console.warn("Cannot generate the localhost certificate on your " + + "platform. Contact the developer.") + process.exit(0) +} diff --git a/cert/generate.sh b/cert/generate.sh new file mode 100644 index 0000000..b85a2a5 --- /dev/null +++ b/cert/generate.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# capture errors and notify the user +set -e +trap 'if [[ $? -ne 0 ]]; then echo "ERROR: something went wrong."; fi' EXIT + +# check the os +case "$(uname -s)" in + Darwin*) machine=MacOS;; + Linux*) machine=Linux + echo "Linux support coming soon" + exit 1;; + CYGWIN*) machine=Linux + echo "WARNING: Support for Cygwin not guaranteed. Trying with the Linux script (coming soon)." + exit 1;; + MINGW*) machine=Linux + echo "WARNING: Support for MinGw not guaranteed. Trying with the Linux script (coming soon)." + exit 1;; + *) echo "Unknown operating system."; exit 1;; +esac + +# generate the CA +echo "Creating a certification authority to sign the certificate..." +openssl req -x509 -newkey rsa:4096 -keyout cert/CA.key -out cert/CA.pem -days 1024 -nodes -subj "/C=US/ST=None/L=None/O=None/OU=None/CN=localhost" +echo "Generated CA.key and CA.pem." + +# install the CA +case ${machine} in + MacOS*) + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain cert/CA.pem + ;; + Linux*) + echo "WARNING: Only Ubuntu is supported. No guarantee for other Linux distributions." + sudo mkdir /usr/local/share/ca-certificates/localhost + cp cert/CA.key /usr/local/share/ca-certificates/localhost/CA.key + cp cert/CA.pem /usr/local/share/ca-certificates/localhost/CA.pem + sudo chmod 775 /usr/local/share/ca-certificates/localhost + sudo update-ca-certificates + ;; + *) exit 1;; +esac + +# crate the certificate +echo "Creating a certificate for localhost and signing with out CA..." +openssl req -new -sha256 -nodes -out cert/server.csr -newkey rsa:2048 -keyout cert/localhost.key -config cert/server.conf +openssl x509 -req -in cert/server.csr -CAkey cert/CA.key -CA cert/CA.pem -CAcreateserial -out cert/localhost.crt -days 1024 -sha256 -extfile cert/x509.ext +echo "Generated localhost.key and localhost.crt." diff --git a/cert/server.conf b/cert/server.conf new file mode 100644 index 0000000..4438bbb --- /dev/null +++ b/cert/server.conf @@ -0,0 +1,14 @@ +[req] +default_bits=2048 +prompt=no +default_md=sha256 +distinguished_name=dn + +[dn] +C=US +ST=None +L=None +O=None +OU=None +emailAddress=mail@example.com +CN=localhost diff --git a/cert/x509.ext b/cert/x509.ext new file mode 100644 index 0000000..ab9de5f --- /dev/null +++ b/cert/x509.ext @@ -0,0 +1,7 @@ +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = localhost diff --git a/index.js b/index.js index 104e210..ab5cffb 100755 --- a/index.js +++ b/index.js @@ -12,9 +12,21 @@ const minify = require("express-minify") /* CONFIGURE THE SERVER */ // SSL certificate -const certOptions = { - key: fs.readFileSync(path.resolve(__dirname, "cert/server.key")), - cert: fs.readFileSync(path.resolve(__dirname, "cert/server.crt")) +let certOptions +try { + certOptions = { + key: fs.readFileSync(path.resolve(__dirname, "cert/localhost.key")), + cert: fs.readFileSync(path.resolve(__dirname, "cert/localhost.crt")) + } +} catch (e) { + // istanbul ignore next + certOptions = { + key: fs.readFileSync(path.resolve(__dirname, "cert/default.key")), + cert: fs.readFileSync(path.resolve(__dirname, "cert/default.crt")) + } + // istanbul ignore next + console.warn("Using the default certificate. " + + "Validate it installing the defaultCA.pem certificate in the cert folder") } // create a server with express @@ -53,7 +65,7 @@ app.serve = function(path = process.cwd(), port = process.env.PORT || 443) { /* MAIN (running as script) */ // usage: `serve []` or `node index.js []` -/* istanbul ignore if */ +// istanbul ignore if if (require.main === module) { // retrieve the static path from the process argv or use the cwd // 1st is node, 2nd is serve or index.js, 3rd (if exists) is the path diff --git a/package.json b/package.json index 466aadb..6672883 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "pretest": "eslint --ignore-path .gitignore .", "test": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/*.js --exit", + "postinstall": "node cert/generate.js", "start": "node index.js" }, "bin": { @@ -30,7 +31,7 @@ "bugs": { "url": "https://github.com/daquinoaldo/https-localhost/issues" }, - "homepage": "https://daquinoaldo.github.io/https-localhost/", + "homepage": "https://daquinoaldo.github.io/https-localhost", "dependencies": { "compression": "^1.7.3", "express": "^4.16.4",