Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

localhost-https

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

localhost-https - npm Package Compare versions

Comparing version
1.0.13
to
2.0.0
certs/v2/localhost.crt

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

+27
const CERT_VERSION = 'v2';
const CERT_DIRECTORY = `certs/${CERT_VERSION}`;
const ROOT_CERT_BASENAME = 'root';
const SERVER_CERT_BASENAME = 'localhost';
const getCertRelativePath = (fileName) => `${CERT_DIRECTORY}/${fileName}`;
const getRootCertFilename = (extension) =>
`${ROOT_CERT_BASENAME}.${extension}`;
const getServerCertFilename = (extension) =>
`${SERVER_CERT_BASENAME}.${extension}`;
const getRootCertPath = (extension) =>
getCertRelativePath(getRootCertFilename(extension));
const getServerCertPath = (extension) =>
getCertRelativePath(getServerCertFilename(extension));
module.exports = {
CERT_VERSION,
CERT_DIRECTORY,
ROOT_CERT_BASENAME,
SERVER_CERT_BASENAME,
getCertRelativePath,
getRootCertFilename,
getServerCertFilename,
getRootCertPath,
getServerCertPath,
};
#!/usr/bin/env node
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const packages = ['localhost-https', 'localhost-cert'];
const projectRoot = path.resolve(__dirname, '..');
const pkgJsonPath = path.join(projectRoot, 'package.json');
const pkgLockPath = path.join(projectRoot, 'package-lock.json');
const npmToken = process.env.NPM_TOKEN || process.env.NODE_AUTH_TOKEN;
if (!npmToken) {
console.error(
'Missing npm authentication token. Please configure NPM_TOKEN or NODE_AUTH_TOKEN.'
);
process.exit(1);
}
console.log(
`Detected npm auth token with length ${npmToken.length}; proceeding with publish.`
);
const originalPackageJson = fs.readFileSync(pkgJsonPath, 'utf-8');
const originalPackageLock = fs.existsSync(pkgLockPath)
? fs.readFileSync(pkgLockPath, 'utf-8')
: null;
function writeJson(filePath, content) {
fs.writeFileSync(filePath, JSON.stringify(content, null, 4) + '\n');
}
function updatePackageName(name) {
const packageJson = JSON.parse(originalPackageJson);
packageJson.name = name;
writeJson(pkgJsonPath, packageJson);
if (originalPackageLock) {
const packageLock = JSON.parse(originalPackageLock);
packageLock.name = name;
if (packageLock.packages && packageLock.packages['']) {
packageLock.packages[''].name = name;
}
writeJson(pkgLockPath, packageLock);
}
}
function restoreOriginalFiles() {
fs.writeFileSync(pkgJsonPath, originalPackageJson);
if (originalPackageLock) {
fs.writeFileSync(pkgLockPath, originalPackageLock);
}
}
function publishPackage(name) {
console.log(`Publishing ${name}...`);
updatePackageName(name);
const env = {
...process.env,
npm_config_registry: 'https://registry.npmjs.org/',
npm_config_always_auth: 'true',
npm_config__authToken: npmToken,
};
execSync('npm publish --access public', {
stdio: 'inherit',
env,
cwd: projectRoot,
});
}
try {
packages.forEach(publishPackage);
console.log('All packages published successfully.');
} finally {
restoreOriginalFiles();
}
const https = require('https');
const { tmpdir } = require('os');
const fs = require('fs');
const path = require('path');
const getHttps = require('../index');
async function main() {
console.log('Step 1: Reading HTTPS configuration...');
const httpsConfig = getHttps({ autoInstall: false });
if (!httpsConfig || typeof httpsConfig !== 'object') {
throw new Error('HTTPS config is not an object.');
}
const { cert, key } = httpsConfig;
if (!cert || !cert.includes('BEGIN CERTIFICATE')) {
throw new Error('Certificate content is invalid.');
}
if (!key || !key.includes('BEGIN')) {
throw new Error('Key content is invalid.');
}
console.log('Step 2: Starting HTTPS server...');
const server = https.createServer({ cert, key }, (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ ok: true }));
});
await new Promise((resolve, reject) => {
server.listen(0, '127.0.0.1', (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
const { port } = server.address();
console.log(`HTTPS server running on port ${port}`);
console.log('Step 3: Performing HTTPS request...');
await new Promise((resolve, reject) => {
https
.get(
{
hostname: '127.0.0.1',
port,
path: '/',
rejectUnauthorized: false,
},
(res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const parsed = JSON.parse(data);
if (!parsed.ok) {
reject(
new Error(
'HTTPS response missing expected ok=true flag'
)
);
return;
}
resolve();
} catch (err) {
reject(err);
}
});
}
)
.on('error', reject);
});
server.close();
console.log('HTTPS server verified successfully.');
}
main().catch((error) => {
console.error('Workflow test failed:', error);
process.exit(1);
});
+18
-16

