@sequencemedia/certificates 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @sequencemedia/certificates
2
+
3
+ ## Pre-requisites for Windows
4
+
5
+ Install the latest pre-built release of OpenSSL
6
+
7
+ ### Install with an MSI
8
+
9
+ Get an MSI from the [Win32/Win64 OpenSSL Installation Project](https://slproweb.com/products/Win32OpenSSL.html) (e.g., [3.0.7](https://slproweb.com/download/Win64OpenSSL-3_0_7.msi))
10
+
11
+ ### Or install with Chocolatey
12
+
13
+ ```
14
+ choco install openssl
15
+ ```
16
+
17
+ ### Add OpenSSL to the `PATH`
18
+
19
+ An [article on Medium](https://medium.com/swlh/installing-openssl-on-windows-10-and-updating-path-80992e26f6a1) also refers to the [OpenSSL Installation Project](https://slproweb.com/products/Win32OpenSSL.html) and describes (with screenshots) how to add OpenSSL to the `PATH`
20
+
21
+ Once you have added OpenSSL to the `PATH`, open a console and at the command prompt enter `openssl version` to confirm the installation
package/README.txt ADDED
@@ -0,0 +1,19 @@
1
+ https://betterprogramming.pub/how-to-create-trusted-ssl-certificates-for-your-local-development-13fd5aad29c6
2
+
3
+ https://www.section.io/engineering-education/how-to-get-ssl-https-for-localhost/
4
+
5
+ https://www.digicert.com/kb/ssl-support/openssl-quick-reference-guide.htm
6
+
7
+ https://www.ietf.org/rfc/rfc4514.txt
8
+
9
+ String X.500 AttributeType
10
+ ------ --------------------------------------------
11
+ CN commonName (2.5.4.3)
12
+ L localityName (2.5.4.7)
13
+ ST stateOrProvinceName (2.5.4.8)
14
+ O organizationName (2.5.4.10)
15
+ OU organizationalUnitName (2.5.4.11)
16
+ C countryName (2.5.4.6)
17
+ STREET streetAddress (2.5.4.9)
18
+ DC domainComponent (0.9.2342.19200300.100.1.25)
19
+ UID userId (0.9.2342.19200300.100.1.1)
@@ -0,0 +1,21 @@
1
+ const debug = require('debug')
2
+
3
+ const log = debug('@sequencemedia/certificates')
4
+
5
+ log('`localhost` is awake')
6
+
7
+ module.exports = {
8
+ compact: true,
9
+ comments: false,
10
+ presets: [
11
+ [
12
+ '@babel/env', {
13
+ targets: {
14
+ node: 'current'
15
+ },
16
+ useBuiltIns: 'usage',
17
+ corejs: 3
18
+ }
19
+ ]
20
+ ]
21
+ }
@@ -0,0 +1,16 @@
1
+ @echo off
2
+
3
+ if defined 1 (
4
+ set SUBJ=%1
5
+ ) else (
6
+ set SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
7
+ )
8
+
9
+ setlocal enableextensions
10
+ md certificates
11
+ endlocal
12
+
13
+ call scripts/bat/certificate-authority-key-pem.bat
14
+ call scripts/bat/certificate-authority-crt.bat
15
+ call scripts/bat/localhost-csr.bat
16
+ call scripts/bat/localhost-crt.bat
@@ -0,0 +1,101 @@
1
+ import debug from 'debug'
2
+ import os from 'node:os'
3
+ import ip from 'ip'
4
+ import {
5
+ exec
6
+ } from 'node:child_process'
7
+ import PATH from './where-am-i.mjs'
8
+ import config from './scripts/js/config.mjs'
9
+ import ext from './scripts/js/ext.mjs'
10
+ import toSubj from './scripts/js/to-subj.mjs'
11
+
12
+ const OPTIONS = {
13
+ maxBuffer: 1024 * 2000,
14
+ shell: true,
15
+ stdio: 'inherit'
16
+ }
17
+
18
+ const HOSTNAME = os.hostname()
19
+ const ADDRESS = ip.address()
20
+ const PLATFORM = os.platform()
21
+
22
+ const log = debug('@sequencemedia/certificates')
23
+ const info = debug('@sequencemedia/certificates:info')
24
+ const error = debug('@sequencemedia/certificates:error')
25
+
26
+ function bat (params) {
27
+ const command = `ca-and-certs.bat "${toSubj(params)}"`
28
+
29
+ info(command)
30
+
31
+ return (
32
+ new Promise((resolve, reject) => {
33
+ exec(command, { ...OPTIONS, cwd: PATH }, (e) => (!e) ? resolve() : reject(e))
34
+ })
35
+ )
36
+ }
37
+
38
+ function sh (params) {
39
+ const command = `./ca-and-certs.sh "${toSubj(params)}"`
40
+
41
+ info(command)
42
+
43
+ return (
44
+ new Promise((resolve, reject) => {
45
+ exec(command, { ...OPTIONS, cwd: PATH }, (e) => (!e) ? resolve() : reject(e))
46
+ })
47
+ )
48
+ }
49
+
50
+ log('`ca-and-certs` is awake')
51
+
52
+ async function app () {
53
+ try {
54
+ await ext(HOSTNAME, ADDRESS)
55
+
56
+ const {
57
+ country,
58
+ state,
59
+ locality,
60
+ organisation,
61
+ commonName,
62
+ emailAddress
63
+ } = config
64
+
65
+ info({
66
+ country,
67
+ state,
68
+ locality,
69
+ organisation,
70
+ commonName,
71
+ emailAddress
72
+ })
73
+
74
+ return (PLATFORM === 'win32')
75
+ ? await bat({
76
+ country,
77
+ state,
78
+ locality,
79
+ organisation,
80
+ commonName,
81
+ emailAddress
82
+ })
83
+ : await sh({
84
+ country,
85
+ state,
86
+ locality,
87
+ organisation,
88
+ commonName,
89
+ emailAddress
90
+ })
91
+ } catch ({
92
+ code = 'N/A',
93
+ message = 'N/A'
94
+ }) {
95
+ error(code, message)
96
+
97
+ process.exit(1)
98
+ }
99
+ }
100
+
101
+ export default app()
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+
3
+ if [ -z "$1" ]
4
+ then
5
+ SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
6
+ else
7
+ SUBJ=$1
8
+ fi
9
+
10
+ mkdir certificates 2> /dev/null
11
+
12
+ source scripts/sh/certificate-authority-key-pem.sh
13
+ source scripts/sh/certificate-authority-crt.sh
14
+ source scripts/sh/localhost-csr.sh
15
+ source scripts/sh/localhost-crt.sh
package/certs.bat ADDED
@@ -0,0 +1,10 @@
1
+ @echo off
2
+
3
+ if defined 1 (
4
+ set SUBJ=%1
5
+ ) else (
6
+ set SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
7
+ )
8
+
9
+ call scripts/bat/localhost-csr.bat
10
+ call scripts/bat/localhost-crt.bat
package/certs.mjs ADDED
@@ -0,0 +1,101 @@
1
+ import debug from 'debug'
2
+ import os from 'node:os'
3
+ import ip from 'ip'
4
+ import {
5
+ exec
6
+ } from 'node:child_process'
7
+ import PATH from './where-am-i.mjs'
8
+ import config from './scripts/js/config.mjs'
9
+ import ext from './scripts/js/ext.mjs'
10
+ import toSubj from './scripts/js/to-subj.mjs'
11
+
12
+ const OPTIONS = {
13
+ maxBuffer: 1024 * 2000,
14
+ shell: true,
15
+ stdio: 'inherit'
16
+ }
17
+
18
+ const HOSTNAME = os.hostname()
19
+ const ADDRESS = ip.address()
20
+ const PLATFORM = os.platform()
21
+
22
+ const log = debug('@sequencemedia/certificates')
23
+ const info = debug('@sequencemedia/certificates:info')
24
+ const error = debug('@sequencemedia/certificates:error')
25
+
26
+ function bat (params) {
27
+ const command = `certs.bat "${toSubj(params)}"`
28
+
29
+ info(command)
30
+
31
+ return (
32
+ new Promise((resolve, reject) => {
33
+ exec(command, { ...OPTIONS, cwd: PATH }, (e) => (!e) ? resolve() : reject(e))
34
+ })
35
+ )
36
+ }
37
+
38
+ function sh (params) {
39
+ const command = `./certs.sh "${toSubj(params)}"`
40
+
41
+ info(command)
42
+
43
+ return (
44
+ new Promise((resolve, reject) => {
45
+ exec(command, { ...OPTIONS, cwd: PATH }, (e) => (!e) ? resolve() : reject(e))
46
+ })
47
+ )
48
+ }
49
+
50
+ log('`certs` is awake')
51
+
52
+ async function app () {
53
+ try {
54
+ await ext(HOSTNAME, ADDRESS)
55
+
56
+ const {
57
+ country,
58
+ state,
59
+ locality,
60
+ organisation,
61
+ commonName,
62
+ emailAddress
63
+ } = config
64
+
65
+ info({
66
+ country,
67
+ state,
68
+ locality,
69
+ organisation,
70
+ commonName,
71
+ emailAddress
72
+ })
73
+
74
+ return (PLATFORM === 'win32')
75
+ ? await bat({
76
+ country,
77
+ state,
78
+ locality,
79
+ organisation,
80
+ commonName,
81
+ emailAddress
82
+ })
83
+ : await sh({
84
+ country,
85
+ state,
86
+ locality,
87
+ organisation,
88
+ commonName,
89
+ emailAddress
90
+ })
91
+ } catch ({
92
+ code = 'N/A',
93
+ message = 'N/A'
94
+ }) {
95
+ error(code, message)
96
+
97
+ process.exit(1)
98
+ }
99
+ }
100
+
101
+ export default app()
package/certs.sh ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ if [ -z "$1" ]
4
+ then
5
+ SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
6
+ else
7
+ SUBJ=$1
8
+ fi
9
+
10
+ source scripts/sh/localhost-csr.sh
11
+ source scripts/sh/localhost-crt.sh
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@sequencemedia/certificates",
3
+ "version": "1.0.0",
4
+ "description": "Generate root CA and self-signed certificates with OpenSSL",
5
+ "type": "module",
6
+ "author": {
7
+ "name": "Jonathan Perry for Sequence Media Limited",
8
+ "email": "sequencemedia@sequencemedia.net",
9
+ "url": "http://sequencemedia.net"
10
+ },
11
+ "license": "ISC",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+ssh://git@github.com/sequencemedia/certificate-authority.git"
15
+ },
16
+ "homepage": "https://github.com/sequencemedia/certificates#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/sequencemedia/certificates/issues"
19
+ },
20
+ "scripts": {
21
+ "lint": "eslint . --ext cjs --ext mjs",
22
+ "lint:fix": "npm run lint -- --fix",
23
+ "ca-and-certs": "DEBUG=@sequencemedia/certificates:* node ca-and-certs.mjs",
24
+ "certs": "DEBUG=@sequencemedia/certificates:* node certs.mjs"
25
+ },
26
+ "dependencies": {
27
+ "debug": "^4.3.4",
28
+ "fs-extra": "^11.1.0",
29
+ "ip": "^1.1.8",
30
+ "nconf": "^0.12.0",
31
+ "os": "^0.1.2"
32
+ },
33
+ "devDependencies": {
34
+ "@babel/cli": "^7.20.7",
35
+ "@babel/core": "^7.20.12",
36
+ "@babel/eslint-parser": "^7.19.1",
37
+ "@babel/preset-env": "^7.20.2",
38
+ "core-js": "^3.27.1",
39
+ "eslint": "^8.31.0",
40
+ "eslint-config-standard": "^17.0.0",
41
+ "eslint-plugin-import": "^2.26.0",
42
+ "eslint-plugin-node": "^11.1.0",
43
+ "eslint-plugin-promise": "^6.1.1"
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ openssl x509 -outform pem -in certificates/certificate-authority.pem -out certificates/certificate-authority.crt
@@ -0,0 +1,5 @@
1
+ @echo off
2
+ if not defined SUBJ (
3
+ set SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
4
+ )
5
+ openssl req -x509 -nodes -new -sha512 -days 365 -newkey rsa:4096 -keyout certificates/certificate-authority.key -out certificates/certificate-authority.pem -subj %SUBJ%
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ openssl x509 -req -sha512 -days 365 -extfile certificates/localhost.ext -CA certificates/certificate-authority.crt -CAkey certificates/certificate-authority.key -CAcreateserial -in certificates/localhost.csr -out certificates/localhost.crt
@@ -0,0 +1,5 @@
1
+ @echo off
2
+ if not defined SUBJ (
3
+ set SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
4
+ )
5
+ openssl req -new -nodes -newkey rsa:4096 -keyout certificates/localhost.key -out certificates/localhost.csr -subj %SUBJ%
@@ -0,0 +1,29 @@
1
+ import debug from 'debug'
2
+ import nconf from 'nconf'
3
+
4
+ const log = debug('@sequencemedia/certificates')
5
+ const error = debug('@sequencemedia/certificates:error')
6
+
7
+ log('`config` is awake')
8
+
9
+ try {
10
+ nconf
11
+ .argv()
12
+ .file('certificates.json')
13
+ .required([
14
+ 'country',
15
+ 'state',
16
+ 'locality',
17
+ 'organisation',
18
+ 'commonName',
19
+ 'emailAddress'
20
+ ])
21
+ } catch ({
22
+ message = 'N/A'
23
+ }) {
24
+ error(message)
25
+
26
+ process.exit(1)
27
+ }
28
+
29
+ export default nconf.get()
@@ -0,0 +1,39 @@
1
+ import debug from 'debug'
2
+ import {
3
+ join
4
+ } from 'node:path'
5
+ import {
6
+ ensureDir
7
+ } from 'fs-extra'
8
+ import {
9
+ writeFile
10
+ } from 'node:fs/promises'
11
+ import PATH from '../../where-am-i.mjs'
12
+
13
+ const CERTIFICATES = join(PATH, 'certificates')
14
+ const FILE = join(CERTIFICATES, 'localhost.ext')
15
+
16
+ const log = debug('@sequencemedia/certificates')
17
+
18
+ function getExt (hostname, address) {
19
+ return (`
20
+ authorityKeyIdentifier = keyid, issuer
21
+ basicConstraints = CA:FALSE
22
+ keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
23
+ subjectAltName = @alt_names
24
+
25
+ [alt_names]
26
+ DNS.1 = localhost
27
+ IP.1 = 127.0.0.1
28
+ IP.2 = ::1
29
+ DNS.2 = ${hostname.toLowerCase()}
30
+ IP.3 = ${address}
31
+ `).trim().concat('\n')
32
+ }
33
+
34
+ log('`ext` is awake')
35
+
36
+ export default async function ext (hostname, address) {
37
+ await ensureDir(CERTIFICATES)
38
+ await writeFile(FILE, getExt(hostname, address))
39
+ }
@@ -0,0 +1,16 @@
1
+ import debug from 'debug'
2
+
3
+ const log = debug('@sequencemedia/certificates')
4
+
5
+ log('`toSubj` is awake')
6
+
7
+ export default function toSubj ({
8
+ country,
9
+ state,
10
+ locality,
11
+ organisation,
12
+ commonName,
13
+ emailAddress
14
+ }) {
15
+ return `/C=${country}/ST=${state}/L=${locality}/O=${organisation}/CN=${commonName}/emailAddress=${emailAddress}`
16
+ }
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+
3
+ openssl x509 -outform pem \
4
+ -in certificates/certificate-authority.pem \
5
+ -out certificates/certificate-authority.crt
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ if [ $# -eq 1 ]
4
+ then
5
+ SUBJ=$1
6
+ fi
7
+
8
+ if [ -z "$SUBJ" ]
9
+ then
10
+ SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
11
+ fi
12
+
13
+ openssl req -x509 -nodes -new -sha512 \
14
+ -days 365 \
15
+ -newkey rsa:4096 \
16
+ -keyout certificates/certificate-authority.key \
17
+ -out certificates/certificate-authority.pem \
18
+ -subj "$SUBJ"
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+
3
+ openssl x509 -req -sha512 -days 365 \
4
+ -extfile certificates/localhost.ext \
5
+ -CA certificates/certificate-authority.crt \
6
+ -CAkey certificates/certificate-authority.key \
7
+ -CAcreateserial \
8
+ -in certificates/localhost.csr \
9
+ -out certificates/localhost.crt
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+
3
+ if [ $# -eq 1 ]
4
+ then
5
+ SUBJ=$1
6
+ fi
7
+
8
+ if [ -z "$SUBJ" ]
9
+ then
10
+ SUBJ="/C=UK/ST=England/L=Greenwich/O=Sequence Media Limited/CN=Sequence Media/emailAddress=sequencemedia@sequencemedia.net"
11
+ fi
12
+
13
+ openssl req -new -nodes -newkey rsa:4096 \
14
+ -keyout certificates/localhost.key \
15
+ -out certificates/localhost.csr \
16
+ -subj "$SUBJ"
package/where-am-i.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ dirname
3
+ } from 'node:path'
4
+ import {
5
+ fileURLToPath
6
+ } from 'node:url'
7
+
8
+ export default dirname(fileURLToPath(import.meta.url))