Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@vladmandic/piacme

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vladmandic/piacme - npm Package Compare versions

Comparing version 1.0.2 to 1.0.3

6

package.json
{
"name": "@vladmandic/piacme",
"version": "1.0.2",
"version": "1.0.3",
"description": "Simple ACME/LetsEncrypt HTTP/SSL Certificate Management",

@@ -47,4 +47,4 @@ "main": "dist/piacme.js",

"devDependencies": {
"esbuild": "^0.15.2",
"eslint": "^8.22.0",
"esbuild": "^0.15.10",
"eslint": "^8.25.0",
"eslint-config-airbnb-base": "^15.0.0",

@@ -51,0 +51,0 @@ "eslint-plugin-import": "^2.26.0"

@@ -38,3 +38,3 @@ const fs = require('fs');

function notify(evt, msg) {
if (config.debug) log.data('acme notification', { evt, msg });
if (config.debug) log.data('ACME Notification:', evt, msg);
let key;

@@ -60,6 +60,6 @@ if (msg.challenge && msg.challenge.keyAuthorization) key = msg.challenge.keyAuthorization;

if (!config.domains || (config.domains.length <= 0)) {
log.info('acme skip create certificate', { domains: config.domains });
log.info('ACME Skip create certificate', { domains: config.domains });
return false;
}
log.info('acme create certificate', { domains: config.domains, encoding: 'der' });
log.info('ACME Create certificate', { domains: config.domains, encoding: 'der' });
// what are we requesting

@@ -83,5 +83,5 @@ const csrDer = await CSR.csr({ jwk: config.key, domains: config.domains, encoding: 'der' });

res.end();
log.info('acme challenge', { key: key.host, url: req.url, sent: key.key });
log.info('ACME Challenge', { key: key.host, url: req.url, sent: key.key });
} else {
log.info('acme challenge', { key: key.host, url: req.url });
log.info('ACME Challenge', { key: key.host, url: req.url });
}

@@ -92,8 +92,10 @@ });

// sudo setcap 'cap_net_bind_service=+ep' `which node`
server.listen(80, () => log.state('acme validation', { server: 'ready', webroot: './.well-known/acme-challenge' }));
server.on('error', (err) => log.error('acme validation', { err: err.message || err }));
server.on('request', (req, res) => { // stop http server once request has finished
req.socket['_isIdle'] = false;
server.listen(80, () => log.state('ACME Validation server ready'));
// stop http server
server.on('request', (req, res) => {
// eslint-disable-next-line no-underscore-dangle
req.socket._isIdle = false;
res.on('finish', () => {
log.state('acme validation', { server: 'finish' });
log.state('ACME Validation', { server: 'finish' });
req.socket['_isIdle'] = true;

@@ -103,6 +105,7 @@ req.socket.destroy();

});
// server.on('close', () => log.info('acme validation server closed'));
// server.on('close', () => log.info('ACME Validation server closed'));
// start actual verification
log.info('acme validating', { domains: config.domains });
log.info('ACME Validating domains:', { domains: config.domains });
log.info(`ACME Account contract: ${config.account.contact} crv: ${config.accountKey.crv}`);

@@ -113,17 +116,17 @@ let pems;

} catch (err) {
log.warn('acme validation exception', err.code ? { code: err.code, syscall: err.syscall, address: err.address, port: err.port } : err);
log.warn('ACME Validation exception', err.code ? { code: err.code, syscall: err.syscall, address: err.address, port: err.port } : err);
}
server.close(() => log.info('acme validation', { server: 'close' }));
server.close(() => log.info('ACME Validation', { server: 'close' }));
// generate actual fullchain from received pems
if (!pems || !pems.cert || !pems.chain) {
log.warn('acme validation failed');
log.warn('ACME Validation failed');
return false;
}
log.info('acme certificate:', { create: config.fullChain });
log.info('ACME Certificate:', { create: config.fullChain });
cert = `${pems.cert}\n${pems.chain}\n`;
await fs.promises.writeFile(config.fullChain, cert, 'ascii');
} else if (initial) {
log.info('acme certificate', { load: config.fullChain });
log.info('ACME Certificate', { load: config.fullChain });
cert = await fs.promises.readFile(config.fullChain, 'ascii');

@@ -137,3 +140,3 @@ }

if (!config.domains || (config.domains.length <= 0)) {
log.info('acme skip create keys', { domains: config.domains });
log.info('ACME Skip create keys', { domains: config.domains });
return;

@@ -146,7 +149,7 @@ }

await acme.init(directoryUrl);
log.info('acme request', { domains: config.domains });
log.info('ACME Request', { domains: config.domains });
// Generate or load account key
if (!fs.existsSync(config.accountKeyFile)) {
log.info('acme account key', { generate: config.accountKeyFile });
log.info('ACME Account key', { generate: config.accountKeyFile });
const accountKeypair = await Keypairs.generate({ kty: 'EC', format: 'jwk' });

@@ -157,3 +160,3 @@ config.accountKey = accountKeypair.private;

} else {
log.info('acme account key', { load: config.accountKeyFile });
log.info('ACME Account key', { load: config.accountKeyFile });
const pem = await fs.promises.readFile(config.accountKeyFile, 'ascii');

@@ -165,7 +168,7 @@ config.accountKey = await Keypairs.import({ pem });

if (!fs.existsSync(config.accountFile)) {
log.info('acme account', { create: config.accountFile });
log.info('ACME Account', { create: config.accountFile });
config.account = await acme.accounts.create({ subscriberEmail: config.subscriber, agreeToTerms: true, accountKey: config.accountKey });
await fs.promises.writeFile(config.accountFile, JSON.stringify(config.account), 'ascii');
} else {
log.info('acme account', { load: config.accountFile });
log.info('ACME Account', { load: config.accountFile });
const json = await fs.promises.readFile(config.accountFile, 'ascii');

@@ -177,3 +180,3 @@ config.account = JSON.parse(json);

if (!fs.existsSync(config.ServerKeyFile)) {
log.info('acme server key', { generate: config.ServerKeyFile });
log.info('ACME Server key: generate', config.ServerKeyFile);
const serverKeypair = await Keypairs.generate({ kty: 'RSA', format: 'jwk' });

@@ -184,3 +187,3 @@ config.key = serverKeypair.private;

} else {
log.info('acme server key', { load: config.ServerKeyFile });
log.info('ACME Server key: load', config.ServerKeyFile);
const pem = await fs.promises.readFile(config.ServerKeyFile, 'ascii');

@@ -234,15 +237,15 @@ config.key = await Keypairs.import({ pem });

if (fs.existsSync(config.fullChain)) {
if (initial) log.info('ssl certificate', { check: config.fullChain });
if (initial) log.info('ACME Certificate check:', config.fullChain);
const ssl = await parseCert();
const now = new Date();
if (!ssl.account || ssl.account.error) {
log.warn('ssl certificate error', { account: ssl.account.error });
log.warn(`ACME Certificate account error: ${ssl.account.error || 'unknown'}`);
return false;
}
if (!ssl.serverKey || ssl.serverKey.error || !ssl.accountKey || ssl.accountKey.error) {
log.warn('ssl certificate error', { key: ssl.serverKey.error, account: ssl.account.error });
log.warn(`SSL Keys error server:${ssl.serverKey.error} account:${ssl.account.error}`);
return false;
}
if (!ssl.fullChain || ssl.fullChain.error) {
log.warn('ssl certificate error', { fullchain: ssl.fullChain.error });
log.warn(`SSL Certificate error: ${ssl.fullChain.error}`);
return false;

@@ -252,3 +255,3 @@ }

if (!ssl.fullChain.notBefore || (now - ssl.fullChain.notBefore < 0)) {
log.warn('ssl certificate invalid', { notbefore: ssl.fullChain.notBefore });
log.warn(`ACME Certificate invalid notBefore: ${ssl.fullChain.notBefore}`);
return false;

@@ -258,3 +261,3 @@ }

if (!ssl.fullChain.notAfter || (now - ssl.fullChain.notAfter > 0)) {
log.warn('ssl certificate invalid', { notafter: ssl.fullChain.notAfter });
log.warn(`ACME Certificate invalid notAfter: ${ssl.fullChain.notAfter}`);
return false;

@@ -264,7 +267,7 @@ }

config.remainingDays = (ssl.fullChain.notAfter - now) / 1000 / 60 / 60 / 24;
log.state('ssl certificate validity', { days: Math.round(config.remainingDays), renew: config.remainingDays < config.renewDays ? 'now' : 'skip' });
log.state('SSL Certificate expires in', config.remainingDays.toFixed(1), `days: ${config.remainingDays < config.renewDays ? 'renewing now' : 'skipping renewal'}`);
if (config.remainingDays < config.renewDays) return false;
return true;
}
log.warn('ssl certificate missing', { cert: config.fullChain });
log.warn(`SSL Certificate does not exist: ${config.fullChain}`);
return false;

@@ -282,3 +285,3 @@ }

if (!certOk) {
log.error('ssl certificate validation failed');
log.error('SSL Certificate did not pass validation');
}

@@ -290,19 +293,2 @@ if (callback) {

}
/*
if (initial) {
const ssl = await parseCert();
if (ssl.account && !ssl.account.error) {
log.info(`SSL account: ${ssl.account.contact} Created: ${moment(ssl.account.createdAt).format('YYYY-MM-DD HH:mm:ss')} `);
} else log.warn(`SSL account error: ${ssl.account.error}`);
if (ssl.serverKey && !ssl.serverKey.error && ssl.accountKey && !ssl.accountKey.error) {
log.info(`SSL keys server: ${ssl.serverKey.type} Account: ${ssl.accountKey.type} `);
} else log.warn(`SSL keys error server: ${ssl.serverKey.error} Account: ${ssl.account.error}`);
if (ssl.fullChain && !ssl.fullChain.error) {
log.info(`SSL certificate subject: ${ssl.fullChain.subject} Issuer: ${ssl.fullChain.issuer}`);
} else log.warn(`SSL certificate error: ${ssl.fullChain.error}`);
config.SSL = { Key: `../${config.ServerKeyFile}`, Crt: `../${config.fullChain}` };
initial = false;
}
return config.SSL;
*/
}

@@ -314,11 +300,69 @@

await getCert();
log.state('ssl monitor', { cert: config.fullChain, check: 'complete' });
log.state('SSL Monitor certificate check complete');
}, 1000 * 60 * config.monitorInterval);
}
function initConfig(userConfig) {
function setConfig(userConfig) {
config = { ...config, ...userConfig };
}
async function test() {
async function scanHost(host, startPort, endPort) {
try {
log.info('Connection test', { fetch: 'create' });
const res = await fetch('https://www.ipfingerprints.com/scripts/getPortsInfo.php', {
headers: {
accept: 'application/json, text/javascript, */*; q=0.01',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded',
pragma: 'no-cache',
Referer: 'https://www.ipfingerprints.com/portscan.php',
},
body: `remoteHost=${host}&start_port=${startPort}&end_port=${endPort}&normalScan=Yes&scan_type=connect&ping_type=none`,
method: 'POST',
});
if (!res?.ok) return [];
const html = await res.text();
const text = html.replace(/<[^>]*>/g, '');
const lines = text.split('\\n').map((line) => line.replace('\'', '').trim()).filter((line) => line.includes('tcp '));
const parsed = lines.map((line) => line.replace('\\/tcp', '').split(' ').filter((str) => str.length > 0));
const services = parsed.map((line) => ({ host, port: Number(line[0]), state: line[1], service: line[2] }));
return services;
} catch {
return [];
}
}
async function testConnection(host, timeout = 5000) {
return new Promise((resolve) => {
let timeoutCallback;
const server = http.createServer();
server.on('listening', () => {
// log.state('Connection test', { server: 'listen' });
scanHost(host, 80, 80).then((services) => {
log.state('Connection test', { services });
if (timeoutCallback) clearTimeout(timeoutCallback);
resolve(services.length > 0);
server.close();
});
});
server.on('error', (err) => log.warn('Connection test', { code: err.code, call: err.syscall, port: err.port }));
// server.on('close', () => log.info('Connection test', { server: 'close' }));
server.on('request', (req, res) => {
// log.state('Connection test', { url: req.url });
res.writeHead(200);
res.write('{ "connection": true }');
res.end();
});
timeoutCallback = setTimeout(() => {
if (server) server.close();
log.warn('Connection test', { host, timeout });
resolve(false);
}, timeout);
server.listen(80);
});
}
async function testModule() {
const status = await testConnection(config.domains[0]);
log.data('Test connection', status);
await getCert();

@@ -330,8 +374,8 @@ const details = await parseCert(); // parse any cert

try {
if (require.main === module) test();
} catch {
//
if (require.main === module) testModule();
} catch (err) {
log.error('test:', err);
}
exports.init = initConfig;
exports.setConfig = setConfig;
exports.getCert = getCert;

@@ -343,1 +387,2 @@ exports.parseCert = parseCert;

exports.monitorCert = monitorCert;
exports.testConnection = testConnection;

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc