certops 1.0.10 → 1.0.12

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # certops
2
2
 
3
- CLI for managing and auto-renewing SSL certificates from the [SSL Pilot](https://ssl-manager.dcom.at) platform.
3
+ CLI for managing and auto-renewing SSL certificates from the [CertOps](https://ssl-manager.dcom.at) platform.
4
4
 
5
5
  ## Install
6
6
 
@@ -11,13 +11,13 @@ npm install -g certops
11
11
  ## Requirements
12
12
 
13
13
  - Node.js 18+
14
- - An SSL Pilot API key (`sslpilot_...`) from your dashboard
14
+ - A CertOps API key (`co_...`) from your dashboard
15
15
 
16
16
  ## Quick start
17
17
 
18
18
  ```bash
19
19
  # Set your API key
20
- export CERTOPS_API_KEY='sslpilot_...'
20
+ export CERTOPS_API_KEY='co_...'
21
21
 
22
22
  # List certificates
23
23
  certops list
@@ -78,18 +78,18 @@ journalctl -u certops -f # follow logs
78
78
 
79
79
  ## Auto-renewal service
80
80
 
81
- The service polls your SSL Pilot account, checks local expiry state, and re-downloads certificates approaching expiry. Hook scripts in `/etc/certops/hooks/` run after each download.
81
+ The service polls your CertOps account, checks local expiry state, and re-downloads certificates approaching expiry. Hook scripts in `/etc/certops/hooks/` run after each download.
82
82
 
83
83
  **Hook environment variables:**
84
84
 
85
85
  | Variable | Value |
86
86
  |----------|-------|
87
- | `SSL_PILOT_CERT_NAME` | Certificate name |
88
- | `SSL_PILOT_DOMAIN` | Domain (certName from API) |
89
- | `SSL_PILOT_FULLCHAIN_PATH` | Path to `fullchain.pem` |
90
- | `SSL_PILOT_CERT_PATH` | Path to `cert.pem` |
91
- | `SSL_PILOT_CHAIN_PATH` | Path to `chain.pem` |
92
- | `SSL_PILOT_KEY_PATH` | Path to `privkey.pem` |
87
+ | `CERTOPS_CERT_NAME` | Certificate name |
88
+ | `CERTOPS_DOMAIN` | Domain (certName from API) |
89
+ | `CERTOPS_FULLCHAIN_PATH` | Path to `fullchain.pem` |
90
+ | `CERTOPS_CERT_PATH` | Path to `cert.pem` |
91
+ | `CERTOPS_CHAIN_PATH` | Path to `chain.pem` |
92
+ | `CERTOPS_KEY_PATH` | Path to `privkey.pem` |
93
93
 
94
94
  **Example hook** (`/etc/certops/hooks/example.com.sh`):
95
95
 
package/dist/brand.js ADDED
@@ -0,0 +1,10 @@
1
+ export const BRAND = {
2
+ name: 'certops',
3
+ displayName: 'CertOps',
4
+ binName: 'certops',
5
+ configDir: '/etc/certops',
6
+ envPrefix: 'CERTOPS',
7
+ keyPrefix: 'co_',
8
+ serviceUnit: 'certops',
9
+ apiUrl: 'https://ssl-manager.dcom.at',
10
+ };
package/dist/client.js CHANGED
@@ -2,21 +2,23 @@ import input from '@inquirer/input';
2
2
  import { readConfig } from './config.js';
3
3
  import { createApiClient } from './api.js';
4
4
  import { CLI_VERSION } from './version.js';
5
+ import { BRAND } from './brand.js';
6
+ const API_KEY_ENV = `${BRAND.envPrefix}_API_KEY`;
5
7
  export async function getConfiguredClient() {
6
- let apiKey = process.env['CERTOPS_API_KEY'];
8
+ let apiKey = process.env[API_KEY_ENV];
7
9
  if (!apiKey) {
8
10
  if (!process.stdin.isTTY) {
9
- process.stderr.write('Error: CERTOPS_API_KEY is not set and no TTY is available for prompt.\n');
10
- process.stderr.write(' export CERTOPS_API_KEY=\'sslpilot_...\'\n\n');
11
+ process.stderr.write(`Error: ${API_KEY_ENV} is not set and no TTY is available for prompt.\n`);
12
+ process.stderr.write(` export ${API_KEY_ENV}='${BRAND.keyPrefix}...'\n\n`);
11
13
  process.exit(1);
12
14
  }
13
15
  apiKey = await input({
14
- message: 'API key (sslpilot_...):',
15
- validate: (v) => v.startsWith('sslpilot_') && v.length > 10
16
+ message: `API key (${BRAND.keyPrefix}...):`,
17
+ validate: (v) => v.startsWith(BRAND.keyPrefix) && v.length > 10
16
18
  ? true
17
- : 'Key must start with sslpilot_',
19
+ : `Key must start with ${BRAND.keyPrefix}`,
18
20
  });
19
21
  }
20
22
  const config = await readConfig();
21
- return createApiClient({ apiKey, apiUrl: config.apiUrl, cliVersion: CLI_VERSION });
23
+ return createApiClient({ apiKey, apiUrl: config.apiUrl ?? BRAND.apiUrl, cliVersion: CLI_VERSION });
22
24
  }
@@ -12,7 +12,7 @@ export const configureCommand = new Command('configure')
12
12
  process.exit(1);
13
13
  }
14
14
  const existing = await readConfig();
15
- console.log('\nSSL Pilot — Update Service Config\n');
15
+ console.log('\nCertOps — Update Service Config\n');
16
16
  console.log(' (API key is stored in the systemd unit, not changed here)\n');
17
17
  const intervalStr = await input({
18
18
  message: 'Check interval (hours):',
@@ -2,13 +2,10 @@ import { Command } from 'commander';
2
2
  import { spawnSync } from 'child_process';
3
3
  import { unlink } from 'fs/promises';
4
4
  import { resolveApiKey, runRenewalCycle } from './renew.js';
5
- const UNIT = 'certops';
6
- const UNIT_PATH = '/etc/systemd/system/certops.service';
7
- /**
8
- * Runs systemctl with stdout inherited (visible) and stderr captured.
9
- * Stderr is only printed if the command fails, so noisy shim warnings
10
- * from Python-based systemctl stubs don't pollute normal output.
11
- */
5
+ import { BRAND } from '../../brand.js';
6
+ import { CERTOPS_DIR } from '../../config.js';
7
+ const UNIT = BRAND.serviceUnit;
8
+ const UNIT_PATH = `/etc/systemd/system/${BRAND.serviceUnit}.service`;
12
9
  function systemctl(args, exitOnFail = true) {
13
10
  const result = spawnSync('systemctl', args, {
14
11
  stdio: ['inherit', 'inherit', 'pipe'],
@@ -30,25 +27,26 @@ function requireRoot() {
30
27
  }
31
28
  }
32
29
  export const startCommand = new Command('start')
33
- .description('Start the SSL Pilot service')
30
+ .description(`Start the ${BRAND.displayName} service`)
34
31
  .action(() => { requireRoot(); systemctl(['start', UNIT]); });
35
32
  export const stopCommand = new Command('stop')
36
- .description('Stop the SSL Pilot service')
33
+ .description(`Stop the ${BRAND.displayName} service`)
37
34
  .action(() => { requireRoot(); systemctl(['stop', UNIT]); });
38
35
  export const restartCommand = new Command('restart')
39
36
  .description('Restart the service — picks up config.json changes immediately')
40
37
  .action(() => { requireRoot(); systemctl(['restart', UNIT]); });
41
38
  export const statusCommand = new Command('status')
42
- .description('Show SSL Pilot service status')
39
+ .description(`Show ${BRAND.displayName} service status`)
43
40
  .action(() => { systemctl(['status', UNIT]); });
44
41
  export const checkCommand = new Command('check')
45
42
  .description('Run one renewal check cycle immediately (for testing)')
46
43
  .action(async () => {
47
44
  requireRoot();
48
45
  const apiKey = await resolveApiKey();
46
+ const apiKeyEnv = `${BRAND.envPrefix}_API_KEY`;
49
47
  if (!apiKey) {
50
- process.stderr.write('\nError: CERTOPS_API_KEY not found in environment or service unit.\n');
51
- process.stderr.write(' Set the env var or run: sudo sp service install\n\n');
48
+ process.stderr.write(`\nError: ${apiKeyEnv} not found in environment or service unit.\n`);
49
+ process.stderr.write(` Set the env var or run: sudo ${BRAND.binName} service install\n\n`);
52
50
  process.exit(1);
53
51
  }
54
52
  const log = (msg) => process.stdout.write(` ${msg}\n`);
@@ -65,10 +63,10 @@ export const checkCommand = new Command('check')
65
63
  }
66
64
  });
67
65
  export const uninstallServiceCommand = new Command('uninstall')
68
- .description('Stop, disable, and remove the SSL Pilot service unit')
66
+ .description(`Stop, disable, and remove the ${BRAND.displayName} service unit`)
69
67
  .action(async () => {
70
68
  requireRoot();
71
- process.stdout.write('\nRemoving SSL Pilot service…\n\n');
69
+ process.stdout.write(`\nRemoving ${BRAND.displayName} service…\n\n`);
72
70
  systemctl(['stop', UNIT], false);
73
71
  systemctl(['disable', UNIT], false);
74
72
  try {
@@ -80,7 +78,7 @@ export const uninstallServiceCommand = new Command('uninstall')
80
78
  throw err;
81
79
  }
82
80
  systemctl(['daemon-reload'], false);
83
- process.stdout.write('\n ✓ Service uninstalled.\n');
84
- process.stdout.write(' /etc/certops/ (config, state, certs, hooks) was NOT removed.\n');
85
- process.stdout.write(' Run "sudo sp service install" to reinstall.\n\n');
81
+ process.stdout.write(`\n ✓ Service uninstalled.\n`);
82
+ process.stdout.write(` ${CERTOPS_DIR}/ (config, state, certs, hooks) was NOT removed.\n`);
83
+ process.stdout.write(` Run "sudo ${BRAND.binName} service install" to reinstall.\n\n`);
86
84
  });
@@ -1,6 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { readConfig } from '../../config.js';
3
3
  import { resolveApiKey, runRenewalCycle } from './renew.js';
4
+ import { BRAND } from '../../brand.js';
4
5
  function log(msg) {
5
6
  process.stdout.write(`[${new Date().toISOString()}] ${msg}\n`);
6
7
  }
@@ -10,7 +11,7 @@ function sleep(ms) {
10
11
  async function tick() {
11
12
  const apiKey = await resolveApiKey();
12
13
  if (!apiKey) {
13
- log('CERTOPS_API_KEY not available — skipping cycle.');
14
+ log(`${BRAND.envPrefix}_API_KEY not available — skipping cycle.`);
14
15
  return;
15
16
  }
16
17
  try {
@@ -24,7 +25,7 @@ async function tick() {
24
25
  export const daemonCommand = new Command('run')
25
26
  .description('Run the monitoring daemon (managed by systemd)')
26
27
  .action(async () => {
27
- log('SSL Pilot daemon starting.');
28
+ log(`${BRAND.displayName} daemon starting.`);
28
29
  process.on('SIGTERM', () => { log('SIGTERM — shutting down.'); process.exit(0); });
29
30
  process.on('SIGINT', () => { log('SIGINT — shutting down.'); process.exit(0); });
30
31
  while (true) {
@@ -4,7 +4,7 @@ import { configureCommand } from './configure.js';
4
4
  import { daemonCommand } from './daemon.js';
5
5
  import { startCommand, stopCommand, restartCommand, statusCommand, checkCommand, uninstallServiceCommand } from './control.js';
6
6
  export const serviceCommand = new Command('service')
7
- .description('Manage the SSL Pilot auto-renewal background service')
7
+ .description('Manage the CertOps auto-renewal background service')
8
8
  .addHelpText('after', `
9
9
  Commands:
10
10
  install Interactive setup — writes config, hooks, and installs systemd unit
@@ -2,25 +2,27 @@ import { Command } from 'commander';
2
2
  import input from '@inquirer/input';
3
3
  import { writeFile, mkdir } from 'fs/promises';
4
4
  import { spawnSync } from 'child_process';
5
- import { readConfig, writeConfig, SSL_PILOT_DIR, HOOKS_DIR } from '../../config.js';
5
+ import { readConfig, writeConfig, CERTOPS_DIR, HOOKS_DIR } from '../../config.js';
6
6
  import { domainHookPath, GLOBAL_HOOK } from '../../hooks.js';
7
- const UNIT_PATH = '/etc/systemd/system/certops.service';
7
+ import { BRAND } from '../../brand.js';
8
+ const UNIT_PATH = `/etc/systemd/system/${BRAND.serviceUnit}.service`;
9
+ const API_KEY_ENV = `${BRAND.envPrefix}_API_KEY`;
8
10
  function buildUnitContent(apiKey) {
9
11
  return `\
10
12
  [Unit]
11
- Description=SSL Pilot Certificate Monitor
13
+ Description=${BRAND.displayName} Certificate Monitor
12
14
  After=network-online.target
13
15
  Wants=network-online.target
14
16
 
15
17
  [Service]
16
18
  Type=simple
17
- Environment=CERTOPS_API_KEY=${apiKey}
18
- ExecStart=/usr/local/bin/certops service run
19
+ Environment=${API_KEY_ENV}=${apiKey}
20
+ ExecStart=/usr/local/bin/${BRAND.binName} service run
19
21
  Restart=on-failure
20
22
  RestartSec=30
21
23
  StandardOutput=journal
22
24
  StandardError=journal
23
- SyslogIdentifier=certops
25
+ SyslogIdentifier=${BRAND.serviceUnit}
24
26
 
25
27
  [Install]
26
28
  WantedBy=multi-user.target
@@ -28,36 +30,35 @@ WantedBy=multi-user.target
28
30
  }
29
31
  const HOOK_TEMPLATE = `#!/usr/bin/env bash
30
32
  # Available env vars:
31
- # SSL_PILOT_CERT_NAME — certificate name (e.g. *.example.com)
32
- # SSL_PILOT_DOMAIN — domain name (certName from API)
33
- # SSL_PILOT_FULLCHAIN_PATH — path to fullchain.pem
34
- # SSL_PILOT_CERT_PATH — path to cert.pem
35
- # SSL_PILOT_CHAIN_PATH — path to chain.pem
36
- # SSL_PILOT_KEY_PATH — path to privkey.pem
33
+ # ${BRAND.envPrefix}_CERT_NAME — certificate name (e.g. *.example.com)
34
+ # ${BRAND.envPrefix}_DOMAIN — domain name (certName from API)
35
+ # ${BRAND.envPrefix}_FULLCHAIN_PATH — path to fullchain.pem
36
+ # ${BRAND.envPrefix}_CERT_PATH — path to cert.pem
37
+ # ${BRAND.envPrefix}_CHAIN_PATH — path to chain.pem
38
+ # ${BRAND.envPrefix}_KEY_PATH — path to privkey.pem
37
39
 
38
40
  # Example: reload nginx after cert update
39
41
  # systemctl reload nginx
40
42
  `;
41
43
  export const installCommand = new Command('install')
42
- .description('Install and configure the SSL Pilot background service')
44
+ .description(`Install and configure the ${BRAND.displayName} background service`)
43
45
  .action(async () => {
44
46
  try {
45
47
  if (process.getuid?.() !== 0) {
46
- console.error('Error: certops service install must run as root.');
47
- console.error('\n sudo -E sp service install\n');
48
+ console.error(`Error: ${BRAND.binName} service install must run as root.`);
49
+ console.error(`\n sudo -E ${BRAND.binName} service install\n`);
48
50
  process.exit(1);
49
51
  }
50
- console.log('\nSSL Pilot Service Setup\n');
52
+ console.log(`\n${BRAND.displayName} Service Setup\n`);
51
53
  const existing = await readConfig();
52
- // API key env takes precedence, otherwise prompt
53
- const apiKey = process.env['CERTOPS_API_KEY'] ?? await input({
54
- message: 'API key (sslpilot_...):',
55
- validate: (v) => v.startsWith('sslpilot_') && v.length > 10
54
+ const apiKey = process.env[API_KEY_ENV] ?? await input({
55
+ message: `API key (${BRAND.keyPrefix}...):`,
56
+ validate: (v) => v.startsWith(BRAND.keyPrefix) && v.length > 10
56
57
  ? true
57
- : 'Key must start with sslpilot_',
58
+ : `Key must start with ${BRAND.keyPrefix}`,
58
59
  });
59
60
  const apiUrl = await input({
60
- message: 'API URL (leave blank for default https://ssl-manager.dcom.at):',
61
+ message: `API URL (leave blank for default ${BRAND.apiUrl}):`,
61
62
  default: existing.apiUrl ?? '',
62
63
  });
63
64
  const intervalStr = await input({
@@ -80,12 +81,10 @@ export const installCommand = new Command('install')
80
81
  watchDomains,
81
82
  maxDownloadRetries: existing.maxDownloadRetries,
82
83
  };
83
- // Write config + create directories
84
84
  await writeConfig(config);
85
- await mkdir(SSL_PILOT_DIR, { recursive: true });
85
+ await mkdir(CERTOPS_DIR, { recursive: true });
86
86
  await mkdir(HOOKS_DIR, { recursive: true });
87
- console.log('\n✓ Config written to /etc/certops/config.json');
88
- // Create hook stubs only if they don't exist yet
87
+ console.log(`\n✓ Config written to ${CERTOPS_DIR}/config.json`);
89
88
  for (const domain of watchDomains) {
90
89
  const hookFile = domainHookPath(domain);
91
90
  try {
@@ -105,13 +104,12 @@ export const installCommand = new Command('install')
105
104
  if (err.code !== 'EEXIST')
106
105
  throw err;
107
106
  }
108
- // Write systemd unit
109
107
  await writeFile(UNIT_PATH, buildUnitContent(apiKey), { encoding: 'utf8', mode: 0o600 });
110
108
  console.log(`✓ Systemd unit written to ${UNIT_PATH}`);
111
109
  for (const args of [
112
110
  ['daemon-reload'],
113
- ['enable', 'certops'],
114
- ['restart', 'certops'],
111
+ ['enable', BRAND.serviceUnit],
112
+ ['restart', BRAND.serviceUnit],
115
113
  ]) {
116
114
  const r = spawnSync('systemctl', args, { stdio: ['inherit', 'inherit', 'pipe'], encoding: 'utf8' });
117
115
  if (r.status !== 0) {
@@ -121,9 +119,9 @@ export const installCommand = new Command('install')
121
119
  }
122
120
  }
123
121
  console.log('\n✓ Service enabled and started.\n');
124
- console.log(' Edit hooks in : /etc/certops/hooks/');
125
- console.log(' Check status : certops service status');
126
- console.log(' Follow logs : journalctl -u certops -f\n');
122
+ console.log(` Edit hooks in : ${HOOKS_DIR}/`);
123
+ console.log(` Check status : ${BRAND.binName} service status`);
124
+ console.log(` Follow logs : journalctl -u ${BRAND.serviceUnit} -f\n`);
127
125
  }
128
126
  catch (err) {
129
127
  if (err.name === 'ExitPromptError')
@@ -4,17 +4,19 @@ import { readConfig } from '../../config.js';
4
4
  import { readState, updateCertState } from '../../state.js';
5
5
  import { runHooks } from '../../hooks.js';
6
6
  import { CLI_VERSION } from '../../version.js';
7
+ import { BRAND } from '../../brand.js';
7
8
  const BASE_RETRY_DELAY_MS = 2_000; // 2 s → 4 s → 8 s …
8
9
  function sleep(ms) {
9
10
  return new Promise(resolve => setTimeout(resolve, ms));
10
11
  }
11
12
  export async function resolveApiKey() {
12
- if (process.env['CERTOPS_API_KEY'])
13
- return process.env['CERTOPS_API_KEY'];
13
+ const envKey = `${BRAND.envPrefix}_API_KEY`;
14
+ if (process.env[envKey])
15
+ return process.env[envKey];
14
16
  try {
15
17
  const { execSync } = await import('child_process');
16
- const out = execSync('systemctl show certops -p Environment --value', { encoding: 'utf8' });
17
- const match = out.match(/CERTOPS_API_KEY=(\S+)/);
18
+ const out = execSync(`systemctl show ${BRAND.serviceUnit} -p Environment --value`, { encoding: 'utf8' });
19
+ const match = out.match(new RegExp(`${BRAND.envPrefix}_API_KEY=(\\S+)`));
18
20
  return match?.[1] ?? null;
19
21
  }
20
22
  catch {
@@ -68,11 +70,11 @@ export async function runRenewalCycle(apiKey, log) {
68
70
  log(` key : ${paths.keyPath}`);
69
71
  await updateCertState(cert.certName, cert.expiryDate ?? '');
70
72
  await runHooks(cert.certName, {
71
- SSL_PILOT_DOMAIN: cert.certName,
72
- SSL_PILOT_FULLCHAIN_PATH: paths.fullchainPath,
73
- SSL_PILOT_CERT_PATH: paths.certPath,
74
- SSL_PILOT_CHAIN_PATH: paths.chainPath,
75
- SSL_PILOT_KEY_PATH: paths.keyPath,
73
+ [`${BRAND.envPrefix}_DOMAIN`]: cert.certName,
74
+ [`${BRAND.envPrefix}_FULLCHAIN_PATH`]: paths.fullchainPath,
75
+ [`${BRAND.envPrefix}_CERT_PATH`]: paths.certPath,
76
+ [`${BRAND.envPrefix}_CHAIN_PATH`]: paths.chainPath,
77
+ [`${BRAND.envPrefix}_KEY_PATH`]: paths.keyPath,
76
78
  }, log);
77
79
  downloaded++;
78
80
  lastError = undefined;
package/dist/config.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { readFile, writeFile, mkdir } from 'fs/promises';
2
2
  import { join } from 'path';
3
- export const SSL_PILOT_DIR = '/etc/certops';
4
- export const HOOKS_DIR = join(SSL_PILOT_DIR, 'hooks');
5
- const CONFIG_PATH = join(SSL_PILOT_DIR, 'config.json');
3
+ import { BRAND } from './brand.js';
4
+ export const CERTOPS_DIR = BRAND.configDir;
5
+ export const HOOKS_DIR = join(CERTOPS_DIR, 'hooks');
6
+ const CONFIG_PATH = join(CERTOPS_DIR, 'config.json');
6
7
  const DEFAULTS = {
7
8
  renewalThresholdDays: 5,
8
9
  checkIntervalHours: 12,
@@ -21,7 +22,7 @@ export async function readConfig() {
21
22
  }
22
23
  }
23
24
  export async function writeConfig(config) {
24
- await mkdir(SSL_PILOT_DIR, { recursive: true });
25
+ await mkdir(CERTOPS_DIR, { recursive: true });
25
26
  await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', {
26
27
  encoding: 'utf8',
27
28
  mode: 0o600,
package/dist/files.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { mkdir, writeFile, chmod } from 'fs/promises';
2
2
  import { join } from 'path';
3
3
  import { unzipSync } from 'fflate';
4
- import { SSL_PILOT_DIR } from './config.js';
4
+ import { CERTOPS_DIR } from './config.js';
5
5
  export async function saveZip(certName, zipBuffer) {
6
6
  const zipDirName = certName.replace(/^\*\./, 'wildcard.');
7
- const dir = join(SSL_PILOT_DIR, zipDirName);
7
+ const dir = join(CERTOPS_DIR, zipDirName);
8
8
  let entries;
9
9
  try {
10
10
  entries = unzipSync(new Uint8Array(zipBuffer));
package/dist/hooks.js CHANGED
@@ -2,6 +2,7 @@ import { spawn } from 'child_process';
2
2
  import { access } from 'fs/promises';
3
3
  import { join } from 'path';
4
4
  import { HOOKS_DIR } from './config.js';
5
+ import { BRAND } from './brand.js';
5
6
  const GLOBAL_HOOK = join(HOOKS_DIR, 'global.sh');
6
7
  function domainHookPath(certName) {
7
8
  const safe = certName.replace(/^\*\./, 'wildcard.');
@@ -33,7 +34,7 @@ async function execHook(scriptPath, vars) {
33
34
  }
34
35
  export async function runHooks(certName, vars, log) {
35
36
  const domainHook = domainHookPath(certName);
36
- const hookVars = { ...vars, SSL_PILOT_CERT_NAME: certName };
37
+ const hookVars = { ...vars, [`${BRAND.envPrefix}_CERT_NAME`]: certName };
37
38
  if (await fileExists(domainHook)) {
38
39
  log(` Running domain hook: ${domainHook}`);
39
40
  try {
package/dist/index.js CHANGED
@@ -3,20 +3,19 @@ import { Command } from 'commander';
3
3
  import { listCommand } from './commands/list.js';
4
4
  import { downloadCommand } from './commands/download.js';
5
5
  import { serviceCommand } from './commands/service/index.js';
6
+ import { CLI_VERSION } from './version.js';
7
+ import { BRAND } from './brand.js';
6
8
  const program = new Command()
7
- .name('certops')
8
- .description('CertOps CLI — manage and auto-renew your SSL certificates')
9
- .version('1.0.0')
9
+ .name(BRAND.binName)
10
+ .description(`${BRAND.displayName} CLI — manage and auto-renew your SSL certificates`)
11
+ .version(CLI_VERSION)
10
12
  .addHelpText('after', `
11
13
  Examples:
12
- certops list List all certificates
13
- sudo certops download Pick and download interactively
14
- sudo certops download '*.example.com' Download a specific domain
15
- sudo certops service install Set up the auto-renewal service
16
- certops service status Check service status
17
-
18
- Documentation:
19
- https://github.com/Vimosoftdev/ssl-checker-web/blob/main/SETUP.md
14
+ ${BRAND.binName} list List all certificates
15
+ sudo ${BRAND.binName} download Pick and download interactively
16
+ sudo ${BRAND.binName} download '*.example.com' Download a specific domain
17
+ sudo ${BRAND.binName} service install Set up the auto-renewal service
18
+ ${BRAND.binName} service status Check service status
20
19
  `);
21
20
  program.addCommand(listCommand);
22
21
  program.addCommand(downloadCommand);
package/dist/state.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { readFile, writeFile, rename, mkdir } from 'fs/promises';
2
2
  import { join } from 'path';
3
3
  import { randomBytes } from 'crypto';
4
- import { SSL_PILOT_DIR } from './config.js';
5
- const STATE_PATH = join(SSL_PILOT_DIR, 'state.json');
4
+ import { CERTOPS_DIR } from './config.js';
5
+ const STATE_PATH = join(CERTOPS_DIR, 'state.json');
6
6
  export async function readState() {
7
7
  try {
8
8
  const raw = await readFile(STATE_PATH, 'utf8');
@@ -15,11 +15,11 @@ export async function readState() {
15
15
  }
16
16
  }
17
17
  export async function updateCertState(certName, expiryDate) {
18
- await mkdir(SSL_PILOT_DIR, { recursive: true });
18
+ await mkdir(CERTOPS_DIR, { recursive: true });
19
19
  const state = await readState();
20
20
  state[certName] = { expiryDate, downloadedAt: new Date().toISOString() };
21
21
  const content = JSON.stringify(state, null, 2) + '\n';
22
- const tmp = join(SSL_PILOT_DIR, `.state-${randomBytes(4).toString('hex')}.tmp`);
22
+ const tmp = join(CERTOPS_DIR, `.state-${randomBytes(4).toString('hex')}.tmp`);
23
23
  await writeFile(tmp, content, { encoding: 'utf8', mode: 0o600 });
24
24
  await rename(tmp, STATE_PATH);
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "certops",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "SSL Pilot CLI — download and manage your SSL certificates",
5
5
  "type": "module",
6
6
  "files": [