-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2786e8d
commit 1290366
Showing
9 changed files
with
217 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,2 @@ | ||
dependencies: | ||
bun.sh: ^1.0.30 | ||
mkcert.dev: ^1.4.4 | ||
mozilla.org/nss: ^3.92.0 # if you test locally using Firefox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/bin/bash | ||
|
||
#/ Add the root CA to the system trust store | ||
# This script is used to add the root CA to the system trust store. | ||
# | ||
# Usage: | ||
# | ||
# 1. Run the script - ./add-root-ca.sh | ||
# 2. Enter the password when prompted | ||
# 3. The root CA will be added to the system trust store | ||
#/ | ||
|
||
CERT_PATH="$HOME/.stacks/ssl/keys/rootCA.crt" | ||
DEST_PATH="/usr/local/share/ca-certificates/rootCA.crt" | ||
|
||
if [[ "$OSTYPE" == "linux-gnu"# ]]; then | ||
if [ -f "$DEST_PATH" ]; then | ||
echo "$DEST_PATH already exists." | ||
read -p "Do you want to overwrite it? [y/N] " -n 1 -r | ||
echo # move to a new line | ||
if [[ ! $REPLY =~ ^[Yy]$ ]] | ||
then | ||
echo "Operation cancelled." | ||
exit 1 | ||
fi | ||
fi | ||
sudo cp "$CERT_PATH" "$DEST_PATH" | ||
sudo update-ca-certificates | ||
elif [[ "$OSTYPE" == "darwin"* ]]; then | ||
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$CERT_PATH" | ||
elif [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then | ||
powershell.exe -Command "Import-Certificate -FilePath '$CERT_PATH' -CertStoreLocation Cert:\LocalMachine\Root" | ||
else | ||
echo "OS not supported" | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { generateAndSaveCertificates, generateRootCA } from '../src/keys' | ||
|
||
// Generate a root key and certificate (self-signed) | ||
generateRootCA() | ||
|
||
// Generate a keypair and create an X.509v3 certificate for the domain | ||
generateAndSaveCertificates() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export { config } from './config' | ||
export * from './keys' | ||
export * from './start' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import fs from 'node:fs' | ||
import path from 'node:path' | ||
import os from 'node:os' | ||
import forge from 'node-forge' | ||
import { log, italic } from '@stacksjs/cli' | ||
|
||
// Function to generate and save keys, certificates, and CA bundle | ||
export async function generateAndSaveCertificates({ | ||
commonName = 'stacks.localhost', | ||
countryName = 'US', | ||
stateName = 'California', | ||
localityName = 'Playa Vista', | ||
organizationName = 'Stacks', | ||
organizationalUnitName = 'Test', | ||
validityYears = 1, | ||
} = {}) { | ||
// Generate a root key and certificate (self-signed) | ||
const rootKeys = forge.pki.rsa.generateKeyPair(2048) | ||
const rootCert = forge.pki.createCertificate() | ||
rootCert.publicKey = rootKeys.publicKey | ||
rootCert.serialNumber = '01' | ||
rootCert.validity.notBefore = new Date() | ||
rootCert.validity.notAfter = new Date() | ||
rootCert.validity.notAfter.setFullYear(rootCert.validity.notBefore.getFullYear() + validityYears) | ||
const rootAttrs = [{ | ||
name: 'countryName', | ||
value: countryName, | ||
}, { | ||
name: 'stateOrProvinceName', | ||
value: stateName, | ||
}, { | ||
name: 'localityName', | ||
value: localityName, | ||
}, { | ||
name: 'organizationName', | ||
value: organizationName, | ||
}, { | ||
name: 'organizationalUnitName', | ||
value: organizationalUnitName, | ||
}, { | ||
name: 'commonName', | ||
value: 'Example Root CA', | ||
}] | ||
rootCert.setSubject(rootAttrs) | ||
rootCert.setIssuer(rootAttrs) // Self-signed, so issuer is the same | ||
rootCert.sign(rootKeys.privateKey) | ||
|
||
// Generate a keypair and create an X.509v3 certificate for the domain | ||
const keys = forge.pki.rsa.generateKeyPair(2048) | ||
const cert = forge.pki.createCertificate() | ||
cert.publicKey = keys.publicKey | ||
cert.serialNumber = '01' | ||
cert.validity.notBefore = new Date() | ||
cert.validity.notAfter = new Date() | ||
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + validityYears) | ||
const attrs = [{ | ||
name: 'countryName', | ||
value: countryName, | ||
}, { | ||
name: 'stateOrProvinceName', | ||
value: stateName, | ||
}, { | ||
name: 'localityName', | ||
value: localityName, | ||
}, { | ||
name: 'organizationName', | ||
value: organizationName, | ||
}, { | ||
name: 'organizationalUnitName', | ||
value: organizationalUnitName, | ||
}, { | ||
name: 'commonName', | ||
value: commonName, | ||
}] | ||
cert.setSubject(attrs) | ||
cert.setIssuer(rootAttrs) // Issued by the root CA | ||
cert.sign(rootKeys.privateKey) // Signed with the root CA's private key | ||
|
||
// Convert certificates and key to PEM format | ||
const pemCert = forge.pki.certificateToPem(cert) | ||
const pemRootCert = forge.pki.certificateToPem(rootCert) | ||
const pemKey = forge.pki.privateKeyToPem(keys.privateKey) | ||
|
||
// Bundle root certificate (and intermediates if any) into a CA bundle | ||
const caBundle = pemRootCert // + pemIntermediateCert; if you have intermediates | ||
|
||
// Define the directory to save the keys and certificates | ||
const saveDir = path.join(os.homedir(), '.stacks', 'ssl', 'keys') | ||
if (!fs.existsSync(saveDir)) | ||
fs.mkdirSync(saveDir, { recursive: true }) | ||
|
||
// Write the PEM-formatted files to disk | ||
fs.writeFileSync(path.join(saveDir, `${commonName}.crt`), pemCert) | ||
fs.writeFileSync(path.join(saveDir, 'rootCA.crt'), pemRootCert) | ||
fs.writeFileSync(path.join(saveDir, `${commonName}.ca-bundle`), caBundle) | ||
fs.writeFileSync(path.join(saveDir, `${commonName}.key`), pemKey) | ||
|
||
log.success(`Certificates and private key have been generated and saved to ${saveDir}`) | ||
} | ||
|
||
export async function generateRootCA({ | ||
countryName = 'US', | ||
stateName = 'California', | ||
localityName = 'Playa Vista', | ||
organizationName = 'Stacks', | ||
organizationalUnitName = 'Test', | ||
} = {}) { | ||
// Generate a root key and certificate (self-signed) | ||
const rootKeys = forge.pki.rsa.generateKeyPair(2048) | ||
const rootCert = forge.pki.createCertificate() | ||
rootCert.publicKey = rootKeys.publicKey | ||
rootCert.serialNumber = '01' | ||
rootCert.validity.notBefore = new Date() | ||
rootCert.validity.notAfter = new Date() | ||
rootCert.validity.notAfter.setFullYear(rootCert.validity.notBefore.getFullYear() + 1) | ||
const rootAttrs = [{ | ||
name: 'countryName', | ||
value: countryName, | ||
}, { | ||
name: 'stateOrProvinceName', | ||
value: stateName, | ||
}, { | ||
name: 'localityName', | ||
value: localityName, | ||
}, { | ||
name: 'organizationName', | ||
value: organizationName, | ||
}, { | ||
name: 'organizationalUnitName', | ||
value: organizationalUnitName, | ||
}, { | ||
name: 'commonName', | ||
value: 'Example Root CA', | ||
}] | ||
rootCert.setSubject(rootAttrs) | ||
rootCert.setIssuer(rootAttrs) // Self-signed, so issuer is the same | ||
rootCert.sign(rootKeys.privateKey) | ||
|
||
// Convert certificates and key to PEM format | ||
const pemRootCert = forge.pki.certificateToPem(rootCert) | ||
const pemRootKey = forge.pki.privateKeyToPem(rootKeys.privateKey) | ||
|
||
// Define the directory to save the keys and certificates | ||
const saveDir = path.join(os.homedir(), '.stacks', 'ssl', 'keys') | ||
if (!fs.existsSync(saveDir)) | ||
fs.mkdirSync(saveDir, { recursive: true }) | ||
|
||
// Write the PEM-formatted files to disk | ||
fs.writeFileSync(path.join(saveDir, 'rootCA.crt'), pemRootCert) | ||
fs.writeFileSync(path.join(saveDir, 'rootCA.key'), pemRootKey) | ||
|
||
log.success(`Root CA has been generated and saved to ${italic(saveDir)}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters