@lamalibre/portlama-agent 1.0.19 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamalibre/portlama-agent",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "Tunnel agent for Portlama — manages Chisel tunnel client as a system service",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -246,6 +246,19 @@ async function runTokenSetup(flags) {
246
246
  await mkdir(logsDir, { recursive: true, mode: 0o700 });
247
247
  },
248
248
  },
249
+ {
250
+ title: 'Requesting macOS login password',
251
+ skip: () => !isDarwin() && 'Not macOS',
252
+ task: async (_ctx, task) => {
253
+ task.output = chalk.dim('Required to authorize curl access to the Keychain certificate');
254
+ ctx._keychainPassword = await prompt('macOS login password (for Keychain access)');
255
+ if (!ctx._keychainPassword) {
256
+ throw new Error('Keychain password is required on macOS to grant curl access to the certificate.');
257
+ }
258
+ task.output = 'Password received';
259
+ },
260
+ rendererOptions: { persistentOutput: true },
261
+ },
249
262
  {
250
263
  title: isDarwin() ? 'Importing certificate into Keychain' : 'Storing certificate',
251
264
  task: async (_ctx, task) => {
@@ -255,6 +268,7 @@ async function runTokenSetup(flags) {
255
268
  ctx._caCertPem,
256
269
  ctx.resolvedLabel,
257
270
  console,
271
+ { keychainPassword: ctx._keychainPassword },
258
272
  );
259
273
  if (result.identity) {
260
274
  ctx.keychainIdentity = result.identity;
@@ -22,12 +22,13 @@ import { secureDelete } from './keychain.js';
22
22
  * @param {string} caCertPem - PEM-encoded CA certificate
23
23
  * @param {string} label - Agent label
24
24
  * @param {import('pino').Logger | Console} logger
25
+ * @param {{ keychainPassword?: string }} [options]
25
26
  * @returns {Promise<{ identity?: string, p12Path?: string, p12Password?: string }>}
26
27
  */
27
- export async function storeEnrolledCert(keyPath, certPem, caCertPem, label, logger) {
28
+ export async function storeEnrolledCert(keyPath, certPem, caCertPem, label, logger, options = {}) {
28
29
  if (isDarwin()) {
29
30
  const { importIdentityToKeychain } = await import('./keychain.js');
30
- const { identity } = await importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger);
31
+ const { identity } = await importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger, options);
31
32
  return { identity };
32
33
  }
33
34
  return storeP12Linux(keyPath, certPem, caCertPem, label, logger);
@@ -82,9 +82,10 @@ export async function generateKeypairAndCSR(label) {
82
82
  * @param {string} caCertPem - PEM-encoded CA certificate
83
83
  * @param {string} label - Agent label
84
84
  * @param {import('pino').Logger | Console} logger
85
+ * @param {{ keychainPassword?: string }} [options]
85
86
  * @returns {Promise<{ identity: string }>}
86
87
  */
87
- export async function importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger) {
88
+ export async function importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger, options = {}) {
88
89
  const suffix = crypto.randomBytes(8).toString('hex');
89
90
  const certPath = path.join(AGENT_DIR, `.tmp-cert-${suffix}.pem`);
90
91
  const caPath = path.join(AGENT_DIR, `.tmp-ca-${suffix}.pem`);
@@ -159,15 +160,15 @@ export async function importIdentityToKeychain(keyPath, certPem, caCertPem, labe
159
160
  }
160
161
 
161
162
  // Set the key partition list so curl can access the identity without prompts.
162
- // This uses the default Keychain password (empty string for login Keychain
163
- // on most macOS setups), which may prompt the user if the Keychain is locked.
163
+ // Requires the login Keychain password callers should prompt the user for it.
164
+ const keychainPassword = options.keychainPassword ?? '';
164
165
  try {
165
166
  await execa('security', [
166
167
  'set-key-partition-list',
167
168
  '-S',
168
169
  'apple-tool:,apple:', // apple-tool: for /usr/bin/curl, apple: for GUI apps
169
170
  '-k',
170
- '', // Keychain password (empty for login Keychain)
171
+ keychainPassword,
171
172
  '-l', // match by Label (friendly name from -name), not -D (Description)
172
173
  identityName,
173
174
  ]);