Skip to content

Commit

Permalink
Merge pull request #282 from MatrixAI/feature-unix-cat
Browse files Browse the repository at this point in the history
Adding `secrets cat` command and removing `secrets get` command
  • Loading branch information
aryanjassal authored Sep 24, 2024
2 parents db47ae7 + be3f953 commit 165c9f4
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 168 deletions.
2 changes: 1 addition & 1 deletion npmDepsHash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sha256-bKqMvZvc//Fo63MbPtkkXyLpCKNHyA0SKFy/Ts/fJLw=
sha256-sQ2HofpSd7lMbycLqKH84lHTamWIt8TwPVyddkC+be8=
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
"nexpect": "^0.6.0",
"node-gyp-build": "^4.4.0",
"nodemon": "^3.0.1",
"polykey": "^1.11.1",
"polykey": "^1.13.0",
"prettier": "^3.0.0",
"shelljs": "^0.8.5",
"shx": "^0.3.4",
Expand Down
109 changes: 109 additions & 0 deletions src/secrets/CommandCat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type PolykeyClient from 'polykey/dist/PolykeyClient';
import CommandPolykey from '../CommandPolykey';
import * as binUtils from '../utils';
import * as binOptions from '../utils/options';
import * as binParsers from '../utils/parsers';
import * as binProcessors from '../utils/processors';

class CommandGet extends CommandPolykey {
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
super(...args);
this.name('cat');
this.description(
'Concatenates secrets and prints them on the standard output',
);
this.argument(
'[secretPaths...]',
'Path to a secret to be retrieved, specified as <vaultName>:<directoryPath>',
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
this.action(async (secretPaths, options) => {
secretPaths = secretPaths.map((path: string) =>
binParsers.parseSecretPathValue(path),
);
const { default: PolykeyClient } = await import(
'polykey/dist/PolykeyClient'
);
const clientOptions = await binProcessors.processClientOptions(
options.nodePath,
options.nodeId,
options.clientHost,
options.clientPort,
this.fs,
this.logger.getChild(binProcessors.processClientOptions.name),
);
const meta = await binProcessors.processAuthentication(
options.passwordFile,
this.fs,
);

let pkClient: PolykeyClient;
this.exitHandlers.handlers.push(async () => {
if (pkClient != null) await pkClient.stop();
});
try {
pkClient = await PolykeyClient.createPolykeyClient({
nodeId: clientOptions.nodeId,
host: clientOptions.clientHost,
port: clientOptions.clientPort,
options: {
nodePath: options.nodePath,
},
logger: this.logger.getChild(PolykeyClient.name),
});
if (secretPaths.length === 0) {
await new Promise<void>((resolve, reject) => {
const cleanup = () => {
process.stdin.removeListener('data', dataHandler);
process.stdin.removeListener('error', errorHandler);
process.stdin.removeListener('end', endHandler);
};
const dataHandler = (data: Buffer) => {
process.stdout.write(data);
};
const errorHandler = (err: Error) => {
cleanup();
reject(err);
};
const endHandler = () => {
cleanup();
resolve();
};
process.stdin.on('data', dataHandler);
process.stdin.once('error', errorHandler);
process.stdin.once('end', endHandler);
});
return;
}
await binUtils.retryAuthentication(async (auth) => {
const response = await pkClient.rpcClient.methods.vaultsSecretsGet();
await (async () => {
const writer = response.writable.getWriter();
let first = true;
for (const [vaultName, secretPath] of secretPaths) {
await writer.write({
nameOrId: vaultName,
secretName: secretPath,
metadata: first
? { ...auth, options: { continueOnError: true } }
: undefined,
});
first = false;
}
await writer.close();
})();
for await (const chunk of response.readable) {
if (chunk.error) process.stderr.write(chunk.error);
else process.stdout.write(chunk.secretContent);
}
}, meta);
} finally {
if (pkClient! != null) await pkClient.stop();
}
});
}
}

export default CommandGet;
24 changes: 17 additions & 7 deletions src/secrets/CommandEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,24 @@ class CommandEdit extends CommandPolykey {
const secretExists = await binUtils.retryAuthentication(
async (auth) => {
let exists: boolean = true;
const response =
await pkClient.rpcClient.methods.vaultsSecretsGet();
await (async () => {
const writer = response.writable.getWriter();
await writer.write({
nameOrId: secretPath[0],
secretName: secretPath[1],
metadata: auth,
});
await writer.close();
})();
try {
const response =
await pkClient.rpcClient.methods.vaultsSecretsGet({
metadata: auth,
nameOrId: secretPath[0],
secretName: secretPath[1],
});
await this.fs.promises.writeFile(tmpFile, response.secretContent);
let rawSecretContent: string = '';
for await (const chunk of response.readable) {
rawSecretContent += chunk.secretContent;
}
const secretContent = Buffer.from(rawSecretContent, 'binary');
await this.fs.promises.writeFile(tmpFile, secretContent);
} catch (e) {
const [cause, _] = binUtils.remoteErrorCause(e);
if (cause instanceof vaultsErrors.ErrorSecretsSecretUndefined) {
Expand Down
86 changes: 0 additions & 86 deletions src/secrets/CommandGet.ts

This file was deleted.

27 changes: 21 additions & 6 deletions src/secrets/CommandRemove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,28 @@ class CommandDelete extends CommandPolykey {
options: { nodePath: options.nodePath },
logger: this.logger.getChild(PolykeyClient.name),
});
await binUtils.retryAuthentication(async (auth) => {
await pkClient.rpcClient.methods.vaultsSecretsRemove({
metadata: auth,
secretNames: secretPaths,
options: { recursive: options.recursive },
});
const response = await binUtils.retryAuthentication(async (auth) => {
const response =
await pkClient.rpcClient.methods.vaultsSecretsRemove();
await (async () => {
const writer = response.writable.getWriter();
let first = true;
for (const [vault, path] of secretPaths) {
await writer.write({
nameOrId: vault,
secretName: path,
metadata: first
? { ...auth, options: { recursive: options.recursive } }
: undefined,
});
first = false;
}
await writer.close();
})();
return response;
}, meta);
// Wait for the program to generate a response (complete processing).
await response.output;
} finally {
if (pkClient! != null) await pkClient.stop();
}
Expand Down
4 changes: 2 additions & 2 deletions src/secrets/CommandSecrets.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import CommandCreate from './CommandCreate';
import CommandCat from './CommandCat';
import CommandDir from './CommandDir';
import CommandEdit from './CommandEdit';
import CommandEnv from './CommandEnv';
import CommandGet from './CommandGet';
import CommandList from './CommandList';
import CommandMkdir from './CommandMkdir';
import CommandRename from './CommandRename';
Expand All @@ -17,10 +17,10 @@ class CommandSecrets extends CommandPolykey {
this.name('secrets');
this.description('Secrets Operations');
this.addCommand(new CommandCreate(...args));
this.addCommand(new CommandCat(...args));
this.addCommand(new CommandDir(...args));
this.addCommand(new CommandEdit(...args));
this.addCommand(new CommandEnv(...args));
this.addCommand(new CommandGet(...args));
this.addCommand(new CommandList(...args));
this.addCommand(new CommandMkdir(...args));
this.addCommand(new CommandRename(...args));
Expand Down
Loading

0 comments on commit 165c9f4

Please sign in to comment.