Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 43 additions & 23 deletions src/utils/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,23 @@ import * as errors from '../errors';
* When SIGINT is received this will return undefined
*/
async function promptPassword(): Promise<string | undefined> {
const { password } = await prompts({
name: 'password',
type: 'password',
message: 'Please enter the password',
});
// If `isTTY` is `undefined` then stdin has been piped into and `prompts` will not process it properly
if (process.stdin.setRawMode == null) return;
let cancelled = false;
const { password } = await prompts(
{
name: 'password',
type: 'password',
message: 'Please enter the password',
},
{
onCancel: () => {
cancelled = true;
},
},
);
// If cancelled then we just return undefined
if (cancelled) return;
return password;
}

Expand All @@ -37,28 +49,36 @@ async function promptPassword(): Promise<string | undefined> {
* When SIGINT is received this will return undefined
*/
async function promptNewPassword(): Promise<string | undefined> {
let password: string | undefined;
// If `isTTY` is `undefined` then stdin has been piped into and `prompts` will not process it properly
if (process.stdin.setRawMode == null) return;
while (true) {
({ password } = await prompts({
name: 'password',
type: 'password',
message: 'Enter new password',
}));
// If undefined, then SIGINT was sent, return undefined
if (password == null) return;
const { passwordConfirm } = await prompts({
name: 'passwordConfirm',
type: 'password',
message: 'Confirm new password',
});
// If undefined, then SIGINT was sent, return undefined
if (passwordConfirm == null) return;
// Compare the passwords are the same
if (password === passwordConfirm) break;
let cancelled = false;
const { password, passwordConfirm } = await prompts(
[
{
name: 'password',
type: 'password',
message: 'Enter new password',
},
{
name: 'passwordConfirm',
type: 'password',
message: 'Confirm new password',
},
],
{
onCancel: () => {
cancelled = true;
},
},
);
// If cancelled then we just return undefined
if (cancelled) return;
// Confirm that the passwords are the same
if (password === passwordConfirm) return password;
// Interactive message
process.stderr.write('Passwords do not match!\n');
}
return password;
}

/**
Expand Down
106 changes: 0 additions & 106 deletions tests/agent/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1036,110 +1036,4 @@ describe('start', () => {
globalThis.defaultTimeout * 2,
);
});
test('prompts for password twice when creating state', async () => {
const polykeyPath = path.join(dataDir, 'polykey');
await fs.promises.mkdir(polykeyPath);

// Starting with missing directory prompts a new password
await testUtils.pkExpect({
args: [
'agent',
'start',
'--node-path',
path.join(dataDir, 'polykey'),
'--client-host',
'127.0.0.1',
'--agent-host',
'127.0.0.1',
'--workers',
'none',
'--seed-nodes',
'',
'--verbose',
'--format',
'json',
'--password-ops-limit',
'min',
'--password-mem-limit',
'min',
],
expect: (expectChain) => {
expectChain.expect(/Enter new password/);
expectChain.sendline('password');
expectChain.wait(/Confirm new password/);
expectChain.sendEof();
return expectChain;
},
});
});
test(
'prompts for password once with existing state',
async () => {
const password = 'abc123';
const agentProcess1 = await testUtils.pkSpawn(
[
'agent',
'start',
'--client-host',
'127.0.0.1',
'--agent-host',
'127.0.0.1',
'--workers',
'none',
'--seed-nodes',
'',
'--verbose',
],
{
env: {
PK_NODE_PATH: path.join(dataDir, 'polykey'),
PK_PASSWORD: password,
PK_PASSWORD_OPS_LIMIT: 'min',
PK_PASSWORD_MEM_LIMIT: 'min',
},
cwd: dataDir,
},
logger,
);
const rlOut = readline.createInterface(agentProcess1.stdout!);
await new Promise<RecoveryCode>((resolve, reject) => {
rlOut.once('line', resolve);
rlOut.once('close', () => reject(Error('closed early')));
});
agentProcess1.kill('SIGHUP');

// Starting again on existing state
await testUtils.pkExpect({
args: [
'agent',
'start',
'--node-path',
path.join(dataDir, 'polykey'),
'--client-host',
'127.0.0.1',
'--agent-host',
'127.0.0.1',
'--workers',
'none',
'--seed-nodes',
'',
'--verbose',
'--format',
'json',
'--password-ops-limit',
'min',
'--password-mem-limit',
'min',
],
expect: (expectChain) => {
expectChain.expect(/Please enter the password/);
expectChain.sendline('password');
expectChain.wait(/Creating PolykeyAgent/);
expectChain.sendEof();
return expectChain;
},
});
},
globalThis.defaultTimeout * 2,
);
});
26 changes: 0 additions & 26 deletions tests/bootstrap.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { IChain } from 'nexpect';
import path from 'path';
import fs from 'fs';
import readline from 'readline';
Expand Down Expand Up @@ -303,29 +302,4 @@ describe('bootstrap', () => {
},
globalThis.defaultTimeout * 2,
);
test(
'bootstraps node state prompts for password twice ',
async () => {
const password = 'password';
const passwordPath = path.join(dataDir, 'password');
await fs.promises.writeFile(passwordPath, password);
await testUtils.pkExpect({
args: ['bootstrap', '--verbose'],
env: {
PK_NODE_PATH: path.join(dataDir, 'polykey'),
PK_PASSWORD_OPS_LIMIT: 'min',
PK_PASSWORD_MEM_LIMIT: 'min',
},
cwd: dataDir,
expect: (expectChain: IChain) => {
expectChain.expect(/Enter new password/);
expectChain.sendline('password');
expectChain.wait(/Confirm new password/);
expectChain.sendEof();
return expectChain;
},
});
},
globalThis.defaultTimeout * 2,
);
});