@@ -9,5 +9,6 @@ # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node

branches: ['main']
pull_request:
branches: ['main']
release:
types: [published]
jobs:

@@ -18,20 +19,21 @@ build:

GH_TOKEN: ${{ secrets.GH_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
strategy:
matrix:
node-version: ['18.x']
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16.x
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm install
- name: Check commit message
run: |
if [[ "${{ github.event.head_commit.message }}" == *"generate root pem"* ]]; then
echo "Commit message contains the keyword."
# Perform additional actions or steps here
node genrate.js
else
echo "Commit message does not contain the keyword."
# Perform other actions or steps here
fi
- name: Install dependencies
run: npm install
- name: Generate certificates and upload
run: node genrate.js
- name: Run full workflow test
run: npm test
- name: Publish to npm on release
run: npm run publish:packages
// set cra https env
const path = require('path');
const { getServerCertPath } = require('../modules/shared');
process.env.HTTPS = true;
process.env.SSL_CRT_FILE = path.resolve(__dirname, '../certs/localhost.crt');
process.env.SSL_KEY_FILE = path.resolve(__dirname, '../certs/localhost.key');
process.env.SSL_CRT_FILE = path.resolve(
__dirname,
'..',
getServerCertPath('crt')
);
process.env.SSL_KEY_FILE = path.resolve(
__dirname,
'..',
getServerCertPath('key')
);

@@ -6,3 +6,6 @@ // 判断当前是否存在文件

const uploadToGithub = require('./modules/uploadToGithub');
const {
getRootCertPath,
getServerCertPath,
} = require('./modules/shared');
function isFileExist(filePath) {

@@ -18,5 +21,5 @@ try {

if (
!isFileExist(path.resolve(__dirname, 'certs/root.crt')) ||
!isFileExist(path.resolve(__dirname, 'certs/localhost.key')) ||
!isFileExist(path.resolve(__dirname, 'certs/localhost.crt'))
!isFileExist(path.resolve(__dirname, getRootCertPath('crt'))) ||
!isFileExist(path.resolve(__dirname, getServerCertPath('key'))) ||
!isFileExist(path.resolve(__dirname, getServerCertPath('crt')))
) {

@@ -23,0 +26,0 @@ createRootCert();

const forge = require('node-forge');
const { writeCert } = require('./utils');
const {
getRootCertPath,
getServerCertPath,
getRootCertFilename,
getServerCertFilename,
} = require('./shared');
module.exports = function createRootCert() {

@@ -34,3 +39,3 @@ const keys = forge.pki.rsa.generateKeyPair(2048);

name: 'organizationName',
value: 'localhost-https',
value: 'localhost-cert',
},

@@ -93,3 +98,3 @@ {

name: 'organizationName',
value: 'localhost-https',
value: 'localhost-cert',
},

@@ -103,2 +108,40 @@ {

serverCert.setIssuer(cert.subject.attributes);
const altNames = [
{ type: 2, value: 'localhost' },
{ type: 2, value: '*.localhost' },
{ type: 2, value: 'localhost.localdomain' },
{ type: 2, value: 'dev.local' },
{ type: 2, value: '*.dev.local' },
{ type: 2, value: '*.local' },
{ type: 2, value: '*.localdomain' },
{ type: 2, value: '*.test' },
{ type: 2, value: '*.home' },
{ type: 2, value: '*.internal' },
{ type: 2, value: '*.lan' },
{ type: 2, value: 'host.docker.internal' },
{ type: 2, value: '*.docker.internal' },
{ type: 7, value: '127.0.0.1' },
{ type: 7, value: '127.0.1.1' },
{ type: 7, value: '10.0.0.1' },
{ type: 7, value: '10.0.1.1' },
{ type: 7, value: '10.1.1.1' },
{ type: 7, value: '10.10.0.1' },
{ type: 7, value: '172.16.0.1' },
{ type: 7, value: '172.17.0.1' },
{ type: 7, value: '172.30.0.1' },
{ type: 7, value: '172.31.0.1' },
{ type: 7, value: '192.168.10.1' },
{ type: 7, value: '192.168.56.1' },
{ type: 7, value: '192.168.100.1' },
];
[0, 1, 3].forEach((a) => {
for (let b = 1; b <= 255; b += 1) {
altNames.push({
type: 7,
value: `192.168.${a}.${b}`,
});
}
});
serverCert.setExtensions([

@@ -118,8 +161,3 @@ {

name: 'subjectAltName',
altNames: [
{
type: 2, // DNS
value: 'localhost',
},
],
altNames,
},

@@ -133,18 +171,29 @@ ]);

writeCert('root.pem', forge.pki.certificateToPem(cert));
writeCert('root.crt', forge.pki.certificateToPem(cert));
writeCert(
getRootCertPath('pem'),
forge.pki.certificateToPem(cert)
);
writeCert(
getRootCertPath('crt'),
forge.pki.certificateToPem(cert)
);
// save server certificate and key
writeCert('localhost.crt', forge.pki.certificateToPem(serverCert));
writeCert(
'localhost.key',
getServerCertPath('crt'),
forge.pki.certificateToPem(serverCert)
);
writeCert(
getServerCertPath('key'),
forge.pki.privateKeyToPem(serverKeys.privateKey)
);
console.log('certs created');
console.log('-----------------root.pem-----------------');
console.log(rootCrt);
console.log('-----------------localhost.crt-----------------');
console.log(
`-----------------${getRootCertPath('pem')}-----------------`
);
// console.log(rootCrt);
console.log(`-----------------${getServerCertPath('crt')}-----------------`);
console.log(localhostCrt);
console.log('-----------------localhost.key-----------------');
console.log(`-----------------${getServerCertPath('key')}-----------------`);
console.log(localhostKey);
};

@@ -5,2 +5,3 @@ const cp = require('child_process');

const path = require('path');
const { getRootCertPath } = require('./shared');
module.exports = function install() {

@@ -12,3 +13,3 @@ // windows 运行 certutil -addstore -enterprise -f "Root" "C:\path\to\your\certificate.crt"

try {
const crtPath = path.resolve(__dirname, '../certs/root.crt');
const crtPath = path.resolve(__dirname, '..', getRootCertPath('crt'));
if (process.platform === 'win32') {

@@ -44,5 +45,5 @@ const cmd =

console.warn(
'please download at:https://github.com/IdeaNest-org/localhost-cert/blob/main/certs/root.crt and install root certificate manually'
`please download at:https://github.com/IdeaNest-org/localhost-cert/blob/main/${getRootCertPath('crt')} and install root certificate manually`
);
}
};
const { Octokit } = require('@octokit/rest');
const fs = require('fs');
const { readCert } = require('./utils');
const {
getRootCertPath,
getServerCertPath,
} = require('./shared');
function getGitHubToken() {

@@ -14,4 +17,8 @@ const token = process.env.GH_TOKEN;

module.exports = async function uploadToGithub() {
const token = getGitHubToken();
console.log(
`[uploadToGithub] Using GitHub token with length ${token.length}. Ensure it has repo scope.`
);
const octokit = new Octokit({
auth: getGitHubToken(), // 请替换为你的个人访问令牌
auth: token,
});

@@ -43,8 +50,15 @@ // 保存证书到本地

} catch (error) {
console.error('Error uploading file to GitHub:', error.message);
if (error.status === 401) {
console.error(
'Error uploading file to GitHub: unauthorized. Please verify GH_TOKEN has repo access or is still valid.'
);
} else {
console.error('Error uploading file to GitHub:', error.message);
}
throw error;
}
}
const rootCrt = readCert('root.crt');
const localhostCrt = readCert('localhost.crt');
const localhostKey = readCert('localhost.key');
const rootCrt = readCert(getRootCertPath('crt'));
const localhostCrt = readCert(getServerCertPath('crt'));
const localhostKey = readCert(getServerCertPath('key'));
console.log(rootCrt);

@@ -58,3 +72,3 @@ console.log(localhostCrt);

'localhost-cert',
'certs/root.crt',
getRootCertPath('crt'),
'main',

@@ -67,3 +81,3 @@ rootCrt

'localhost-cert',
'certs/localhost.crt',
getServerCertPath('crt'),
'main',

@@ -76,3 +90,3 @@ localhostCrt

'localhost-cert',
'certs/localhost.key',
getServerCertPath('key'),
'main',

@@ -79,0 +93,0 @@ localhostKey

const path = require('path');
const fs = require('fs-extra');
const {
CERT_DIRECTORY,
getCertRelativePath,
getRootCertPath,
} = require('./shared');
function readFileFromDir(file) {

@@ -10,12 +15,20 @@ return fs.readFileSync(path.resolve(__dirname, '../', file), 'utf-8');

function getRootCrt() {
return readFileFromDirAsync('certs/root.crt');
return readFileFromDirAsync(getRootCertPath('crt'));
}
function writeFileToDir(file, content) {
return fs.writeFileSync(path.resolve(__dirname, '../', file), content);
const targetPath = path.resolve(__dirname, '../', file);
fs.ensureDirSync(path.dirname(targetPath));
return fs.writeFileSync(targetPath, content);
}
function resolveCertPath(name) {
if (name.startsWith(CERT_DIRECTORY) || name.startsWith('certs/')) {
return name;
}
return getCertRelativePath(name);
}
function readCert(name) {
return readFileFromDir('certs/' + name);
return readFileFromDir(resolveCertPath(name));
}
function writeCert(name, content) {
return writeFileToDir('certs/' + name, content);
return writeFileToDir(resolveCertPath(name), content);
}

@@ -22,0 +35,0 @@ module.exports = {

{
"name": "localhost-https",
"version": "1.0.13",
"version": "2.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node tests/fullWorkflow.js",
"publish:packages": "node scripts/publishBoth.js"
},
"bin": {
"cra-https": "bin/cra-https.js"
"cra-cert": "bin/cra-cert.js"
},

@@ -29,2 +30,8 @@ "repository": {

"localhost-certificate",
"localhost-cert",
"localhost https",
"localhost ssl",
"localhost tls",
"localhost certificate",
"localhost cert",
"localhost-https",

@@ -31,0 +38,0 @@ "localhost-ssl",

@@ -17,2 +17,17 @@

### Why adopt it across the team?
- When everyone relies on `localhost-cert`, you can share the same HTTPS setup when starting local servers—no more regenerating certificates per project or teammate.
- Especially for open-source projects, adopting this approach means contributors immediately benefit from the shared root certificate without extra setup.
- Need additional hostnames or internal IP addresses in the SAN list? Open an issue or send a PR so the whole community benefits.
### Included SAN coverage
Localhost Cert ships with a subjectAltName list tailored for common development setups:
- DNS entries: `localhost`, `*.localhost`, `localhost.localdomain`, `dev.local`, `*.dev.local`, `*.local`, `*.localdomain`, `*.test`, `*.home`, `*.internal`, `*.lan`, `host.docker.internal`, `*.docker.internal`.
- Loopback and RFC1918 IPs: `127.0.0.1`, `127.0.1.1`, `10.0.0.1`, `10.0.1.1`, `10.1.1.1`, `10.10.0.1`, `172.16.0.1`, `172.17.0.1`, `172.30.0.1`, `172.31.0.1`, `192.168.10.1`, `192.168.56.1`, `192.168.100.1`.
- Full ranges: every address in `192.168.0.x`, `192.168.1.x`, and `192.168.3.x` (i.e. `192.168.{0,1,3}.1-255`).
This balance keeps the certificate broadly useful while staying within browser/OpenSSL size limits. If you need additional entries, please open an issue or PR so we can discuss expanding the list responsibly.
### Why is it secure?

@@ -31,3 +46,3 @@

```bash
npm install localhost-https --save-dev
npm install localhost-cert --save-dev
```

@@ -38,3 +53,3 @@

```javascript
const getHttps = require('localhost-https');
const getHttps = require('localhost-cert');

@@ -51,3 +66,3 @@ // webpack config

// vite config
const getHttps = require('localhost-https');
const getHttps = require('localhost-cert');
export default defineConfig({

@@ -54,0 +69,0 @@ server: {

@@ -13,2 +13,16 @@ # Localhost Cert / Localhost Https

### 为什么推荐团队一起使用?
- 当团队成员统一使用 `localhost-cert`,启动本地服务器时可共享同一套 HTTPS 证书配置,无需为不同项目或成员重复生成。
- 如果你在维护开源项目,采用这种方式可以让所有参与者共享同一个根证书,降低协作成本。
- 如果你想新增域名或内网 IP 到 SAN 列表,欢迎提交 issue 或 PR,让更多人一起受益。
### 当前默认支持的域名与 IP
- DNS 名称:`localhost`、`*.localhost`、`localhost.localdomain`、`dev.local`、`*.dev.local`、`*.local`、`*.localdomain`、`*.test`、`*.home`、`*.internal`、`*.lan`、`host.docker.internal`、`*.docker.internal` 等常见开发域名。
- 回环与典型内网地址:`127.0.0.1`、`127.0.1.1`、`10.0.0.1`、`10.0.1.1`、`10.1.1.1`、`10.10.0.1`、`172.16.0.1`、`172.17.0.1`、`172.30.0.1`、`172.31.0.1`、`192.168.10.1`、`192.168.56.1`、`192.168.100.1`。
- 批量 IP 覆盖:完整包含 `192.168.0.x`、`192.168.1.x` 和 `192.168.3.x` 三段网段(即 `192.168.{0,1,3}.1-255`)。
这样的取舍既保证常见开发场景可用,也避免了证书过大导致浏览器或系统拒绝。如果你还需要额外的域名或 IP,欢迎通过 issue 或 PR 反馈,我们会评估后逐步扩充。
### 为什么是安全的?

@@ -26,3 +40,3 @@

```bash
npm install localhost-https --save-dev
npm install localhost-cert --save-dev
```

@@ -33,3 +47,3 @@

```javascript
const getHttps = require('localhost-https');
const getHttps = require('localhost-cert');

@@ -46,3 +60,3 @@ // webpack config

// vite config
const getHttps = require('localhost-https');
const getHttps = require('localhost-cert');
export default defineConfig({

@@ -49,0 +63,0 @@ server: {

@@ -6,10 +6,11 @@ const {

} = require('../modules/utils');
const { getRootCertPath } = require('../modules/shared');
console.log(readFileFromDir('certs/root.crt'));
console.log(readFileFromDir(getRootCertPath('crt')));
readFileFromDirAsync('certs/root.crt').then((res) => {
readFileFromDirAsync(getRootCertPath('crt')).then((res) => {
console.log(res);
});
getRootCrt().then((res) => {
console.log(res);
console.log(res);
});