localhost-cert
Advanced tools
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| const https = require('https'); | ||
| const { getRootCrt } = require('./utils'); | ||
| const getLocalhostCerts = require('./getLocalhostCerts'); | ||
| const path = require('path'); | ||
| const fs = require('fs-extra'); | ||
| let testServer = null; | ||
| async function startTestServer() { | ||
| if (testServer) { | ||
| return testServer; | ||
| } | ||
| const testPort = 11790 + Math.floor(Math.random() * 100); | ||
| const options = getLocalhostCerts(); | ||
| try { | ||
| testServer = https.createServer(options, (req, res) => { | ||
| res.writeHead(200); | ||
| res.end('TESTSERVER'); | ||
| }); | ||
| testServer.on('error', (error) => { | ||
| testServer.close(); | ||
| }); | ||
| testServer.on('close', () => { | ||
| testServer = null; | ||
| }); | ||
| testServer.listen(testPort); | ||
| return { server: testServer, port: testPort }; | ||
| } catch (error) { | ||
| return null; | ||
| } | ||
| } | ||
| // 检测根证书的安装情况 | ||
| module.exports = async function checkRootCertificateInstallation() { | ||
| try { | ||
| // mac | ||
| if (process.platform === 'darwin') { | ||
| return await checkMacCert(); | ||
| } | ||
| // windows | ||
| else if (process.platform === 'win32') { | ||
| return await checkWinCert(); | ||
| } | ||
| // linux | ||
| else if (process.platform === 'linux') { | ||
| return await checkLinuxCert(); | ||
| } | ||
| } catch (error) { | ||
| console.log('error', error); | ||
| return false; | ||
| } | ||
| }; | ||
| function replaceEnter(str) { | ||
| try { | ||
| return str.replace(/\n/g, '').replace(/\r/g, '').replace(/\t/g, ''); | ||
| } catch (error) { | ||
| return str; | ||
| } | ||
| } | ||
| async function checkMacCert() { | ||
| const macCa = require('mac-ca'); | ||
| const rootCrt = await getRootCrt(); | ||
| const ca = await macCa.get(); | ||
| return ca.some((item) => { | ||
| return item && replaceEnter(item) === replaceEnter(rootCrt); | ||
| }); | ||
| } | ||
| async function checkWinCert() { | ||
| const ca = require('win-ca'); | ||
| rootCAs = []; | ||
| // Fetch all certificates in PEM format | ||
| ca({ | ||
| format: ca.der2.pem, | ||
| ondata: (crt) => { | ||
| rootCAs.push(crt); | ||
| }, | ||
| }); | ||
| const rootCrt = await getRootCrt(); | ||
| return rootCAs.some((item) => { | ||
| return item && replaceEnter(item) === replaceEnter(rootCrt); | ||
| }); | ||
| } | ||
| async function checkLinuxCert() { | ||
| return await fs.exists(`/usr/local/share/ca-certificates/root.crt`); | ||
| } |
| const forge = require('node-forge'); | ||
| const { writeCert } = require('./utils'); | ||
| module.exports = function createRootCert() { | ||
| 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() + 20 | ||
| ); | ||
| const attrs = [ | ||
| { | ||
| name: 'commonName', | ||
| value: 'Localhost Root Ca No.1', | ||
| }, | ||
| { | ||
| name: 'countryName', | ||
| value: 'US', | ||
| }, | ||
| { | ||
| shortName: 'ST', | ||
| value: 'Virginia', | ||
| }, | ||
| { | ||
| name: 'localityName', | ||
| value: 'Blacksburg', | ||
| }, | ||
| { | ||
| name: 'organizationName', | ||
| value: 'localhost-https', | ||
| }, | ||
| { | ||
| shortName: 'OU', | ||
| value: 'LH', | ||
| }, | ||
| ]; | ||
| cert.setSubject(attrs); | ||
| cert.setIssuer(attrs); | ||
| cert.setExtensions([ | ||
| { | ||
| name: 'basicConstraints', | ||
| cA: true, | ||
| }, | ||
| { | ||
| name: 'keyUsage', | ||
| keyCertSign: true, | ||
| digitalSignature: true, | ||
| nonRepudiation: true, | ||
| keyEncipherment: true, | ||
| dataEncipherment: true, | ||
| }, | ||
| { | ||
| name: 'subjectKeyIdentifier', | ||
| }, | ||
| ]); | ||
| cert.sign(keys.privateKey, forge.md.sha256.create()); | ||
| // generate a server keypair | ||
| const serverKeys = forge.pki.rsa.generateKeyPair(2048); | ||
| const serverCert = forge.pki.createCertificate(); | ||
| serverCert.publicKey = serverKeys.publicKey; | ||
| serverCert.serialNumber = '01'; | ||
| serverCert.validity.notBefore = new Date(); | ||
| serverCert.validity.notAfter = new Date(); | ||
| serverCert.validity.notAfter.setFullYear( | ||
| serverCert.validity.notBefore.getFullYear() + 20 | ||
| ); | ||
| const serverAttrs = [ | ||
| { | ||
| name: 'commonName', | ||
| value: 'Localhost Root Ca No.1', | ||
| }, | ||
| { | ||
| name: 'countryName', | ||
| value: 'US', | ||
| }, | ||
| { | ||
| shortName: 'ST', | ||
| value: 'Virginia', | ||
| }, | ||
| { | ||
| name: 'localityName', | ||
| value: 'Blacksburg', | ||
| }, | ||
| { | ||
| name: 'organizationName', | ||
| value: 'localhost-https', | ||
| }, | ||
| { | ||
| shortName: 'OU', | ||
| value: 'LH', | ||
| }, | ||
| ]; | ||
| serverCert.setSubject(serverAttrs); | ||
| serverCert.setIssuer(cert.subject.attributes); | ||
| serverCert.setExtensions([ | ||
| { | ||
| name: 'basicConstraints', | ||
| cA: false, | ||
| }, | ||
| { | ||
| name: 'keyUsage', | ||
| digitalSignature: true, | ||
| nonRepudiation: true, | ||
| keyEncipherment: true, | ||
| dataEncipherment: true, | ||
| }, | ||
| { | ||
| name: 'subjectAltName', | ||
| altNames: [ | ||
| { | ||
| type: 2, // DNS | ||
| value: 'localhost', | ||
| }, | ||
| ], | ||
| }, | ||
| ]); | ||
| serverCert.sign(keys.privateKey, forge.md.sha256.create()); | ||
| // save root certificate and key | ||
| const rootCrt = forge.pki.certificateToPem(cert); | ||
| const localhostCrt = forge.pki.certificateToPem(serverCert); | ||
| const localhostKey = forge.pki.privateKeyToPem(serverKeys.privateKey); | ||
| writeCert('root.pem', forge.pki.certificateToPem(cert)); | ||
| writeCert('root.crt', forge.pki.certificateToPem(cert)); | ||
| // save server certificate and key | ||
| writeCert('localhost.crt', forge.pki.certificateToPem(serverCert)); | ||
| writeCert( | ||
| 'localhost.key', | ||
| forge.pki.privateKeyToPem(serverKeys.privateKey) | ||
| ); | ||
| console.log('certs created'); | ||
| console.log('-----------------root.pem-----------------'); | ||
| console.log(rootCrt); | ||
| console.log('-----------------localhost.crt-----------------'); | ||
| console.log(localhostCrt); | ||
| console.log('-----------------localhost.key-----------------'); | ||
| console.log(localhostKey); | ||
| }; |
| const { readCert } = require('./utils'); | ||
| const getLocalhostCerts = () => { | ||
| const localhostCrt = readCert('localhost.crt'); | ||
| const localhostKey = readCert('localhost.key'); | ||
| return { | ||
| cert: localhostCrt, | ||
| key: localhostKey, | ||
| }; | ||
| }; | ||
| module.exports = getLocalhostCerts; |
| const cp = require('child_process'); | ||
| const process = require('process'); | ||
| var sudo = require('sudo-prompt'); | ||
| const path = require('path'); | ||
| module.exports = function install() { | ||
| // windows 运行 certutil -addstore -enterprise -f "Root" "C:\path\to\your\certificate.crt" | ||
| // mac 运行 sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /path/to/your/certificate.crt | ||
| // linux 运行 sudo cp /path/to/your/certificate.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates | ||
| // 以上命令均需要管理员权限 | ||
| try { | ||
| const crtPath = path.resolve(__dirname, '../certs/root.crt'); | ||
| if (process.platform === 'win32') { | ||
| const cmd = | ||
| 'certutil -addstore -enterprise -f "Root" "' + crtPath + '"'; | ||
| var options = { | ||
| name: 'Localhost Cert', | ||
| }; | ||
| sudo.exec(cmd, options, function (error, stdout, stderr) { | ||
| if (error) throw error; | ||
| }); | ||
| } else if (process.platform === 'darwin') { | ||
| const proce = cp.exec( | ||
| 'sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "' + | ||
| crtPath + | ||
| '"' | ||
| ); | ||
| proce.on('exit', function (code) { | ||
| console.log('child process exited with code ' + code); | ||
| }); | ||
| } else if (process.platform === 'linux') { | ||
| cp.exec( | ||
| 'sudo cp "' + | ||
| crtPath + | ||
| '" /usr/local/share/ca-certificates/ && sudo update-ca-certificates' | ||
| ); | ||
| } else { | ||
| console.log('unsupport platform:' + process.platform); | ||
| } | ||
| } catch (error) { | ||
| console.warn('install root certificate error:' + error); | ||
| console.warn( | ||
| 'please download at:https://github.com/IdeaNest-org/localhost-cert/blob/main/certs/root.crt and install root certificate manually' | ||
| ); | ||
| } | ||
| }; |
| const { Octokit } = require('@octokit/rest'); | ||
| const fs = require('fs'); | ||
| const { readCert } = require('./utils'); | ||
| function getGitHubToken() { | ||
| const token = process.env.GH_TOKEN; | ||
| if (!token) { | ||
| throw new Error('Please set the GH_TOKEN environment variable.'); | ||
| } | ||
| return token; | ||
| } | ||
| module.exports = async function uploadToGithub() { | ||
| const octokit = new Octokit({ | ||
| auth: getGitHubToken(), // 请替换为你的个人访问令牌 | ||
| }); | ||
| // 保存证书到本地 | ||
| async function uploadFileToGitHubRepo( | ||
| owner, | ||
| repo, | ||
| filePath, | ||
| branch, | ||
| message | ||
| ) { | ||
| const fileContent = fs.readFileSync(filePath, 'utf-8'); | ||
| const contentEncoded = Buffer.from(fileContent).toString('base64'); | ||
| try { | ||
| const response = await octokit.repos.createOrUpdateFileContents({ | ||
| owner: owner, | ||
| repo: repo, | ||
| path: filePath, | ||
| message: message, | ||
| content: contentEncoded, | ||
| branch: branch, | ||
| }); | ||
| console.log( | ||
| 'File uploaded to GitHub:', | ||
| response.data.content.html_url | ||
| ); | ||
| } catch (error) { | ||
| console.error('Error uploading file to GitHub:', error.message); | ||
| } | ||
| } | ||
| const rootCrt = readCert('root.crt'); | ||
| const localhostCrt = readCert('localhost.crt'); | ||
| const localhostKey = readCert('localhost.key'); | ||
| console.log(rootCrt); | ||
| console.log(localhostCrt); | ||
| console.log(localhostKey); | ||
| // 使用示例 | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'certs/root.crt', | ||
| 'main', | ||
| rootCrt | ||
| ); | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'certs/localhost.crt', | ||
| 'main', | ||
| localhostCrt | ||
| ); | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'certs/localhost.key', | ||
| 'main', | ||
| localhostKey | ||
| ); | ||
| }; |
| const path = require('path'); | ||
| const fs = require('fs-extra'); | ||
| function readFileFromDir(file) { | ||
| return fs.readFileSync(path.resolve(__dirname, '../', file), 'utf-8'); | ||
| } | ||
| function readFileFromDirAsync(file) { | ||
| return fs.readFile(path.resolve(__dirname, '../', file), 'utf-8'); | ||
| } | ||
| function getRootCrt() { | ||
| return readFileFromDirAsync('certs/root.crt'); | ||
| } | ||
| function writeFileToDir(file, content) { | ||
| return fs.writeFileSync(path.resolve(__dirname, '../', file), content); | ||
| } | ||
| function readCert(name) { | ||
| return readFileFromDir('certs/' + name); | ||
| } | ||
| function writeCert(name, content) { | ||
| return writeFileToDir('certs/' + name, content); | ||
| } | ||
| module.exports = { | ||
| readFileFromDir, | ||
| readFileFromDirAsync, | ||
| getRootCrt, | ||
| writeFileToDir, | ||
| readCert, | ||
| writeCert, | ||
| }; |
| const checkRootCertInstall = require('../modules/checkRootCertInstall'); | ||
| const installRootCert = require('../modules/installRootCert'); | ||
| checkRootCertInstall().then((res) => { | ||
| console.log(res); | ||
| if (!res) { | ||
| console.log('start install root cert') | ||
| installRootCert(); | ||
| } | ||
| }); |
| const createRootCert = require('../modules/createRootCert'); | ||
| function create() { | ||
| createRootCert(); | ||
| } | ||
| create(); |
| const getHttps = require('../index'); | ||
| console.log(getHttps()) |
| const uploadToGithub = require('../modules/uploadToGithub'); | ||
| uploadToGithub() |
| const { | ||
| readFileFromDir, | ||
| readFileFromDirAsync, | ||
| getRootCrt, | ||
| } = require('../modules/utils'); | ||
| console.log(readFileFromDir('certs/root.crt')); | ||
| readFileFromDirAsync('certs/root.crt').then((res) => { | ||
| console.log(res); | ||
| }); | ||
| getRootCrt().then((res) => { | ||
| console.log(res); | ||
| }); |
+2
-2
| // set cra https env | ||
| const path = require('path'); | ||
| process.env.HTTPS = true; | ||
| process.env.SSL_CRT_FILE = path.resolve(__dirname, '../localhost.crt'); | ||
| process.env.SSL_KEY_FILE = path.resolve(__dirname, '../localhost.key'); | ||
| process.env.SSL_CRT_FILE = path.resolve(__dirname, '../certs/localhost.crt'); | ||
| process.env.SSL_KEY_FILE = path.resolve(__dirname, '../certs/localhost.key'); |
+6
-6
| // 判断当前是否存在文件 | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const createRootCert = require('./createRootCert'); | ||
| const saveAndDelete = require('./saveAndDelete'); | ||
| const createRootCert = require('./modules/createRootCert'); | ||
| const uploadToGithub = require('./modules/uploadToGithub'); | ||
@@ -17,10 +17,10 @@ function isFileExist(filePath) { | ||
| if ( | ||
| !isFileExist(path.resolve(__dirname, 'root.pem')) || | ||
| !isFileExist(path.resolve(__dirname, 'localhost.key')) || | ||
| !isFileExist(path.resolve(__dirname, 'localhost.crt')) | ||
| !isFileExist(path.resolve(__dirname, 'certs/root.crt')) || | ||
| !isFileExist(path.resolve(__dirname, 'certs/localhost.key')) || | ||
| !isFileExist(path.resolve(__dirname, 'certs/localhost.crt')) | ||
| ) { | ||
| createRootCert(); | ||
| saveAndDelete(); | ||
| uploadToGithub(); | ||
| } else { | ||
| console.log('certs already exist'); | ||
| } |
+10
-120
@@ -1,122 +0,11 @@ | ||
| // 引导安装根证书 | ||
| const cp = require('child_process'); | ||
| const process = require('process'); | ||
| const path = require('path'); | ||
| const fs = require('fs-extra'); | ||
| const tls = require('tls'); | ||
| const https = require('https'); | ||
| var sudo = require('sudo-prompt'); | ||
| let testServer = null; | ||
| const testPort = 11790 + Math.floor(Math.random() * 100); | ||
| function install() { | ||
| // windows 运行 certutil -addstore -enterprise -f "Root" "C:\path\to\your\certificate.crt" | ||
| // mac 运行 sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /path/to/your/certificate.crt | ||
| // linux 运行 sudo cp /path/to/your/certificate.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates | ||
| // 以上命令均需要管理员权限 | ||
| try { | ||
| console.log('install root certificate'); | ||
| const crtPath = path.resolve(__dirname, 'root.crt'); | ||
| if (process.platform === 'win32') { | ||
| console.log('windows'); | ||
| const cmd = | ||
| 'certutil -addstore -enterprise -f "Root" "' + crtPath + '"'; | ||
| var options = { | ||
| name: 'Localhost Cert', | ||
| }; | ||
| sudo.exec(cmd, options, function (error, stdout, stderr) { | ||
| if (error) throw error; | ||
| }); | ||
| // cp.exec( | ||
| // 'certutil -addstore -enterprise -f "Root" "' + crtPath + '"' | ||
| // ); | ||
| } else if (process.platform === 'darwin') { | ||
| cp.exec( | ||
| 'sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "' + | ||
| crtPath + | ||
| '"' | ||
| ); | ||
| } else if (process.platform === 'linux') { | ||
| cp.exec( | ||
| 'sudo cp "' + | ||
| crtPath + | ||
| '" /usr/local/share/ca-certificates/ && sudo update-ca-certificates' | ||
| ); | ||
| } else { | ||
| console.log('unsupport platform:' + process.platform); | ||
| } | ||
| } catch (error) { | ||
| console.warn('install root certificate error:' + error); | ||
| console.warn( | ||
| 'please download at:https://github.com/IdeaNest-org/localhost-cert/blob/main/root.crt and install root certificate manually' | ||
| ); | ||
| } | ||
| } | ||
| const localhostCrt = readFileFromDir('localhost.crt'); | ||
| const localhostKey = readFileFromDir('localhost.key'); | ||
| // 检测根证书的安装情况 | ||
| async function checkRootCertificateInstallation() { | ||
| const rootCrt = await readFileFromDirAsync('root.crt'); | ||
| const options = { | ||
| ca: [rootCrt], // 添加你要验证的根证书 | ||
| checkServerIdentity: () => null, // 禁用服务器身份验证 | ||
| }; | ||
| // https 启动localhost 服务 | ||
| const server = startTestServer(); | ||
| if (!server) { | ||
| return false; | ||
| } | ||
| try { | ||
| return await new Promise((resolve, reject) => { | ||
| const socket = tls.connect(testPort, 'localhost', options, () => { | ||
| // server && server.close(); | ||
| socket.end(); | ||
| resolve(true); | ||
| }); | ||
| socket.on('error', (error) => { | ||
| // server && server.close(); | ||
| resolve(false); | ||
| socket.end(); | ||
| }); | ||
| }); | ||
| } catch (error) { | ||
| return false; | ||
| } | ||
| } | ||
| async function startTestServer() { | ||
| if (testServer) { | ||
| return testServer; | ||
| } | ||
| const options = getHttps({ | ||
| autoInstall: false, | ||
| }); | ||
| try { | ||
| testServer = https.createServer(options, (req, res) => { | ||
| res.writeHead(200); | ||
| res.end('Hello World!'); | ||
| }); | ||
| testServer.listen(testPort); | ||
| return testServer; | ||
| } catch (error) { | ||
| return null; | ||
| } | ||
| } | ||
| function readFileFromDir(file) { | ||
| return fs.readFileSync(path.resolve(__dirname, file), 'utf-8'); | ||
| } | ||
| function readFileFromDirAsync(file) { | ||
| return fs.readFile(path.resolve(__dirname, file), 'utf-8'); | ||
| } | ||
| // 调用检测函数 | ||
| module.exports = getHttps = ({ autoInstall = true } = {}) => { | ||
| const checkRootCertInstall = require('./modules/checkRootCertInstall'); | ||
| const installRootCert = require('./modules/installRootCert'); | ||
| const { readCert } = require('./modules/utils'); | ||
| const getHttpsConfig = ({ autoInstall = true } = {}) => { | ||
| if (autoInstall) { | ||
| checkRootCertificateInstallation().then((res) => { | ||
| checkRootCertInstall().then((res) => { | ||
| console.log('is root install', res); | ||
| if (!res) { | ||
| install(); | ||
| installRootCert(); | ||
| } | ||
@@ -126,5 +15,6 @@ }); | ||
| return { | ||
| cert: localhostCrt, | ||
| key: localhostKey, | ||
| cert: readCert('localhost.crt'), | ||
| key: readCert('localhost.key'), | ||
| }; | ||
| }; | ||
| module.exports = getHttpsConfig; |
+9
-3
| { | ||
| "name": "localhost-cert", | ||
| "version": "1.0.10", | ||
| "version": "1.0.13", | ||
| "main": "index.js", | ||
@@ -31,3 +31,7 @@ "scripts": { | ||
| "localhost-ssl", | ||
| "localhost-cert" | ||
| "localhost-cert", | ||
| "https-localhost", | ||
| "https-server", | ||
| "minica", | ||
| "mkcert" | ||
| ], | ||
@@ -43,3 +47,5 @@ "npmIgnore": [ | ||
| "fs-extra": "^11.1.1", | ||
| "sudo-prompt": "^9.2.1" | ||
| "mac-ca": "^2.0.3", | ||
| "sudo-prompt": "^9.2.1", | ||
| "win-ca": "^3.5.1" | ||
| }, | ||
@@ -46,0 +52,0 @@ "devDependencies": { |
+7
-13
| # Localhost Cert | ||
| # Localhost Https / Localhost Cert | ||
@@ -21,3 +21,3 @@ ## A secure and convenient solution for enabling HTTPS on localhost | ||
| To ensure that the private key is not remembered, Localhost Cert utilizes GitHub Actions to generate the root certificate. The process of generating the certificate and the code at that time are fully traceable on GitHub. If you're interested, you can view the [GitHub Action](https://github.com/IdeaNest-org/localhost-cert/actions/runs/7004987626/job/19053845251) for more details. | ||
| To ensure that the private key is not remembered, Localhost Cert utilizes GitHub Actions to generate the root certificate. The process of generating the certificate and the code at that time are fully traceable on GitHub. If you're interested, you can view the [GitHub Action](https://github.com/IdeaNest-org/localhost-cert/actions/runs/7056302734) for more details. | ||
@@ -31,3 +31,3 @@ In summary, it is completely secure due to two reasons: | ||
| ```bash | ||
| npm install localhost-cert --save-dev | ||
| npm install localhost-https --save-dev | ||
| ``` | ||
@@ -38,3 +38,3 @@ | ||
| ```javascript | ||
| const getHttps = require('localhost-cert'); | ||
| const getHttps = require('localhost-https'); | ||
@@ -44,6 +44,3 @@ // webpack config | ||
| devServer: { | ||
| https: getHttps({ | ||
| // If the developer has not installed the root certificate, they will be guided to install it. | ||
| autoInstall: true, | ||
| }), | ||
| https: getHttps(), | ||
| }, | ||
@@ -55,9 +52,6 @@ }; | ||
| // vite config | ||
| const getHttps = require('localhost-cert'); | ||
| const getHttps = require('localhost-https'); | ||
| export default defineConfig({ | ||
| server: { | ||
| https: getHttps({ | ||
| // If the developer has not installed the root certificate, they will be guided to install it. | ||
| autoInstall: true, | ||
| }), | ||
| https: getHttps(), | ||
| }, | ||
@@ -64,0 +58,0 @@ }); |
+6
-9
@@ -1,2 +0,2 @@ | ||
| # Localhost Cert | ||
| # Localhost Cert / Localhost Https | ||
@@ -16,3 +16,3 @@ ## 一个安全、便捷的 localhost 支持 HTTPS 的方案 | ||
| 如果你对 HTTPS 有一定的了解,那么你应该知道如果在本地安装一个 CA 根证书,这是一个很危险的事,因为这个根证书可以用于签名任何域名比如,google.com. 从而达到中间人劫持,但是 Localhost Cert 生成 localhost 的域名后,立马丢弃了根证书的私钥,也就是说,即便有人想用这个根证书对其他网站签名是不可能的。 | ||
| 那么是如何保证私钥没有被记住呢,Localhost cert 是利用 github action 生成根证书的,github Action 生成的过程以及 github 当时的代码是完全可追踪的,如果感兴趣可以查看[github action](https://github.com/IdeaNest-org/localhost-cert/actions/runs/7004987626/job/19053845251) | ||
| 那么是如何保证私钥没有被记住呢,Localhost cert 是利用 github action 生成根证书的,github Action 生成的过程以及 github 当时的代码是完全可追踪的,如果感兴趣可以查看[github action](https://github.com/IdeaNest-org/localhost-cert/actions/runs/7056302734) | ||
@@ -26,3 +26,3 @@ 总结一下基于两点,它是完全安全的 | ||
| ```bash | ||
| npm install localhost-cert --save-dev | ||
| npm install localhost-https --save-dev | ||
| ``` | ||
@@ -33,3 +33,3 @@ | ||
| ```javascript | ||
| const getHttps = require('localhost-cert'); | ||
| const getHttps = require('localhost-https'); | ||
@@ -39,6 +39,3 @@ // webpack config | ||
| devServer: { | ||
| https: getHttps({ | ||
| // 如果开发者没有安装根证书,那么会引导开发者安装根证书 | ||
| autoInstall: true, | ||
| }), | ||
| https: getHttps(), | ||
| }, | ||
@@ -50,3 +47,3 @@ }; | ||
| // vite config | ||
| const getHttps = require('localhost-cert'); | ||
| const getHttps = require('localhost-https'); | ||
| export default defineConfig({ | ||
@@ -53,0 +50,0 @@ server: { |
+1
-3
| const getHttps = require('./index.js'); | ||
| const options = getHttps({ | ||
| autoInstall: true, | ||
| }); | ||
| const options = getHttps(); | ||
| console.log(options); | ||
@@ -6,0 +4,0 @@ const https = require('https'); |
| const forge = require('node-forge'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| module.exports = function createRootCert() { | ||
| // generate a root CA keypair | ||
| 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() + 20 | ||
| ); | ||
| const attrs = [ | ||
| { | ||
| name: 'commonName', | ||
| value: 'My Root CA', | ||
| }, | ||
| { | ||
| name: 'countryName', | ||
| value: 'US', | ||
| }, | ||
| { | ||
| shortName: 'ST', | ||
| value: 'Virginia', | ||
| }, | ||
| { | ||
| name: 'localityName', | ||
| value: 'Blacksburg', | ||
| }, | ||
| { | ||
| name: 'organizationName', | ||
| value: 'Test', | ||
| }, | ||
| { | ||
| shortName: 'OU', | ||
| value: 'Test', | ||
| }, | ||
| ]; | ||
| cert.setSubject(attrs); | ||
| cert.setIssuer(attrs); | ||
| cert.setExtensions([ | ||
| { | ||
| name: 'basicConstraints', | ||
| cA: true, | ||
| }, | ||
| { | ||
| name: 'keyUsage', | ||
| keyCertSign: true, | ||
| digitalSignature: true, | ||
| nonRepudiation: true, | ||
| keyEncipherment: true, | ||
| dataEncipherment: true, | ||
| }, | ||
| { | ||
| name: 'subjectKeyIdentifier', | ||
| }, | ||
| ]); | ||
| cert.sign(keys.privateKey, forge.md.sha256.create()); | ||
| // generate a server keypair | ||
| const serverKeys = forge.pki.rsa.generateKeyPair(2048); | ||
| const serverCert = forge.pki.createCertificate(); | ||
| serverCert.publicKey = serverKeys.publicKey; | ||
| serverCert.serialNumber = '01'; | ||
| serverCert.validity.notBefore = new Date(); | ||
| serverCert.validity.notAfter = new Date(); | ||
| serverCert.validity.notAfter.setFullYear( | ||
| serverCert.validity.notBefore.getFullYear() + 20 | ||
| ); | ||
| const serverAttrs = [ | ||
| { | ||
| name: 'commonName', | ||
| value: 'localhost', | ||
| }, | ||
| { | ||
| name: 'countryName', | ||
| value: 'US', | ||
| }, | ||
| { | ||
| shortName: 'ST', | ||
| value: 'Virginia', | ||
| }, | ||
| { | ||
| name: 'localityName', | ||
| value: 'Blacksburg', | ||
| }, | ||
| { | ||
| name: 'organizationName', | ||
| value: 'Test', | ||
| }, | ||
| { | ||
| shortName: 'OU', | ||
| value: 'Test', | ||
| }, | ||
| ]; | ||
| serverCert.setSubject(serverAttrs); | ||
| serverCert.setIssuer(cert.subject.attributes); | ||
| serverCert.setExtensions([ | ||
| { | ||
| name: 'basicConstraints', | ||
| cA: false, | ||
| }, | ||
| { | ||
| name: 'keyUsage', | ||
| digitalSignature: true, | ||
| nonRepudiation: true, | ||
| keyEncipherment: true, | ||
| dataEncipherment: true, | ||
| }, | ||
| { | ||
| name: 'subjectAltName', | ||
| altNames: [ | ||
| { | ||
| type: 2, // DNS | ||
| value: 'localhost', | ||
| }, | ||
| ], | ||
| }, | ||
| ]); | ||
| serverCert.sign(keys.privateKey, forge.md.sha256.create()); | ||
| // save root certificate and key | ||
| const rootCrt = forge.pki.certificateToPem(cert); | ||
| const localhostCrt = forge.pki.certificateToPem(serverCert); | ||
| const localhostKey = forge.pki.privateKeyToPem(serverKeys.privateKey); | ||
| fs.writeFileSync('root.pem', forge.pki.certificateToPem(cert)); | ||
| fs.writeFileSync('root.crt', forge.pki.certificateToPem(cert)); | ||
| // save server certificate and key | ||
| fs.writeFileSync('localhost.crt', forge.pki.certificateToPem(serverCert)); | ||
| fs.writeFileSync( | ||
| 'localhost.key', | ||
| forge.pki.privateKeyToPem(serverKeys.privateKey) | ||
| ); | ||
| console.log('certs created') | ||
| console.log('-----------------root.pem-----------------') | ||
| console.log(rootCrt); | ||
| console.log('-----------------localhost.crt-----------------') | ||
| console.log(localhostCrt); | ||
| console.log('-----------------localhost.key-----------------') | ||
| console.log(localhostKey); | ||
| }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| const { Octokit } = require('@octokit/rest'); | ||
| const fs = require('fs'); | ||
| function getGitHubToken() { | ||
| const token = process.env.GH_TOKEN; | ||
| console.log('token', token); | ||
| if (!token) { | ||
| throw new Error('Please set the GH_TOKEN environment variable.'); | ||
| } | ||
| return token; | ||
| } | ||
| const octokit = new Octokit({ | ||
| auth: getGitHubToken(), // 请替换为你的个人访问令牌 | ||
| }); | ||
| module.exports = async function saveAndDelete() { | ||
| // 保存证书到本地 | ||
| async function uploadFileToGitHubRepo( | ||
| owner, | ||
| repo, | ||
| filePath, | ||
| branch, | ||
| message | ||
| ) { | ||
| const fileContent = fs.readFileSync(filePath, 'utf-8'); | ||
| const contentEncoded = Buffer.from(fileContent).toString('base64'); | ||
| try { | ||
| const response = await octokit.repos.createOrUpdateFileContents({ | ||
| owner: owner, | ||
| repo: repo, | ||
| path: filePath, | ||
| message: message, | ||
| content: contentEncoded, | ||
| branch: branch, | ||
| }); | ||
| console.log( | ||
| 'File uploaded to GitHub:', | ||
| response.data.content.html_url | ||
| ); | ||
| } catch (error) { | ||
| console.error('Error uploading file to GitHub:', error.message); | ||
| } | ||
| } | ||
| const rootCrt = fs.readFileSync('root.crt', 'utf-8'); | ||
| const localhostCrt = fs.readFileSync('localhost.crt', 'utf-8'); | ||
| const localhostKey = fs.readFileSync('localhost.key', 'utf-8'); | ||
| console.log(rootCrt); | ||
| console.log(localhostCrt); | ||
| console.log(localhostKey); | ||
| // 使用示例 | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'root.crt', | ||
| 'main', | ||
| fs.readFileSync('root.crt', 'utf-8') | ||
| ); | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'localhost.crt', | ||
| 'main', | ||
| fs.readFileSync('localhost.crt', 'utf-8') | ||
| ); | ||
| await uploadFileToGitHubRepo( | ||
| 'IdeaNest-org', | ||
| 'localhost-cert', | ||
| 'localhost.key', | ||
| 'main', | ||
| fs.readFileSync('localhost.key', 'utf-8') | ||
| ); | ||
| }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
26315
9.85%23
76.92%460
23.32%4
100%57
-9.52%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added