Ind.ie is now Small Technology Foundation.
Commit 4083b5a7 authored by Aral Balkan's avatar Aral Balkan

Seamlessly installs certutil on Linux (only tested with apt)

parent 93e531bf
......@@ -9,13 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Nothing yet.
## [1.3.2] - 2019-02-24
### Added
- Seamless installation of certutil dependency on Linux (only tested with apt)
## [1.3.1] - 2019-02-24
### Added
- Binary; you can now install it globally and run it as nodecert
- Binary; you can now install it globally and run it as `nodecert`.
### Changed
- mkcert version no longer coupled to app version from package.json
- `mkcert` version no longer coupled to app version from _package.json_.
## [1.3.0] - 2019-02-24
......
......@@ -2,6 +2,7 @@
A Node.js wrapper that uses the 64-bit [mkcert](https://github.com/FiloSottile/mkcert/) release binaries (Linux, macOS, Windows) to:
* Automatically install the _certutil_ dependecy on Linux on systems with apt, yum (untested), and pacman (untested)
* Create a root Certificate Authority
* Create TLS certificates for localhost, 127.0.0.1, and ::1
......@@ -11,12 +12,11 @@ For more details, [see the mkcert README](https://github.com/FiloSottile/mkcert/
## Installation
1. [Install the prerequisite](#prerequisite)
2. `npm i -g nodecert`
`npm i -g nodecert`
## Usage
(On macOS, you must [manually install the dependency](#macos-dependency) for now.)
Make sure you have the prerequisite ([nss](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/tools/NSS_Tools_certutil)) installed.
## Usage
```sh
nodecert
......@@ -24,17 +24,7 @@ nodecert
Your certificates will be created in the _~/.nodecert_ directory.
## Prerequisite
### Linux
For your certificate to work in Chrome and Firefox:
* apt: `sudo apt install libnss3-tools`
* yum: `sudo yum install nss-tools`
* pacman: `sudo pacman -S nss`
## macOS
## macOS Dependency
For your certificate to work in Firefox:
......@@ -43,4 +33,9 @@ For your certificate to work in Firefox:
## Help wanted
* Has not been tested on Windows (64-bit only). If anyone wants to give it a shot and let me know how/if it works, I’d appreciate it.
* Has not been tested on Windows (64-bit only).
* _certutil_ auto-installation has not been tested with yum.
* _certutil_ auto-installation has not been tested with pacman.
* _nss_ auto-installation not implemented yet on macOS.
If you want to give nodecert a shot on these platforms and [let me know how/if it works](https://github.com/indie-mirror/nodecert/issues), I’d appreciate it.
......@@ -3,11 +3,66 @@ const path = require('path')
const fs = require('fs')
const childProcess = require('child_process')
const _platform = os.platform()
const _architecture = os.arch()
const homeDir = os.homedir()
const nodecertDir = path.join(homeDir, '.nodecert')
const mkcertBinary = mkcertBinaryForThisMachine()
module.exports = function () {
// Create certificates.
if (!allOK()) {
// On Linux and on macOS, mkcert relies on the Mozilla nss library.
// Make sure this is installed before continuing.
ensurePrerequisite()
// Create the directory if it doesn’t already exist.
if (!fs.existsSync(nodecertDir)) {
fs.mkdirSync(nodecertDir)
}
// mkcert uses the CAROOT environment variable to know where to create/find the certificate authority.
// We also pass the rest of the system environment to the spawned processes.
const options = {
env: process.env
}
options.env.CAROOT = nodecertDir
try {
// Create the local certificate authority.
childProcess.execFileSync(mkcertBinary, ['-install'], options)
// Create the local certificate.
const createCertificateArguments = [
`-key-file=${path.join(nodecertDir, 'localhost-key.pem')}`,
`-cert-file=${path.join(nodecertDir, 'localhost.pem')}`,
'localhost', '127.0.0.1', '::1'
]
childProcess.execFileSync(mkcertBinary, createCertificateArguments, options)
} catch (error) {
console.log(error)
}
if (!allOK()) {
process.exit(1)
}
} else {
console.log('📜 [nodecert] Local development TLS certificate exists.')
}
}()
// Check if the local certificate authority and local keys exist.
function allOK() {
return fs.existsSync(path.join(nodecertDir, 'rootCA.pem')) && fs.existsSync(path.join(nodecertDir, 'rootCA-key.pem')) && fs.existsSync(path.join(nodecertDir, 'localhost.pem')) && fs.existsSync(path.join(nodecertDir, 'localhost-key.pem'))
}
const _platform = os.platform()
const _architecture = os.arch()
// Returns the mkcert binary for this machine (platform + architecture) and
// throws an error if there isn’t one for it.
function mkcertBinaryForThisMachine() {
const platformMap = {
linux: 'linux',
darwin: 'darwin',
......@@ -31,30 +86,66 @@ module.exports = function () {
if (platform === 'windows') mkcertBinary += '.exe'
const homeDir = os.homedir()
const nodecertDir = path.join(homeDir, '.nodecert')
// Check if the platform + architecture combination is supported.
if (!fs.existsSync(mkcertBinary)) throw new Error(`Unsupported platform + architecture combination for ${platform}-${architecture}`)
// Check if the local certificate authority and local keys exist.
function allOK() {
return fs.existsSync(path.join(nodecertDir, 'rootCA.pem')) && fs.existsSync(path.join(nodecertDir, 'rootCA-key.pem')) && fs.existsSync(path.join(nodecertDir, 'localhost.pem')) && fs.existsSync(path.join(nodecertDir, 'localhost-key.pem'))
return mkcertBinary
}
// Does the passed command exist? Returns: bool.
function commandExists (command) {
try {
childProcess.execFileSync('which', [command], {env: process.env})
return true
} catch (error) {
return false
}
}
let log = []
if (!allOK()) {
// Create certificates.
if (!fs.existsSync(nodecertDir)) {
fs.mkdirSync(nodecertDir)
// On Linux, we must install nss for mkcert to work with both Chrome and Firefox.
// Depending on the platform we try to do so using apt, yum, or pacman. If none of
// those exist, we fail.
function installCertutilOnLinux() {
let options = {env: process.env}
try {
if (commandExists('apt')) {
options.env.DEBIAN_FRONTEND = 'noninteractive'
childProcess.execSync('sudo apt-get install -y -q libnss3-tools', options)
} else if (commandExists('yum')) {
// Untested.
childProcess.execSync('sudo yum install nss-tools', options)
} else if (commandExists('pacman')) {
// Untested.
childProcess.execSync('sudo pacman -S nss', options)
} else {
throw new Error('No supported package manager found for installing certutil on Linux (tried apt, yum, and pacman. Please install certutil manually and run nodecert again. For more instructions on installing mkcert dependencies, please see https://github.com/FiloSottile/mkcert/')
}
childProcess.execFile(mkcertBinary, ['-install'], {env: { CAROOT: nodecertDir, PATH: process.env.PATH},}, (error, stdout, stderr) => {
log = log.concat([error, stdout, stderr])
childProcess.execFile(mkcertBinary, [`-key-file=${path.join(nodecertDir, 'localhost-key.pem')}`, `-cert-file=${path.join(nodecertDir, 'localhost.pem')}`, 'localhost', '127.0.0.1', '::1'], {env: { CAROOT: nodecertDir }}, (error, stdout, stderr) => {
log = log.concat([error, stdout, stderr])
if (!allOK()) {
console.log(log)
process.exit(1)
}
})
})
} catch (error) {
throw error
}
}()
}
// Mozilla’s nss is a prerequisite on Linux (for Chrome and Firefox)
// and on macOS (for Firefox). Ensure it exists.
function ensurePrerequisite() {
if (_platform === 'linux') {
if (commandExists('certutil')) return
try {
installCertutilOnLinux()
} catch (error) {
console.log(error)
process.exit(1)
}
} else if (_platform === 'darwin') {
// On macOS, we must install nss for mkcert to work with Firefox. To
// install nss, we can use either Homebrew or Macports. If neither of
// those are installed, we default to installing Homebrew and using that
// to install nss.
console.log('Automatic nss/certutil installation on macOS has not been implemented yet. For instructions on installing mkcert dependencies, please see https://github.com/FiloSottile/mkcert/')
// TODO
}
}
{
"name": "nodecert",
"version": "1.3.1",
"version": "1.3.2",
"description": "mkcert wrapper for Node.js",
"main": "index.js",
"bin": "bin/nodecert.js",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment