Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preparing Polykey for Local Demo #504

Merged
merged 10 commits into from
Feb 3, 2023
Merged
3 changes: 3 additions & 0 deletions src/PolykeyAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ class PolykeyAgent {
logger: logger.getChild(SessionManager.name),
fresh,
}));
// If a recovery code is provided then we reset any sessions in case the
// password changed.
if (keyRingConfig.recoveryCode != null) await sessionManager.resetKey();
grpcServerClient =
grpcServerClient ??
new GRPCServer({
Expand Down
18 changes: 13 additions & 5 deletions src/bin/agent/CommandStart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { PolykeyWorkerManagerInterface } from '../../workers/types';
import path from 'path';
import childProcess from 'child_process';
import process from 'process';
import * as keysErrors from '../../keys/errors';
import CommandPolykey from '../CommandPolykey';
import * as binUtils from '../utils';
import * as binOptions from '../utils/options';
Expand Down Expand Up @@ -218,11 +219,18 @@ class CommandStart extends CommandPolykey {
await workerManager?.destroy();
await pkAgent?.stop();
});
pkAgent = await PolykeyAgent.createPolykeyAgent({
fs: this.fs,
logger: this.logger.getChild(PolykeyAgent.name),
...agentConfig,
});
try {
pkAgent = await PolykeyAgent.createPolykeyAgent({
fs: this.fs,
logger: this.logger.getChild(PolykeyAgent.name),
...agentConfig,
});
} catch (e) {
if (e instanceof keysErrors.ErrorKeyPairParse) {
throw new binErrors.ErrorCLIPasswordWrong();
}
throw e;
}
if (options.workers !== 0) {
workerManager = await workersUtils.createWorkerManager({
cores: options.workers,
Expand Down
6 changes: 6 additions & 0 deletions src/bin/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class ErrorCLIClientOptions<T> extends ErrorCLI<T> {
exitCode = sysexits.USAGE;
}

class ErrorCLIPasswordWrong<T> extends ErrorCLI<T> {
static description = 'Wrong password, please try again';
exitCode = sysexits.USAGE;
}

class ErrorCLIPasswordMissing<T> extends ErrorCLI<T> {
static description =
'Password is necessary, provide it via --password-file, PK_PASSWORD or when prompted';
Expand Down Expand Up @@ -90,6 +95,7 @@ export {
ErrorCLI,
ErrorCLINodePath,
ErrorCLIClientOptions,
ErrorCLIPasswordWrong,
ErrorCLIPasswordMissing,
ErrorCLIPasswordFileRead,
ErrorCLIRecoveryCodeFileRead,
Expand Down
10 changes: 2 additions & 8 deletions src/bin/identities/CommandAuthenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@ class CommandAuthenticate extends CommandPolykey {
'Name of the digital identity provider',
parsers.parseProviderId,
);
this.argument(
'<identityId>',
'Digital identity to authenticate',
parsers.parseIdentityId,
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
this.action(async (providerId, identityId, options) => {
this.action(async (providerId, options) => {
const { default: PolykeyClient } = await import('../../PolykeyClient');
const identitiesPB = await import(
'../../proto/js/polykey/v1/identities/identities_pb'
Expand Down Expand Up @@ -59,7 +54,6 @@ class CommandAuthenticate extends CommandPolykey {
});
const providerMessage = new identitiesPB.Provider();
providerMessage.setProviderId(providerId);
providerMessage.setIdentityId(identityId);
await binUtils.retryAuthentication(async (auth) => {
genReadable = pkClient.grpcClient.identitiesAuthenticate(
providerMessage,
Expand Down Expand Up @@ -90,7 +84,7 @@ class CommandAuthenticate extends CommandPolykey {
case identitiesPB.AuthenticationProcess.StepCase.RESPONSE: {
const authResponse = message.getResponse()!;
this.logger.info(
`Authenticated digital identity provider ${providerId} with identity ${identityId}`,
`Authenticated digital identity provider ${providerId}`,
);
process.stdout.write(
binUtils.outputFormatter({
Expand Down
34 changes: 7 additions & 27 deletions src/bin/secrets/CommandGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ class CommandGet extends CommandPolykey {
'Path to where the secret to be retrieved, specified as <vaultName>:<directoryPath>',
parsers.parseSecretPath,
);
this.option(
'-e, --env',
'Wrap the secret in an environment variable declaration',
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
Expand Down Expand Up @@ -54,7 +50,6 @@ class CommandGet extends CommandPolykey {
port: clientOptions.clientPort,
logger: this.logger.getChild(PolykeyClient.name),
});
const isEnv: boolean = options.env ?? false;
const secretMessage = new secretsPB.Secret();
const vaultMessage = new vaultsPB.Vault();
vaultMessage.setNameOrId(secretPath[0]);
Expand All @@ -64,28 +59,13 @@ class CommandGet extends CommandPolykey {
(auth) => pkClient.grpcClient.vaultsSecretsGet(secretMessage, auth),
meta,
);
if (isEnv) {
process.stdout.write(
binUtils.outputFormatter({
type: options.format === 'json' ? 'json' : 'list',
data: [
`Export ${secretMessage
.getSecretName()
.toUpperCase()
.replace('-', '_')}='${response.getSecretName()}`,
],
}),
);
} else {
process.stdout.write(
binUtils.outputFormatter({
type: options.format === 'json' ? 'json' : 'list',
data: [
`${secretMessage.getSecretName()}:\t\t${response.getSecretName()}`,
],
}),
);
}
const secretContent = response.getSecretContent_asU8();
process.stdout.write(
binUtils.outputFormatter({
type: 'raw',
data: secretContent,
}),
);
} finally {
if (pkClient! != null) await pkClient.stop();
}
Expand Down
15 changes: 11 additions & 4 deletions src/bin/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ function verboseToLogLevel(c: number = 0): LogLevel {
}

type OutputObject =
| {
type: 'raw';
data: string | Uint8Array;
}
| {
type: 'list';
data: Array<string>;
Expand All @@ -47,9 +51,11 @@ type OutputObject =
data: Error;
};

function outputFormatter(msg: OutputObject): string {
function outputFormatter(msg: OutputObject): string | Uint8Array {
let output = '';
if (msg.type === 'list') {
if (msg.type === 'raw') {
return msg.data;
} else if (msg.type === 'list') {
for (let elem in msg.data) {
// Empty string for null or undefined values
if (elem == null) {
Expand Down Expand Up @@ -127,8 +133,9 @@ function outputFormatter(msg: OutputObject): string {
output += ` - ${currError.message}`;
}
output += '\n';
output += `${indent}exitCode\t${currError.exitCode}\n`;
output += `${indent}timestamp\t${currError.timestamp}\n`;
// Disabled to streamline output
// output += `${indent}exitCode\t${currError.exitCode}\n`;
// output += `${indent}timestamp\t${currError.timestamp}\n`;
if (currError.data && !utils.isEmptyObject(currError.data)) {
output += `${indent}data\t${JSON.stringify(currError.data)}\n`;
}
Expand Down
8 changes: 5 additions & 3 deletions src/identities/IdentitiesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ class IdentitiesManager {
}
const identities = await provider.getAuthIdentityIds();
if (!identities.includes(identityId)) {
throw new identitiesErrors.ErrorProviderUnauthenticated();
throw new identitiesErrors.ErrorProviderIdentityMissing(
`Authenticated identities: ${JSON.stringify(identities)}`,
);
}
// Create identity claim on our node
const publishedClaimProm = promise<IdentitySignedClaim>();
Expand All @@ -258,11 +260,11 @@ class IdentitiesManager {
async (token) => {
// Publishing in the callback to avoid adding bad claims
const claim = token.toSigned();
const asd = await provider.publishClaim(
const identitySignedClaim = await provider.publishClaim(
identityId,
claim as SignedClaim<ClaimLinkIdentity>,
);
publishedClaimProm.resolveP(asd);
publishedClaimProm.resolveP(identitySignedClaim);
return token;
},
tran,
Expand Down
6 changes: 6 additions & 0 deletions src/identities/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class ErrorProviderUnauthenticated<T> extends ErrorIdentities<T> {
exitCode = sysexits.NOPERM;
}

class ErrorProviderIdentityMissing<T> extends ErrorIdentities<T> {
static description = 'Identity is not authenticated with the provider';
exitCode = sysexits.NOPERM;
}

class ErrorProviderUnimplemented<T> extends ErrorIdentities<T> {
static description = 'Functionality is unavailable';
exitCode = sysexits.USAGE;
Expand All @@ -58,5 +63,6 @@ export {
ErrorProviderAuthentication,
ErrorProviderUnauthenticated,
ErrorProviderUnimplemented,
ErrorProviderIdentityMissing,
ErrorProviderMissing,
};
24 changes: 15 additions & 9 deletions src/keys/utils/symmetric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,21 @@ function decryptWithKey(
const plainText = Buffer.allocUnsafeSlow(
macAndCipherText.byteLength - macSize,
);
// This returns the number of bytes that has been decrypted
const decrypted = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
plainText,
null,
macAndCipherText,
additionalData,
nonce,
key,
);
let decrypted: number;
try {
// This returns the number of bytes that has been decrypted
// It will throw if the MAC cannot be authenticated
decrypted = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
plainText,
null,
macAndCipherText,
additionalData,
nonce,
key,
);
} catch {
return;
}
if (decrypted !== plainText.byteLength) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/nodes/NodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class NodeManager {
const seedNodes = this.nodeConnectionManager.getSeedNodes();
const allInactive = !seedNodes
.map((nodeId) => this.nodeConnectionManager.hasConnection(nodeId))
.reduce((a, b) => a || b);
.reduce((a, b) => a || b, false);
try {
if (allInactive) {
this.logger.debug(
Expand Down
2 changes: 1 addition & 1 deletion src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async function dirEmpty(fs: FileSystem, path): Promise<boolean> {
return entries.length === 0;
} catch (e) {
if (e.code === 'ENOENT') {
return false;
return true;
}
throw e;
}
Expand Down
1 change: 1 addition & 0 deletions tests/bin/secrets/secrets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ describe('CLI secrets', () => {
env: {},
cwd: dataDir,
});
expect(result.stdout).toBe('this is the secret');
expect(result.exitCode).toBe(0);
},
);
Expand Down