Skip to content

Commit 6f59805

Browse files
authored
Merge pull request #292 from MatrixAI/feature-unix-write
Implementing `secrets write` command
2 parents b6ac336 + ba1345c commit 6f59805

File tree

10 files changed

+202
-154
lines changed

10 files changed

+202
-154
lines changed

npmDepsHash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sha256-lbtIQDruaGlF/lyCqRQLatL6n26VzaF0ezJXn8RgUGg=
1+
sha256-8rBOwTKsBhskBLbHJJrIwwtiW6FRXD8sOVvaGSW8I48=

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
"nexpect": "^0.6.0",
151151
"node-gyp-build": "^4.4.0",
152152
"nodemon": "^3.0.1",
153-
"polykey": "^1.13.0",
153+
"polykey": "^1.14.0",
154154
"prettier": "^3.0.0",
155155
"shelljs": "^0.8.5",
156156
"shx": "^0.3.4",

src/secrets/CommandEdit.ts

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class CommandEdit extends CommandPolykey {
1212
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
1313
super(...args);
1414
this.name('edit');
15+
this.alias('ed');
1516
this.description('Edit a Secret');
1617
this.argument(
1718
'<secretPath>',
@@ -62,21 +63,18 @@ class CommandEdit extends CommandPolykey {
6263
const tmpFile = path.join(tmpDir, path.basename(secretPath[1]));
6364
const secretExists = await binUtils.retryAuthentication(
6465
async (auth) => {
65-
let exists: boolean = true;
66-
const response =
67-
await pkClient.rpcClient.methods.vaultsSecretsGet();
68-
await (async () => {
69-
const writer = response.writable.getWriter();
70-
await writer.write({
71-
nameOrId: secretPath[0],
72-
secretName: secretPath[1],
73-
metadata: auth,
74-
});
75-
await writer.close();
76-
})();
66+
let exists = true;
67+
const res = await pkClient.rpcClient.methods.vaultsSecretsGet();
68+
const writer = res.writable.getWriter();
69+
await writer.write({
70+
nameOrId: secretPath[0],
71+
secretName: secretPath[1],
72+
metadata: auth,
73+
});
74+
await writer.close();
7775
try {
7876
let rawSecretContent: string = '';
79-
for await (const chunk of response.readable) {
77+
for await (const chunk of res.readable) {
8078
rawSecretContent += chunk.secretContent;
8179
}
8280
const secretContent = Buffer.from(rawSecretContent, 'binary');
@@ -99,9 +97,8 @@ class CommandEdit extends CommandPolykey {
9997
execSync(`${process.env.EDITOR} \"${tmpFile}\"`, { stdio: 'inherit' });
10098
let content: string;
10199
try {
102-
content = (await this.fs.promises.readFile(tmpFile)).toString(
103-
'binary',
104-
);
100+
const buffer = await this.fs.promises.readFile(tmpFile);
101+
content = buffer.toString('binary');
105102
} catch (e) {
106103
if (e.code === 'ENOENT') {
107104
// If the secret exists but the file doesn't, then something went
@@ -125,26 +122,17 @@ class CommandEdit extends CommandPolykey {
125122
}
126123
throw e;
127124
}
128-
await binUtils.retryAuthentication(async (auth) => {
129-
// This point will never be reached if the temp file doesn't exist.
130-
// As such, if the secret didn't exist before, then we want to make it.
131-
// Otherwise, if the secret existed before, then we want to edit it.
132-
if (secretExists) {
133-
await pkClient.rpcClient.methods.vaultsSecretsEdit({
134-
metadata: auth,
135-
nameOrId: secretPath[0],
136-
secretName: secretPath[1],
137-
secretContent: content,
138-
});
139-
} else {
140-
await pkClient.rpcClient.methods.vaultsSecretsNew({
125+
// We will reach here only when the user wants to write a new secret.
126+
await binUtils.retryAuthentication(
127+
async (auth) =>
128+
await pkClient.rpcClient.methods.vaultsSecretsWriteFile({
141129
metadata: auth,
142130
nameOrId: secretPath[0],
143131
secretName: secretPath[1],
144132
secretContent: content,
145-
});
146-
}
147-
}, meta);
133+
}),
134+
meta,
135+
);
148136
// Windows
149137
// TODO: complete windows impl
150138
} finally {

src/secrets/CommandList.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class CommandList extends CommandPolykey {
99
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
1010
super(...args);
1111
this.name('ls');
12-
this.aliases(['list']);
12+
this.alias('list');
1313
this.description('List all secrets for a vault within a directory');
1414
this.argument(
1515
'<directoryPath>',

src/secrets/CommandRemove.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import * as binOptions from '../utils/options';
55
import * as binParsers from '../utils/parsers';
66
import * as binProcessors from '../utils/processors';
77

8-
class CommandDelete extends CommandPolykey {
8+
class CommandRemove extends CommandPolykey {
99
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
1010
super(...args);
1111
this.name('rm');
12+
this.alias('remove');
1213
this.description('Delete a Secret from a specified Vault');
1314
this.argument(
1415
'<secretPaths...>',
@@ -78,4 +79,4 @@ class CommandDelete extends CommandPolykey {
7879
}
7980
}
8081

81-
export default CommandDelete;
82+
export default CommandRemove;

src/secrets/CommandSecrets.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import CommandList from './CommandList';
77
import CommandMkdir from './CommandMkdir';
88
import CommandRename from './CommandRename';
99
import CommandRemove from './CommandRemove';
10-
import CommandUpdate from './CommandUpdate';
1110
import CommandStat from './CommandStat';
11+
import CommandWrite from './CommandWrite';
1212
import CommandPolykey from '../CommandPolykey';
1313

1414
class CommandSecrets extends CommandPolykey {
@@ -25,8 +25,8 @@ class CommandSecrets extends CommandPolykey {
2525
this.addCommand(new CommandMkdir(...args));
2626
this.addCommand(new CommandRename(...args));
2727
this.addCommand(new CommandRemove(...args));
28-
this.addCommand(new CommandUpdate(...args));
2928
this.addCommand(new CommandStat(...args));
29+
this.addCommand(new CommandWrite(...args));
3030
}
3131
}
3232

Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
import type PolykeyClient from 'polykey/dist/PolykeyClient';
2-
import * as errors from '../errors';
32
import CommandPolykey from '../CommandPolykey';
3+
import * as binProcessors from '../utils/processors';
4+
import * as binParsers from '../utils/parsers';
45
import * as binUtils from '../utils';
56
import * as binOptions from '../utils/options';
6-
import * as binParsers from '../utils/parsers';
7-
import * as binProcessors from '../utils/processors';
87

9-
class CommandUpdate extends CommandPolykey {
8+
class CommandWrite extends CommandPolykey {
109
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
1110
super(...args);
12-
this.name('update');
13-
this.description('Update a Secret');
14-
this.argument(
15-
'<directoryPath>',
16-
'On disk path to the secret file with the contents of the updated secret',
17-
);
11+
this.name('write');
12+
this.description('Write data into a secret from standard in');
1813
this.argument(
1914
'<secretPath>',
20-
'Path to where the secret to be updated, specified as <vaultName>:<directoryPath>',
15+
'Path to the secret, specified as <vaultName>:<directoryPath>',
2116
binParsers.parseSecretPathValue,
2217
);
2318
this.addOption(binOptions.nodeId);
2419
this.addOption(binOptions.clientHost);
2520
this.addOption(binOptions.clientPort);
26-
this.action(async (directoryPath, secretPath, options) => {
21+
this.action(async (secretPath, options) => {
2722
const { default: PolykeyClient } = await import(
2823
'polykey/dist/PolykeyClient'
2924
);
@@ -54,27 +49,36 @@ class CommandUpdate extends CommandPolykey {
5449
},
5550
logger: this.logger.getChild(PolykeyClient.name),
5651
});
57-
let content: Buffer;
58-
try {
59-
content = await this.fs.promises.readFile(directoryPath);
60-
} catch (e) {
61-
throw new errors.ErrorPolykeyCLIFileRead(e.message, {
62-
data: {
63-
errno: e.errno,
64-
syscall: e.syscall,
65-
code: e.code,
66-
path: e.path,
67-
},
68-
cause: e,
69-
});
70-
}
52+
53+
let stdin: string = '';
54+
await new Promise<void>((resolve, reject) => {
55+
const cleanup = () => {
56+
process.stdin.removeListener('data', dataHandler);
57+
process.stdin.removeListener('error', errorHandler);
58+
process.stdin.removeListener('end', endHandler);
59+
};
60+
const dataHandler = (data: Buffer) => {
61+
stdin += data.toString();
62+
};
63+
const errorHandler = (err: Error) => {
64+
cleanup();
65+
reject(err);
66+
};
67+
const endHandler = () => {
68+
cleanup();
69+
resolve();
70+
};
71+
process.stdin.on('data', dataHandler);
72+
process.stdin.once('error', errorHandler);
73+
process.stdin.once('end', endHandler);
74+
});
7175
await binUtils.retryAuthentication(
72-
(auth) =>
73-
pkClient.rpcClient.methods.vaultsSecretsEdit({
76+
async (auth) =>
77+
await pkClient.rpcClient.methods.vaultsSecretsWriteFile({
7478
metadata: auth,
7579
nameOrId: secretPath[0],
7680
secretName: secretPath[1],
77-
secretContent: content.toString('binary'),
81+
secretContent: stdin,
7882
}),
7983
meta,
8084
);
@@ -85,4 +89,4 @@ class CommandUpdate extends CommandPolykey {
8589
}
8690
}
8791

88-
export default CommandUpdate;
92+
export default CommandWrite;

tests/secrets/update.test.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)